From de85e27b17aab8573158220842ae50ac36d6e877 Mon Sep 17 00:00:00 2001 From: Vicente Date: Sun, 9 Jun 2013 12:32:06 +0200 Subject: [PATCH] Changes for kernel and Busybox --- release/src/btools/fpkg.c | 5 +- release/src/btools/libfoo.pl | 20 +- release/src/include/bcmparams.h | 2 +- .../src/linux/linux/Documentation/Configure.help | 12 + release/src/linux/linux/arch/mips/bcm947xx/setup.c | 4 + release/src/linux/linux/arch/mips/bcm947xx/time.c | 2 + release/src/linux/linux/arch/mips/kernel/proc.c | 2 + release/src/linux/linux/config_base | 4 +- release/src/linux/linux/drivers/net/ppp_generic.c | 9 +- .../include/linux/netfilter_ipv4/ipt_account.h | 50 +- release/src/linux/linux/include/linux/pkt_sched.h | 11 +- release/src/linux/linux/include/net/pkt_sched.h | 13 + .../src/linux/linux/net/ipv4/netfilter/Config.in | 3 - .../linux/linux/net/ipv4/netfilter/ipt_account.c | 1760 ++- release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c | 3 + release/src/linux/linux/net/sched/police.c | 4 +- release/src/linux/linux/net/sched/sch_cbq.c | 2 +- release/src/linux/linux/net/sched/sch_htb.c | 12 +- release/src/linux/linux/net/sched/sch_tbf.c | 4 +- release/src/router/busybox/.gitignore | 1 + release/src/router/busybox/Config.in | 114 +- release/src/router/busybox/INSTALL | 11 +- release/src/router/busybox/Makefile | 29 +- release/src/router/busybox/Makefile.flags | 39 +- release/src/router/busybox/Makefile.help | 4 + release/src/router/busybox/README | 4 +- release/src/router/busybox/TODO | 2 + release/src/router/busybox/applets/.gitignore | 1 + release/src/router/busybox/applets/Kbuild.src | 3 + release/src/router/busybox/applets/applet_tables.c | 12 +- release/src/router/busybox/applets/busybox.mkll | 2 +- release/src/router/busybox/applets/install.sh | 71 +- release/src/router/busybox/applets/usage_pod.c | 4 +- release/src/router/busybox/applets_sh/README | 5 + release/src/router/busybox/applets_sh/dos2unix | 5 + release/src/router/busybox/applets_sh/nologin | 4 + release/src/router/busybox/applets_sh/tac | 7 + release/src/router/busybox/applets_sh/unix2dos | 5 + release/src/router/busybox/archival/Config.src | 23 +- release/src/router/busybox/archival/ar.c | 14 +- release/src/router/busybox/archival/bbunzip.c | 156 +- release/src/router/busybox/archival/bzip2.c | 17 +- release/src/router/busybox/archival/cpio.c | 103 +- release/src/router/busybox/archival/dpkg.c | 36 +- release/src/router/busybox/archival/dpkg_deb.c | 16 +- release/src/router/busybox/archival/gzip.c | 33 +- .../router/busybox/archival/libarchive/Kbuild.src | 25 +- .../busybox/archival/libarchive/bz/blocksort.c | 8 +- .../busybox/archival/libarchive/bz/bzlib_private.h | 2 +- .../busybox/archival/libarchive/bz/compress.c | 15 +- .../busybox/archival/libarchive/bz/huffman.c | 2 +- .../busybox/archival/libarchive/data_align.c | 2 +- .../busybox/archival/libarchive/data_extract_all.c | 10 +- .../archival/libarchive/data_extract_to_command.c | 18 +- .../archival/libarchive/data_extract_to_stdout.c | 2 +- .../router/busybox/archival/libarchive/data_skip.c | 2 +- .../archival/libarchive/decompress_bunzip2.c | 29 +- .../{decompress_unzip.c => decompress_gunzip.c} | 71 +- .../archival/libarchive/decompress_uncompress.c | 26 +- .../archival/libarchive/decompress_unlzma.c | 4 +- .../busybox/archival/libarchive/decompress_unxz.c | 14 +- .../archival/libarchive/filter_accept_all.c | 2 +- .../archival/libarchive/filter_accept_list.c | 2 +- .../libarchive/filter_accept_list_reassign.c | 2 +- .../libarchive/filter_accept_reject_list.c | 2 +- .../busybox/archival/libarchive/find_list_entry.c | 2 +- .../busybox/archival/libarchive/get_header_ar.c | 2 +- .../busybox/archival/libarchive/get_header_cpio.c | 2 +- .../busybox/archival/libarchive/get_header_tar.c | 166 +- .../archival/libarchive/get_header_tar_bz2.c | 4 +- .../{get_header_tar_bz2.c => get_header_tar_gz.c} | 6 +- .../archival/libarchive/get_header_tar_lzma.c | 4 +- .../busybox/archival/libarchive/header_list.c | 2 +- .../busybox/archival/libarchive/header_skip.c | 2 +- .../archival/libarchive/header_verbose_list.c | 2 +- .../busybox/archival/libarchive/init_handle.c | 2 +- .../busybox/archival/libarchive/open_transformer.c | 193 +- .../busybox/archival/libarchive/seek_by_jump.c | 2 +- .../busybox/archival/libarchive/seek_by_read.c | 2 +- .../archival/libarchive/unpack_ar_archive.c | 2 +- release/src/router/busybox/archival/lzop.c | 42 +- release/src/router/busybox/archival/rpm.c | 16 +- release/src/router/busybox/archival/rpm2cpio.c | 60 +- release/src/router/busybox/archival/tar.c | 199 +- release/src/router/busybox/archival/unzip.c | 29 +- release/src/router/busybox/config_base | 76 +- .../src/router/busybox/{config_base => config_nc} | 133 +- .../router/busybox/configs/TEST_nommu_defconfig | 926 ++ .../TEST_noprintf_defconfig} | 555 +- .../src/router/busybox/configs/TEST_rh9_defconfig | 941 ++ .../{config_base => configs/android2_defconfig} | 835 +- .../{config_base => configs/android_defconfig} | 917 +- .../{config_base => configs/android_ndk_defconfig} | 904 +- .../{config_base => configs/cygwin_defconfig} | 803 +- .../{config_base => configs/freebsd_defconfig} | 608 +- .../src/router/busybox/console-tools/Config.src | 26 +- release/src/router/busybox/console-tools/chvt.c | 6 + release/src/router/busybox/console-tools/clear.c | 6 + .../src/router/busybox/console-tools/deallocvt.c | 5 + .../src/router/busybox/console-tools/dumpkmap.c | 8 + .../src/router/busybox/console-tools/fgconsole.c | 5 + .../src/router/busybox/console-tools/kbd_mode.c | 11 + .../src/router/busybox/console-tools/loadfont.c | 20 + .../src/router/busybox/console-tools/loadkmap.c | 10 + release/src/router/busybox/console-tools/openvt.c | 16 +- release/src/router/busybox/console-tools/reset.c | 9 +- release/src/router/busybox/console-tools/resize.c | 7 + .../src/router/busybox/console-tools/setconsole.c | 8 +- .../src/router/busybox/console-tools/setkeycodes.c | 12 + .../src/router/busybox/console-tools/setlogcons.c | 5 + release/src/router/busybox/console-tools/showkey.c | 45 +- release/src/router/busybox/coreutils/Config.src | 39 +- release/src/router/busybox/coreutils/Kbuild.src | 6 +- release/src/router/busybox/coreutils/basename.c | 18 + release/src/router/busybox/coreutils/cal.c | 8 + release/src/router/busybox/coreutils/cat.c | 9 + release/src/router/busybox/coreutils/catv.c | 8 + release/src/router/busybox/coreutils/chgrp.c | 22 + release/src/router/busybox/coreutils/chmod.c | 22 + release/src/router/busybox/coreutils/chown.c | 25 + release/src/router/busybox/coreutils/chroot.c | 22 +- release/src/router/busybox/coreutils/cksum.c | 6 + release/src/router/busybox/coreutils/comm.c | 8 + release/src/router/busybox/coreutils/cp.c | 17 + release/src/router/busybox/coreutils/cut.c | 17 + release/src/router/busybox/coreutils/date.c | 18 +- release/src/router/busybox/coreutils/dd.c | 38 + release/src/router/busybox/coreutils/df.c | 40 +- release/src/router/busybox/coreutils/dirname.c | 11 + release/src/router/busybox/coreutils/dos2unix.c | 16 + release/src/router/busybox/coreutils/du.c | 47 +- release/src/router/busybox/coreutils/echo.c | 205 +- release/src/router/busybox/coreutils/env.c | 8 + release/src/router/busybox/coreutils/expand.c | 29 + release/src/router/busybox/coreutils/expr.c | 38 + release/src/router/busybox/coreutils/false.c | 10 + release/src/router/busybox/coreutils/fold.c | 9 + release/src/router/busybox/coreutils/fsync.c | 7 + release/src/router/busybox/coreutils/head.c | 19 + release/src/router/busybox/coreutils/hostid.c | 18 +- release/src/router/busybox/coreutils/id.c | 99 +- release/src/router/busybox/coreutils/install.c | 17 + .../src/router/busybox/coreutils/length.c.disabled | 31 + release/src/router/busybox/coreutils/ln.c | 25 +- release/src/router/busybox/coreutils/logname.c | 9 + release/src/router/busybox/coreutils/ls.c | 1255 +- .../src/router/busybox/coreutils/md5_sha1_sum.c | 178 +- release/src/router/busybox/coreutils/mkdir.c | 25 +- release/src/router/busybox/coreutils/mkfifo.c | 9 + release/src/router/busybox/coreutils/mknod.c | 17 + release/src/router/busybox/coreutils/mv.c | 1 - release/src/router/busybox/coreutils/nice.c | 6 + release/src/router/busybox/coreutils/nohup.c | 8 + release/src/router/busybox/coreutils/od.c | 6 + release/src/router/busybox/coreutils/od_bloaty.c | 443 +- release/src/router/busybox/coreutils/printenv.c | 6 + release/src/router/busybox/coreutils/printf.c | 30 +- release/src/router/busybox/coreutils/pwd.c | 61 +- release/src/router/busybox/coreutils/readlink.c | 11 + release/src/router/busybox/coreutils/realpath.c | 5 + release/src/router/busybox/coreutils/rm.c | 11 + release/src/router/busybox/coreutils/rmdir.c | 15 + release/src/router/busybox/coreutils/seq.c | 9 + release/src/router/busybox/coreutils/sleep.c | 15 + release/src/router/busybox/coreutils/sort.c | 47 + release/src/router/busybox/coreutils/split.c | 16 +- release/src/router/busybox/coreutils/stat.c | 60 + release/src/router/busybox/coreutils/stty.c | 66 +- release/src/router/busybox/coreutils/sum.c | 7 + release/src/router/busybox/coreutils/sync.c | 5 + release/src/router/busybox/coreutils/tac.c | 5 + release/src/router/busybox/coreutils/tail.c | 69 +- release/src/router/busybox/coreutils/tee.c | 12 + release/src/router/busybox/coreutils/test.c | 43 +- release/src/router/busybox/coreutils/touch.c | 57 +- release/src/router/busybox/coreutils/tr.c | 18 + release/src/router/busybox/coreutils/true.c | 10 + release/src/router/busybox/coreutils/tty.c | 12 + release/src/router/busybox/coreutils/uname.c | 16 + release/src/router/busybox/coreutils/uniq.c | 17 + release/src/router/busybox/coreutils/usleep.c | 13 +- release/src/router/busybox/coreutils/uudecode.c | 20 +- release/src/router/busybox/coreutils/uuencode.c | 13 + release/src/router/busybox/coreutils/wc.c | 1 - release/src/router/busybox/coreutils/who.c | 98 +- release/src/router/busybox/coreutils/whoami.c | 5 + release/src/router/busybox/debianutils/mktemp.c | 62 +- .../src/router/busybox/debianutils/pipe_progress.c | 4 + release/src/router/busybox/debianutils/run_parts.c | 28 + .../router/busybox/debianutils/start_stop_daemon.c | 102 +- release/src/router/busybox/debianutils/which.c | 9 + release/src/router/busybox/docs/.gitignore | 1 + release/src/router/busybox/docs/ctty.htm | 3 + release/src/router/busybox/docs/mdev.txt | 12 +- .../src/router/busybox/docs/new-applet-HOWTO.txt | 2 +- release/src/router/busybox/docs/nofork_noexec.txt | 27 +- release/src/router/busybox/docs/style-guide.txt | 11 +- release/src/router/busybox/docs/syslog.conf.txt | 28 + release/src/router/busybox/docs/unicode.txt | 2 +- release/src/router/busybox/e2fsprogs/Config.src | 63 +- release/src/router/busybox/e2fsprogs/Kbuild.src | 11 +- release/src/router/busybox/e2fsprogs/README | 15 +- .../src/router/busybox/e2fsprogs/blkid/Kbuild.src | 26 + release/src/router/busybox/e2fsprogs/blkid/blkid.h | 104 + .../src/router/busybox/e2fsprogs/blkid/blkidP.h | 186 + .../router/busybox/e2fsprogs/blkid/blkid_getsize.c | 179 + release/src/router/busybox/e2fsprogs/blkid/cache.c | 125 + release/src/router/busybox/e2fsprogs/blkid/dev.c | 213 + .../src/router/busybox/e2fsprogs/blkid/devname.c | 367 + release/src/router/busybox/e2fsprogs/blkid/devno.c | 222 + release/src/router/busybox/e2fsprogs/blkid/list.c | 110 + release/src/router/busybox/e2fsprogs/blkid/list.h | 73 + release/src/router/busybox/e2fsprogs/blkid/probe.c | 726 + release/src/router/busybox/e2fsprogs/blkid/probe.h | 374 + release/src/router/busybox/e2fsprogs/blkid/read.c | 459 + .../src/router/busybox/e2fsprogs/blkid/resolve.c | 139 + release/src/router/busybox/e2fsprogs/blkid/save.c | 189 + release/src/router/busybox/e2fsprogs/blkid/tag.c | 431 + release/src/router/busybox/e2fsprogs/chattr.c | 204 +- release/src/router/busybox/e2fsprogs/e2fs_lib.h | 2 +- release/src/router/busybox/e2fsprogs/e2fsbb.h | 43 + release/src/router/busybox/e2fsprogs/e2fsck.c | 13520 +++++++++++++++++++ release/src/router/busybox/e2fsprogs/e2fsck.h | 637 + .../src/router/busybox/e2fsprogs/e2p/Kbuild.src | 18 + release/src/router/busybox/e2fsprogs/e2p/e2p.h | 41 + release/src/router/busybox/e2fsprogs/e2p/feature.c | 187 + .../router/busybox/e2fsprogs/e2p/fgetsetflags.c | 70 + .../router/busybox/e2fsprogs/e2p/fgetsetversion.c | 70 + release/src/router/busybox/e2fsprogs/e2p/hashstr.c | 70 + release/src/router/busybox/e2fsprogs/e2p/iod.c | 52 + release/src/router/busybox/e2fsprogs/e2p/ls.c | 274 + release/src/router/busybox/e2fsprogs/e2p/mntopts.c | 134 + release/src/router/busybox/e2fsprogs/e2p/ostype.c | 72 + .../src/router/busybox/e2fsprogs/e2p/parse_num.c | 65 + release/src/router/busybox/e2fsprogs/e2p/pe.c | 32 + release/src/router/busybox/e2fsprogs/e2p/pf.c | 74 + release/src/router/busybox/e2fsprogs/e2p/ps.c | 27 + release/src/router/busybox/e2fsprogs/e2p/uuid.c | 78 + .../src/router/busybox/e2fsprogs/ext2fs/Kbuild.src | 26 + .../src/router/busybox/e2fsprogs/ext2fs/alloc.c | 173 + .../src/router/busybox/e2fsprogs/ext2fs/alloc_sb.c | 58 + .../router/busybox/e2fsprogs/ext2fs/alloc_stats.c | 53 + .../router/busybox/e2fsprogs/ext2fs/alloc_tables.c | 114 + .../router/busybox/e2fsprogs/ext2fs/badblocks.c | 328 + .../router/busybox/e2fsprogs/ext2fs/bb_compat.c | 64 + .../src/router/busybox/e2fsprogs/ext2fs/bb_inode.c | 262 + .../src/router/busybox/e2fsprogs/ext2fs/bitmaps.c | 211 + .../src/router/busybox/e2fsprogs/ext2fs/bitops.c | 91 + .../src/router/busybox/e2fsprogs/ext2fs/bitops.h | 105 + .../src/router/busybox/e2fsprogs/ext2fs/block.c | 437 + release/src/router/busybox/e2fsprogs/ext2fs/bmap.c | 261 + .../src/router/busybox/e2fsprogs/ext2fs/bmove.c | 155 + release/src/router/busybox/e2fsprogs/ext2fs/brel.h | 86 + .../src/router/busybox/e2fsprogs/ext2fs/brel_ma.c | 196 + .../router/busybox/e2fsprogs/ext2fs/check_desc.c | 69 + .../src/router/busybox/e2fsprogs/ext2fs/closefs.c | 380 + .../router/busybox/e2fsprogs/ext2fs/cmp_bitmaps.c | 72 + .../src/router/busybox/e2fsprogs/ext2fs/dblist.c | 260 + .../router/busybox/e2fsprogs/ext2fs/dblist_dir.c | 76 + .../router/busybox/e2fsprogs/ext2fs/dir_iterate.c | 219 + .../src/router/busybox/e2fsprogs/ext2fs/dirblock.c | 132 + .../src/router/busybox/e2fsprogs/ext2fs/dirhash.c | 234 + .../src/router/busybox/e2fsprogs/ext2fs/dupfs.c | 95 + .../src/router/busybox/e2fsprogs/ext2fs/e2image.h | 39 + .../router/busybox/e2fsprogs/ext2fs/expanddir.c | 127 + .../src/router/busybox/e2fsprogs/ext2fs/ext2_err.h | 116 + .../busybox/e2fsprogs/ext2fs/ext2_ext_attr.h | 52 + .../src/router/busybox/e2fsprogs/ext2fs/ext2_fs.h | 569 + .../src/router/busybox/e2fsprogs/ext2fs/ext2_io.h | 112 + .../router/busybox/e2fsprogs/ext2fs/ext2_types.h | 2 + .../src/router/busybox/e2fsprogs/ext2fs/ext2fs.h | 926 ++ .../src/router/busybox/e2fsprogs/ext2fs/ext2fsP.h | 87 + .../busybox/e2fsprogs/ext2fs/ext2fs_inline.c | 365 + .../src/router/busybox/e2fsprogs/ext2fs/ext_attr.c | 101 + .../src/router/busybox/e2fsprogs/ext2fs/fileio.c | 377 + .../src/router/busybox/e2fsprogs/ext2fs/finddev.c | 199 + .../src/router/busybox/e2fsprogs/ext2fs/flushb.c | 83 + .../src/router/busybox/e2fsprogs/ext2fs/freefs.c | 127 + .../router/busybox/e2fsprogs/ext2fs/gen_bitmap.c | 49 + .../router/busybox/e2fsprogs/ext2fs/get_pathname.c | 156 + .../router/busybox/e2fsprogs/ext2fs/getsectsize.c | 58 + .../src/router/busybox/e2fsprogs/ext2fs/getsize.c | 292 + .../src/router/busybox/e2fsprogs/ext2fs/icount.c | 467 + .../src/router/busybox/e2fsprogs/ext2fs/imager.c | 377 + .../router/busybox/e2fsprogs/ext2fs/ind_block.c | 69 + .../router/busybox/e2fsprogs/ext2fs/initialize.c | 388 + .../src/router/busybox/e2fsprogs/ext2fs/inline.c | 32 + .../src/router/busybox/e2fsprogs/ext2fs/inode.c | 766 ++ .../src/router/busybox/e2fsprogs/ext2fs/inode_io.c | 270 + .../router/busybox/e2fsprogs/ext2fs/io_manager.c | 70 + release/src/router/busybox/e2fsprogs/ext2fs/irel.h | 115 + .../src/router/busybox/e2fsprogs/ext2fs/irel_ma.c | 367 + .../router/busybox/e2fsprogs/ext2fs/ismounted.c | 356 + .../src/router/busybox/e2fsprogs/ext2fs/jfs_dat.h | 63 + .../router/busybox/e2fsprogs/ext2fs/kernel-jbd.h | 235 + .../router/busybox/e2fsprogs/ext2fs/kernel-list.h | 113 + release/src/router/busybox/e2fsprogs/ext2fs/link.c | 135 + .../src/router/busybox/e2fsprogs/ext2fs/lookup.c | 68 + .../src/router/busybox/e2fsprogs/ext2fs/mkdir.c | 139 + .../router/busybox/e2fsprogs/ext2fs/mkjournal.c | 426 + .../src/router/busybox/e2fsprogs/ext2fs/namei.c | 204 + .../src/router/busybox/e2fsprogs/ext2fs/newdir.c | 72 + .../src/router/busybox/e2fsprogs/ext2fs/openfs.c | 330 + .../src/router/busybox/e2fsprogs/ext2fs/read_bb.c | 96 + .../router/busybox/e2fsprogs/ext2fs/read_bb_file.c | 96 + .../src/router/busybox/e2fsprogs/ext2fs/res_gdt.c | 220 + .../router/busybox/e2fsprogs/ext2fs/rs_bitmap.c | 106 + .../router/busybox/e2fsprogs/ext2fs/rw_bitmaps.c | 294 + .../src/router/busybox/e2fsprogs/ext2fs/sparse.c | 79 + .../src/router/busybox/e2fsprogs/ext2fs/swapfs.c | 234 + .../src/router/busybox/e2fsprogs/ext2fs/test_io.c | 380 + .../src/router/busybox/e2fsprogs/ext2fs/unix_io.c | 703 + .../src/router/busybox/e2fsprogs/ext2fs/unlink.c | 99 + .../router/busybox/e2fsprogs/ext2fs/valid_blk.c | 57 + .../src/router/busybox/e2fsprogs/ext2fs/version.c | 51 + .../busybox/e2fsprogs/ext2fs/write_bb_file.c | 35 + release/src/router/busybox/e2fsprogs/fsck.c | 1438 +- release/src/router/busybox/e2fsprogs/fsck.h | 16 + release/src/router/busybox/e2fsprogs/lsattr.c | 123 +- release/src/router/busybox/e2fsprogs/mke2fs.c | 1372 ++ release/src/router/busybox/e2fsprogs/tune2fs.c | 827 +- release/src/router/busybox/e2fsprogs/util.c | 264 + release/src/router/busybox/e2fsprogs/util.h | 22 + .../src/router/busybox/e2fsprogs/uuid/Kbuild.src | 16 + .../src/router/busybox/e2fsprogs/uuid/compare.c | 55 + .../src/router/busybox/e2fsprogs/uuid/gen_uuid.c | 304 + release/src/router/busybox/e2fsprogs/uuid/pack.c | 69 + release/src/router/busybox/e2fsprogs/uuid/parse.c | 80 + release/src/router/busybox/e2fsprogs/uuid/unpack.c | 63 + .../src/router/busybox/e2fsprogs/uuid/unparse.c | 77 + release/src/router/busybox/e2fsprogs/uuid/uuid.h | 103 + release/src/router/busybox/e2fsprogs/uuid/uuidP.h | 60 + .../src/router/busybox/e2fsprogs/uuid/uuid_time.c | 161 + release/src/router/busybox/editors/Config.src | 273 +- release/src/router/busybox/editors/Kbuild.src | 1 - release/src/router/busybox/editors/awk.c | 101 +- release/src/router/busybox/editors/cmp.c | 8 + release/src/router/busybox/editors/diff.c | 63 +- release/src/router/busybox/editors/ed.c | 11 +- release/src/router/busybox/editors/patch.c | 68 +- release/src/router/busybox/editors/sed.c | 295 +- release/src/router/busybox/editors/vi.c | 645 +- release/src/router/busybox/examples/android-build | 32 + release/src/router/busybox/examples/depmod.pl | 2 +- .../src/router/busybox/examples/udhcp/udhcpd.conf | 25 +- .../src/router/busybox/examples/var_service/README | 59 + release/src/router/busybox/examples/zcip.script | 4 +- release/src/router/busybox/findutils/find.c | 506 +- release/src/router/busybox/findutils/grep.c | 41 +- release/src/router/busybox/findutils/xargs.c | 20 +- release/src/router/busybox/include/.gitignore | 4 + .../src/router/busybox/include/applet_metadata.h | 30 + release/src/router/busybox/include/applets.src.h | 841 +- release/src/router/busybox/include/bb_archive.h | 244 + release/src/router/busybox/include/bb_e2fs_defs.h | 579 + release/src/router/busybox/include/busybox.h | 25 +- release/src/router/busybox/include/grp_.h | 2 +- release/src/router/busybox/include/libbb.h | 417 +- release/src/router/busybox/include/platform.h | 229 +- release/src/router/busybox/include/pwd_.h | 2 +- release/src/router/busybox/include/shadow_.h | 5 - release/src/router/busybox/include/unicode.h | 4 + release/src/router/busybox/include/usage.src.h | 4483 +----- release/src/router/busybox/include/volume_id.h | 3 +- release/src/router/busybox/include/xatonum.h | 9 + release/src/router/busybox/init/bootchartd.c | 47 +- release/src/router/busybox/init/halt.c | 14 +- release/src/router/busybox/init/init.c | 99 +- release/src/router/busybox/init/mesg.c | 60 +- release/src/router/busybox/libbb/Config.src | 49 +- release/src/router/busybox/libbb/Kbuild.src | 25 +- release/src/router/busybox/libbb/appletlib.c | 325 +- release/src/router/busybox/libbb/bb_askpass.c | 22 +- release/src/router/busybox/libbb/bb_pwd.c | 4 +- release/src/router/busybox/libbb/bb_strtonum.c | 65 +- release/src/router/busybox/libbb/copy_file.c | 8 +- release/src/router/busybox/libbb/crc32.c | 2 +- .../src/router/busybox/libbb/die_if_bad_username.c | 42 +- release/src/router/busybox/libbb/dump.c | 30 +- release/src/router/busybox/libbb/execable.c | 10 +- .../src/router/busybox/libbb/find_mount_point.c | 5 +- .../src/router/busybox/libbb/find_root_device.c | 9 +- .../router/busybox/libbb/get_last_path_component.c | 10 +- .../src/router/busybox/libbb/get_line_from_file.c | 36 +- release/src/router/busybox/libbb/get_shell_name.c | 25 + release/src/router/busybox/libbb/getopt32.c | 35 +- release/src/router/busybox/libbb/getpty.c | 18 +- release/src/router/busybox/libbb/hash_md5_sha.c | 32 +- release/src/router/busybox/libbb/hash_md5prime.c | 26 +- release/src/router/busybox/libbb/inet_cksum.c | 36 + release/src/router/busybox/libbb/inet_common.c | 19 +- release/src/router/busybox/libbb/isdirectory.c | 15 +- release/src/router/busybox/libbb/lineedit.c | 470 +- release/src/router/busybox/libbb/llist.c | 2 +- release/src/router/busybox/libbb/loop.c | 10 +- release/src/router/busybox/libbb/makedev.c | 19 +- release/src/router/busybox/libbb/match_fstype.c | 4 + release/src/router/busybox/libbb/messages.c | 13 +- release/src/router/busybox/libbb/obscure.c | 2 + release/src/router/busybox/libbb/parse_config.c | 140 +- release/src/router/busybox/libbb/percent_decode.c | 69 + release/src/router/busybox/libbb/platform.c | 56 +- release/src/router/busybox/libbb/procps.c | 108 +- release/src/router/busybox/libbb/progress.c | 175 +- release/src/router/busybox/libbb/pw_encrypt.c | 25 +- release/src/router/busybox/libbb/read_key.c | 16 +- release/src/router/busybox/libbb/read_printf.c | 156 +- .../src/router/busybox/libbb/setup_environment.c | 3 + release/src/router/busybox/libbb/single_argv.c | 2 + release/src/router/busybox/libbb/systemd_support.c | 62 + release/src/router/busybox/libbb/time.c | 20 +- release/src/router/busybox/libbb/u_signal_names.c | 68 +- release/src/router/busybox/libbb/udp_io.c | 9 +- release/src/router/busybox/libbb/unicode.c | 29 +- release/src/router/busybox/libbb/utmp.c | 1 - release/src/router/busybox/libbb/uuencode.c | 155 +- release/src/router/busybox/libbb/vdprintf.c | 4 +- .../src/router/busybox/libbb/vfork_daemon_rexec.c | 70 +- release/src/router/busybox/libbb/xconnect.c | 37 +- release/src/router/busybox/libbb/xfuncs.c | 20 +- release/src/router/busybox/libbb/xfuncs_printf.c | 1 + release/src/router/busybox/libpwdgrp/pwd_grp.c | 113 +- release/src/router/busybox/libpwdgrp/uidgid_get.c | 3 +- release/src/router/busybox/loginutils/Config.src | 32 +- release/src/router/busybox/loginutils/README | 70 + .../router/busybox/loginutils/add-remove-shell.c | 4 +- release/src/router/busybox/loginutils/addgroup.c | 8 + release/src/router/busybox/loginutils/adduser.c | 68 +- release/src/router/busybox/loginutils/chpasswd.c | 48 +- release/src/router/busybox/loginutils/cryptpw.c | 62 +- release/src/router/busybox/loginutils/deluser.c | 12 + release/src/router/busybox/loginutils/getty.c | 1416 +- release/src/router/busybox/loginutils/login.c | 154 +- release/src/router/busybox/loginutils/passwd.c | 89 +- release/src/router/busybox/loginutils/su.c | 21 +- release/src/router/busybox/loginutils/sulogin.c | 10 +- release/src/router/busybox/loginutils/vlock.c | 19 +- release/src/router/busybox/mailutils/Kbuild.src | 4 - release/src/router/busybox/mailutils/mail.c | 28 +- release/src/router/busybox/mailutils/mail.h | 25 +- release/src/router/busybox/mailutils/makemime.c | 239 + release/src/router/busybox/mailutils/popmaildir.c | 40 +- release/src/router/busybox/mailutils/reformime.c | 278 + release/src/router/busybox/mailutils/sendmail.c | 156 +- release/src/router/busybox/miscutils/Config.src | 95 +- release/src/router/busybox/miscutils/adjtimex.c | 17 +- release/src/router/busybox/miscutils/bbconfig.c | 8 +- release/src/router/busybox/miscutils/beep.c | 10 + release/src/router/busybox/miscutils/chat.c | 9 + release/src/router/busybox/miscutils/chrt.c | 42 +- release/src/router/busybox/miscutils/conspy.c | 130 +- release/src/router/busybox/miscutils/crond.c | 16 +- release/src/router/busybox/miscutils/crontab.c | 17 +- release/src/router/busybox/miscutils/dc.c | 27 +- release/src/router/busybox/miscutils/devfsd.c | 15 + release/src/router/busybox/miscutils/devmem.c | 8 + release/src/router/busybox/miscutils/eject.c | 10 + release/src/router/busybox/miscutils/fbsplash.c | 219 +- .../src/router/busybox/miscutils/flash_eraseall.c | 7 + .../router/busybox/miscutils/flash_lock_unlock.c | 12 + release/src/router/busybox/miscutils/flashcp.c | 6 + release/src/router/busybox/miscutils/hdparm.c | 54 + release/src/router/busybox/miscutils/inotifyd.c | 48 +- release/src/router/busybox/miscutils/ionice.c | 7 + release/src/router/busybox/miscutils/last.c | 11 +- release/src/router/busybox/miscutils/last_fancy.c | 4 +- release/src/router/busybox/miscutils/less.c | 150 +- release/src/router/busybox/miscutils/makedevs.c | 60 + release/src/router/busybox/miscutils/man.c | 58 +- release/src/router/busybox/miscutils/microcom.c | 11 + release/src/router/busybox/miscutils/mountpoint.c | 15 + release/src/router/busybox/miscutils/mt.c | 12 + release/src/router/busybox/miscutils/nandwrite.c | 24 +- release/src/router/busybox/miscutils/raidautorun.c | 8 + release/src/router/busybox/miscutils/readahead.c | 5 + release/src/router/busybox/miscutils/rfkill.c | 13 + release/src/router/busybox/miscutils/runlevel.c | 14 +- release/src/router/busybox/miscutils/rx.c | 30 +- release/src/router/busybox/miscutils/setserial.c | 763 ++ release/src/router/busybox/miscutils/setsid.c | 7 + release/src/router/busybox/miscutils/strings.c | 9 + release/src/router/busybox/miscutils/taskset.c | 17 + release/src/router/busybox/miscutils/time.c | 6 + release/src/router/busybox/miscutils/timeout.c | 8 +- release/src/router/busybox/miscutils/ttysize.c | 6 + release/src/router/busybox/miscutils/ubi_tools.c | 276 + release/src/router/busybox/miscutils/volname.c | 6 + release/src/router/busybox/miscutils/wall.c | 10 +- release/src/router/busybox/miscutils/watchdog.c | 10 + release/src/router/busybox/modutils/Config.src | 20 +- release/src/router/busybox/modutils/depmod.c | 29 +- release/src/router/busybox/modutils/insmod.c | 5 +- release/src/router/busybox/modutils/lsmod.c | 2 +- release/src/router/busybox/modutils/modinfo.c | 24 +- .../src/router/busybox/modutils/modprobe-small.c | 21 +- release/src/router/busybox/modutils/modprobe.c | 188 +- release/src/router/busybox/modutils/modutils-24.c | 15 +- release/src/router/busybox/modutils/modutils.c | 32 +- release/src/router/busybox/modutils/modutils.h | 2 +- release/src/router/busybox/modutils/rmmod.c | 3 +- release/src/router/busybox/networking/Config.src | 103 +- release/src/router/busybox/networking/Kbuild.src | 2 - release/src/router/busybox/networking/arp.c | 18 + release/src/router/busybox/networking/arping.c | 16 + release/src/router/busybox/networking/brctl.c | 24 + release/src/router/busybox/networking/dnsd.c | 15 + release/src/router/busybox/networking/ether-wake.c | 13 +- release/src/router/busybox/networking/ftpd.c | 25 +- release/src/router/busybox/networking/ftpgetput.c | 45 +- release/src/router/busybox/networking/hostname.c | 20 +- release/src/router/busybox/networking/httpd.c | 390 +- .../src/router/busybox/networking/httpd_indexcgi.c | 27 +- release/src/router/busybox/networking/httpd_ssi.c | 4 +- release/src/router/busybox/networking/ifconfig.c | 32 +- release/src/router/busybox/networking/ifenslave.c | 26 + release/src/router/busybox/networking/ifplugd.c | 55 +- release/src/router/busybox/networking/ifupdown.c | 108 +- release/src/router/busybox/networking/inetd.c | 94 +- release/src/router/busybox/networking/interface.c | 9 +- release/src/router/busybox/networking/ip.c | 72 + release/src/router/busybox/networking/ipcalc.c | 26 + .../src/router/busybox/networking/isrv_identd.c | 10 + .../busybox/networking/libiproute/ipaddress.c | 3 + .../router/busybox/networking/libiproute/iplink.c | 2 +- .../router/busybox/networking/libiproute/iproute.c | 59 +- .../busybox/networking/libiproute/libnetlink.c | 3 +- .../busybox/networking/libiproute/ll_proto.c | 6 +- .../busybox/networking/libiproute/ll_types.c | 1 + .../router/busybox/networking/libiproute/utils.c | 86 +- .../router/busybox/networking/libiproute/utils.h | 6 +- release/src/router/busybox/networking/nameif.c | 114 +- release/src/router/busybox/networking/nbd-client.c | 2 +- release/src/router/busybox/networking/nc.c | 2 +- release/src/router/busybox/networking/nc_bloaty.c | 60 +- release/src/router/busybox/networking/netstat.c | 1 - release/src/router/busybox/networking/nslookup.c | 18 +- release/src/router/busybox/networking/ntpd.c | 342 +- release/src/router/busybox/networking/ping.c | 175 +- release/src/router/busybox/networking/pscan.c | 13 +- release/src/router/busybox/networking/route.c | 83 +- release/src/router/busybox/networking/slattach.c | 13 + release/src/router/busybox/networking/tc.c | 51 +- release/src/router/busybox/networking/tcpudp.c | 39 +- release/src/router/busybox/networking/telnet.c | 34 +- release/src/router/busybox/networking/telnetd.c | 28 +- release/src/router/busybox/networking/tftp.c | 62 +- release/src/router/busybox/networking/traceroute.c | 160 +- release/src/router/busybox/networking/tunctl.c | 18 + .../src/router/busybox/networking/udhcp/Config.src | 30 +- .../src/router/busybox/networking/udhcp/arpping.c | 9 +- .../src/router/busybox/networking/udhcp/common.c | 19 + .../networking/udhcp/{common.c => common.c.20} | 103 +- .../src/router/busybox/networking/udhcp/common.h | 10 +- .../networking/udhcp/{common.h => common.h.20} | 18 +- .../router/busybox/networking/udhcp/d6_common.h | 127 + .../src/router/busybox/networking/udhcp/d6_dhcpc.c | 1483 ++ .../router/busybox/networking/udhcp/d6_packet.c | 172 + .../router/busybox/networking/udhcp/d6_socket.c | 34 + .../src/router/busybox/networking/udhcp/dhcpc.c | 25 +- .../networking/udhcp/{dhcpc.c => dhcpc.c.20} | 481 +- .../src/router/busybox/networking/udhcp/dhcpd.c | 83 +- .../router/busybox/networking/udhcp/dhcprelay.c | 8 +- .../router/busybox/networking/udhcp/dumpleases.c | 16 + .../src/router/busybox/networking/udhcp/files.c | 6 +- .../src/router/busybox/networking/udhcp/leases.c | 40 +- .../src/router/busybox/networking/udhcp/packet.c | 103 +- .../src/router/busybox/networking/udhcp/socket.c | 32 +- release/src/router/busybox/networking/vconfig.c | 101 +- release/src/router/busybox/networking/wget.c | 649 +- release/src/router/busybox/networking/whois.c | 65 + release/src/router/busybox/networking/zcip.c | 18 +- release/src/router/busybox/printutils/lpd.c | 13 +- release/src/router/busybox/printutils/lpr.c | 19 + release/src/router/busybox/procps/Config.src | 37 +- release/src/router/busybox/procps/Kbuild.src | 1 - release/src/router/busybox/procps/free.c | 17 +- release/src/router/busybox/procps/fuser.c | 638 +- release/src/router/busybox/procps/iostat.c | 511 +- release/src/router/busybox/procps/kill.c | 75 +- release/src/router/busybox/procps/lsof.c | 76 + release/src/router/busybox/procps/mpstat.c | 6 +- release/src/router/busybox/procps/nmeter.c | 100 +- release/src/router/busybox/procps/pgrep.c | 29 +- release/src/router/busybox/procps/pidof.c | 28 + release/src/router/busybox/procps/pmap.c | 16 +- release/src/router/busybox/procps/powertop.c | 4 +- release/src/router/busybox/procps/ps.c | 240 +- release/src/router/busybox/procps/pstree.c | 407 + release/src/router/busybox/procps/pwdx.c | 60 + release/src/router/busybox/procps/renice.c | 9 + release/src/router/busybox/procps/smemcap.c | 4 +- release/src/router/busybox/procps/sysctl.c | 22 +- release/src/router/busybox/procps/top.c | 344 +- release/src/router/busybox/procps/uptime.c | 72 +- release/src/router/busybox/procps/watch.c | 13 + release/src/router/busybox/runit/chpst.c | 79 +- release/src/router/busybox/runit/runsv.c | 29 +- release/src/router/busybox/runit/runsvdir.c | 10 +- release/src/router/busybox/runit/sv.c | 19 +- release/src/router/busybox/runit/svlogd.c | 24 +- release/src/router/busybox/scripts/Makefile.IMA | 21 +- release/src/router/busybox/scripts/basic/docproc.c | 3 +- release/src/router/busybox/scripts/basic/fixdep.c | 3 +- release/src/router/busybox/scripts/bloat-o-meter | 27 +- .../src/router/busybox/scripts/gen_build_files.sh | 63 +- .../src/router/busybox/scripts/kconfig/Makefile | 2 +- release/src/router/busybox/scripts/kconfig/conf.c | 13 +- .../busybox/scripts/kconfig/lxdialog/textbox.c | 8 +- release/src/router/busybox/scripts/kconfig/mconf.c | 3 + release/src/router/busybox/scripts/randomtest.loop | 12 +- release/src/router/busybox/scripts/trylink | 1 + release/src/router/busybox/selinux/chcon.c | 34 +- release/src/router/busybox/selinux/getenforce.c | 3 + release/src/router/busybox/selinux/getsebool.c | 5 + release/src/router/busybox/selinux/load_policy.c | 4 + release/src/router/busybox/selinux/matchpathcon.c | 10 + release/src/router/busybox/selinux/runcon.c | 26 +- .../src/router/busybox/selinux/selinuxenabled.c | 4 + release/src/router/busybox/selinux/sestatus.c | 6 + release/src/router/busybox/selinux/setenforce.c | 4 + release/src/router/busybox/selinux/setfiles.c | 40 + release/src/router/busybox/selinux/setsebool.c | 5 + release/src/router/busybox/shell/Config.src | 19 +- release/src/router/busybox/shell/ash.c | 264 +- .../shell/ash_test/ash-misc/echo_write_error.right | 2 + .../shell/ash_test/ash-misc/echo_write_error.tests | 7 + .../busybox/shell/ash_test/ash-redir/redir.right | 1 + .../shell/ash_test/ash-signals/sigint1.right | 1 + .../shell/ash_test/ash-signals/sigint1.tests | 41 + release/src/router/busybox/shell/cttyhack.c | 123 +- release/src/router/busybox/shell/hush.c | 1091 +- .../shell/hush_test/hush-misc/assignment4.right | 1 + .../shell/hush_test/hush-misc/assignment4.tests | 3 + .../hush_test/hush-misc/echo_write_error.right | 2 + .../hush_test/hush-misc/echo_write_error.tests | 7 + .../shell/hush_test/hush-misc/return1.right | 1 + .../shell/hush_test/hush-misc/return1.tests | 4 + .../shell/hush_test/hush-misc/sigint1.right | 1 + .../shell/hush_test/hush-misc/sigint1.tests | 41 + .../shell/hush_test/hush-misc/source1.right | 5 + .../shell/hush_test/hush-misc/source1.tests | 10 + .../shell/hush_test/hush-parsing/starquoted2.right | 3 + .../shell/hush_test/hush-parsing/starquoted2.tests | 6 +- .../shell/hush_test/hush-trap/signal_read1.right | 1 + .../shell/hush_test/hush-trap/signal_read1.tests | 5 + .../shell/hush_test/hush-trap/signal_read2.right | 2 + .../shell/hush_test/hush-trap/signal_read2.tests | 7 + .../hush_test/hush-vars/var_expand_on_ifs.right | 9 + .../hush_test/hush-vars/var_expand_on_ifs.tests | 11 + release/src/router/busybox/shell/hush_test/run-all | 10 +- release/src/router/busybox/shell/shell_common.c | 69 +- release/src/router/busybox/sysklogd/Config.src | 10 +- release/src/router/busybox/sysklogd/klogd.c | 7 + release/src/router/busybox/sysklogd/logger.c | 11 + release/src/router/busybox/sysklogd/logread.c | 6 + release/src/router/busybox/sysklogd/syslogd.c | 391 +- release/src/router/busybox/testsuite/awk.tests | 3 + release/src/router/busybox/testsuite/bzcat.tests | 30 + .../src/router/busybox/testsuite/date/date-@-works | 13 + .../src/router/busybox/testsuite/date/date-R-works | 21 +- .../router/busybox/testsuite/echo/echo-prints-dash | 1 + .../busybox/testsuite/echo/echo-prints-non-opts | 1 + .../busybox/testsuite/echo/echo-prints-slash_00041 | 3 + .../busybox/testsuite/echo/echo-prints-slash_0041 | 3 + .../busybox/testsuite/echo/echo-prints-slash_041 | 3 + .../busybox/testsuite/echo/echo-prints-slash_41 | 3 + release/src/router/busybox/testsuite/grep.tests | 18 +- release/src/router/busybox/testsuite/ls.tests | 11 + release/src/router/busybox/testsuite/mount.tests | 41 +- release/src/router/busybox/testsuite/od.tests | 22 +- release/src/router/busybox/testsuite/parse.tests | 1 + release/src/router/busybox/testsuite/patch.tests | 67 + release/src/router/busybox/testsuite/runtest | 6 +- release/src/router/busybox/testsuite/sed.tests | 13 +- release/src/router/busybox/testsuite/tail.tests | 8 + release/src/router/busybox/testsuite/tar.tests | 54 + .../busybox/testsuite/tar/tar-extracts-all-subdirs | 2 +- release/src/router/busybox/testsuite/testing.sh | 1 + .../src/router/busybox/testsuite/uncompress.tests | 20 + .../src/router/busybox/testsuite/uuencode.tests | 101 +- release/src/router/busybox/util-linux/Config.src | 129 +- release/src/router/busybox/util-linux/Kbuild.src | 1 - release/src/router/busybox/util-linux/acpid.c | 100 +- release/src/router/busybox/util-linux/blkid.c | 17 +- release/src/router/busybox/util-linux/blockdev.c | 29 +- release/src/router/busybox/util-linux/dmesg.c | 9 + release/src/router/busybox/util-linux/fbset.c | 32 +- release/src/router/busybox/util-linux/fdformat.c | 6 + release/src/router/busybox/util-linux/fdisk.c | 141 +- release/src/router/busybox/util-linux/fdisk_gpt.c | 6 +- release/src/router/busybox/util-linux/fdisk_osf.c | 14 +- release/src/router/busybox/util-linux/findfs.c | 8 + release/src/router/busybox/util-linux/flock.c | 12 +- .../src/router/busybox/util-linux/freeramdisk.c | 14 + release/src/router/busybox/util-linux/fsck_minix.c | 12 + release/src/router/busybox/util-linux/getopt.c | 86 +- release/src/router/busybox/util-linux/hexdump.c | 23 + release/src/router/busybox/util-linux/hwclock.c | 91 +- release/src/router/busybox/util-linux/ipcrm.c | 9 + release/src/router/busybox/util-linux/ipcs.c | 30 +- release/src/router/busybox/util-linux/losetup.c | 31 +- release/src/router/busybox/util-linux/lspci.c | 9 + release/src/router/busybox/util-linux/lsusb.c | 4 + release/src/router/busybox/util-linux/mdev.c | 709 +- release/src/router/busybox/util-linux/mkfs_ext2.c | 58 +- release/src/router/busybox/util-linux/mkfs_minix.c | 10 + .../src/router/busybox/util-linux/mkfs_reiser.c | 8 + release/src/router/busybox/util-linux/mkfs_vfat.c | 16 + release/src/router/busybox/util-linux/mkswap.c | 7 + release/src/router/busybox/util-linux/more.c | 12 +- release/src/router/busybox/util-linux/mount.c | 264 +- release/src/router/busybox/util-linux/pivot_root.c | 7 + release/src/router/busybox/util-linux/rdate.c | 7 + release/src/router/busybox/util-linux/rdev.c | 13 +- .../src/router/busybox/util-linux/readprofile.c | 14 + release/src/router/busybox/util-linux/rev.c | 2 +- release/src/router/busybox/util-linux/rtcwake.c | 23 + release/src/router/busybox/util-linux/script.c | 17 +- .../src/router/busybox/util-linux/scriptreplay.c | 6 + release/src/router/busybox/util-linux/setarch.c | 15 +- release/src/router/busybox/util-linux/swaponoff.c | 29 +- .../src/router/busybox/util-linux/switch_root.c | 11 +- release/src/router/busybox/util-linux/umount.c | 43 +- .../router/busybox/util-linux/volume_id/cramfs.c | 2 +- .../src/router/busybox/util-linux/volume_id/ext.c | 60 +- .../src/router/busybox/util-linux/volume_id/fat.c | 2 +- .../busybox/util-linux/volume_id/get_devname.c | 110 +- .../src/router/busybox/util-linux/volume_id/hfs.c | 2 +- .../router/busybox/util-linux/volume_id/iso9660.c | 2 +- .../src/router/busybox/util-linux/volume_id/jfs.c | 2 +- .../busybox/util-linux/volume_id/linux_raid.c | 2 +- .../busybox/util-linux/volume_id/linux_swap.c | 2 +- .../src/router/busybox/util-linux/volume_id/luks.c | 2 +- .../src/router/busybox/util-linux/volume_id/ntfs.c | 2 +- .../router/busybox/util-linux/volume_id/ocfs2.c | 2 +- .../router/busybox/util-linux/volume_id/reiserfs.c | 2 +- .../router/busybox/util-linux/volume_id/romfs.c | 2 +- .../src/router/busybox/util-linux/volume_id/sysv.c | 4 +- .../src/router/busybox/util-linux/volume_id/udf.c | 3 +- .../busybox/util-linux/volume_id/volume_id.c | 26 +- .../util-linux/volume_id/volume_id_internal.h | 4 +- .../src/router/busybox/util-linux/volume_id/xfs.c | 2 +- release/src/router/config/config.in | 58 +- release/src/router/cstats/Makefile | 39 + release/src/router/cstats/cstats.c | 798 ++ release/src/router/cstats/cstats.h | 103 + .../router/pppd/pppd/plugins/rp-pppoe/discovery.c | 2 + 747 files changed, 69231 insertions(+), 18113 deletions(-) rewrite release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h (69%) rewrite release/src/linux/linux/net/ipv4/netfilter/ipt_account.c (91%) create mode 100644 release/src/router/busybox/applets_sh/README create mode 100755 release/src/router/busybox/applets_sh/dos2unix create mode 100755 release/src/router/busybox/applets_sh/nologin create mode 100755 release/src/router/busybox/applets_sh/tac create mode 100755 release/src/router/busybox/applets_sh/unix2dos rename release/src/router/busybox/archival/libarchive/{decompress_unzip.c => decompress_gunzip.c} (96%) copy release/src/router/busybox/archival/libarchive/{get_header_tar_bz2.c => get_header_tar_gz.c} (67%) copy release/src/router/busybox/{config_base => config_nc} (92%) create mode 100644 release/src/router/busybox/configs/TEST_nommu_defconfig copy release/src/router/busybox/{config_base => configs/TEST_noprintf_defconfig} (75%) create mode 100644 release/src/router/busybox/configs/TEST_rh9_defconfig copy release/src/router/busybox/{config_base => configs/android2_defconfig} (56%) copy release/src/router/busybox/{config_base => configs/android_defconfig} (52%) copy release/src/router/busybox/{config_base => configs/android_ndk_defconfig} (52%) copy release/src/router/busybox/{config_base => configs/cygwin_defconfig} (55%) copy release/src/router/busybox/{config_base => configs/freebsd_defconfig} (66%) create mode 100644 release/src/router/busybox/coreutils/length.c.disabled create mode 100644 release/src/router/busybox/docs/syslog.conf.txt rewrite release/src/router/busybox/e2fsprogs/README (99%) create mode 100644 release/src/router/busybox/e2fsprogs/blkid/Kbuild.src create mode 100644 release/src/router/busybox/e2fsprogs/blkid/blkid.h create mode 100644 release/src/router/busybox/e2fsprogs/blkid/blkidP.h create mode 100644 release/src/router/busybox/e2fsprogs/blkid/blkid_getsize.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/cache.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/dev.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/devname.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/devno.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/list.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/list.h create mode 100644 release/src/router/busybox/e2fsprogs/blkid/probe.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/probe.h create mode 100644 release/src/router/busybox/e2fsprogs/blkid/read.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/resolve.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/save.c create mode 100644 release/src/router/busybox/e2fsprogs/blkid/tag.c create mode 100644 release/src/router/busybox/e2fsprogs/e2fsbb.h create mode 100644 release/src/router/busybox/e2fsprogs/e2fsck.c create mode 100644 release/src/router/busybox/e2fsprogs/e2fsck.h create mode 100644 release/src/router/busybox/e2fsprogs/e2p/Kbuild.src create mode 100644 release/src/router/busybox/e2fsprogs/e2p/e2p.h create mode 100644 release/src/router/busybox/e2fsprogs/e2p/feature.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/fgetsetflags.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/fgetsetversion.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/hashstr.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/iod.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/ls.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/mntopts.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/ostype.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/parse_num.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/pe.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/pf.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/ps.c create mode 100644 release/src/router/busybox/e2fsprogs/e2p/uuid.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/Kbuild.src create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/alloc.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/alloc_sb.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/alloc_stats.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/alloc_tables.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/badblocks.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bb_compat.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bb_inode.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bitmaps.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bitops.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bitops.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/block.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bmap.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/bmove.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/brel.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/brel_ma.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/check_desc.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/closefs.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/cmp_bitmaps.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dblist.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dblist_dir.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dir_iterate.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dirblock.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dirhash.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/dupfs.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/e2image.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/expanddir.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2_err.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2_ext_attr.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2_fs.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2_io.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2_types.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2fs.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2fsP.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext2fs_inline.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ext_attr.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/fileio.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/finddev.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/flushb.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/freefs.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/gen_bitmap.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/get_pathname.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/getsectsize.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/getsize.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/icount.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/imager.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ind_block.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/initialize.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/inline.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/inode.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/inode_io.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/io_manager.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/irel.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/irel_ma.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/ismounted.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/jfs_dat.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/kernel-jbd.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/kernel-list.h create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/link.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/lookup.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/mkdir.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/mkjournal.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/namei.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/newdir.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/openfs.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/read_bb.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/read_bb_file.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/res_gdt.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/rs_bitmap.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/rw_bitmaps.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/sparse.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/swapfs.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/test_io.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/unix_io.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/unlink.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/valid_blk.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/version.c create mode 100644 release/src/router/busybox/e2fsprogs/ext2fs/write_bb_file.c create mode 100644 release/src/router/busybox/e2fsprogs/fsck.h create mode 100644 release/src/router/busybox/e2fsprogs/mke2fs.c rewrite release/src/router/busybox/e2fsprogs/tune2fs.c (78%) create mode 100644 release/src/router/busybox/e2fsprogs/util.c create mode 100644 release/src/router/busybox/e2fsprogs/util.h create mode 100644 release/src/router/busybox/e2fsprogs/uuid/Kbuild.src create mode 100644 release/src/router/busybox/e2fsprogs/uuid/compare.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/gen_uuid.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/pack.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/parse.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/unpack.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/unparse.c create mode 100644 release/src/router/busybox/e2fsprogs/uuid/uuid.h create mode 100644 release/src/router/busybox/e2fsprogs/uuid/uuidP.h create mode 100644 release/src/router/busybox/e2fsprogs/uuid/uuid_time.c rewrite release/src/router/busybox/editors/Config.src (65%) create mode 100644 release/src/router/busybox/examples/android-build create mode 100644 release/src/router/busybox/examples/var_service/README create mode 100644 release/src/router/busybox/include/applet_metadata.h rewrite release/src/router/busybox/include/applets.src.h (85%) create mode 100644 release/src/router/busybox/include/bb_archive.h create mode 100644 release/src/router/busybox/include/bb_e2fs_defs.h rewrite release/src/router/busybox/include/usage.src.h (99%) create mode 100644 release/src/router/busybox/libbb/get_shell_name.c create mode 100644 release/src/router/busybox/libbb/inet_cksum.c create mode 100644 release/src/router/busybox/libbb/percent_decode.c create mode 100644 release/src/router/busybox/libbb/systemd_support.c create mode 100644 release/src/router/busybox/loginutils/README rewrite release/src/router/busybox/loginutils/getty.c (72%) create mode 100644 release/src/router/busybox/mailutils/makemime.c create mode 100644 release/src/router/busybox/mailutils/reformime.c create mode 100644 release/src/router/busybox/miscutils/setserial.c create mode 100644 release/src/router/busybox/miscutils/ubi_tools.c copy release/src/router/busybox/networking/udhcp/{common.c => common.c.20} (86%) copy release/src/router/busybox/networking/udhcp/{common.h => common.h.20} (96%) create mode 100644 release/src/router/busybox/networking/udhcp/d6_common.h create mode 100644 release/src/router/busybox/networking/udhcp/d6_dhcpc.c create mode 100644 release/src/router/busybox/networking/udhcp/d6_packet.c create mode 100644 release/src/router/busybox/networking/udhcp/d6_socket.c copy release/src/router/busybox/networking/udhcp/{dhcpc.c => dhcpc.c.20} (82%) create mode 100644 release/src/router/busybox/networking/whois.c rewrite release/src/router/busybox/procps/fuser.c (65%) create mode 100644 release/src/router/busybox/procps/lsof.c create mode 100644 release/src/router/busybox/procps/pstree.c create mode 100644 release/src/router/busybox/procps/pwdx.c create mode 100644 release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.tests create mode 100644 release/src/router/busybox/shell/ash_test/ash-signals/sigint1.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-signals/sigint1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/assignment4.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/assignment4.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/echo_write_error.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/echo_write_error.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/return1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/return1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/sigint1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/sigint1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/source1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/source1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/signal_read1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/signal_read1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/signal_read2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/signal_read2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_expand_on_ifs.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_expand_on_ifs.tests create mode 100644 release/src/router/busybox/testsuite/date/date-@-works rewrite release/src/router/busybox/testsuite/date/date-R-works (99%) create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-dash create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-non-opts create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-slash_00041 create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-slash_0041 create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-slash_041 create mode 100644 release/src/router/busybox/testsuite/echo/echo-prints-slash_41 create mode 100644 release/src/router/busybox/testsuite/uncompress.tests create mode 100644 release/src/router/cstats/Makefile create mode 100644 release/src/router/cstats/cstats.c create mode 100644 release/src/router/cstats/cstats.h diff --git a/release/src/btools/fpkg.c b/release/src/btools/fpkg.c index d11df83b50..acbd7c165b 100644 --- a/release/src/btools/fpkg.c +++ b/release/src/btools/fpkg.c @@ -320,7 +320,10 @@ void create_cytan(const char *fname, const char *pattern) memset(&h, 0, sizeof(h)); memcpy(h.magic, pattern, 4); memcpy(h.u2nd, "U2ND", 4); - h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h + h.version[0] = 4; // stock fw has version check + h.version[1] = 20; + h.version[2] = 6; +// h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h h.flags = 0xFF; tm = localtime(&max_time); h.date[0] = tm->tm_year - 100; diff --git a/release/src/btools/libfoo.pl b/release/src/btools/libfoo.pl index 8716feab58..39a7b32159 100755 --- a/release/src/btools/libfoo.pl +++ b/release/src/btools/libfoo.pl @@ -155,7 +155,9 @@ sub fixDyn fixDynDep("pppd", "rp-pppoe.so"); fixDynDep("libcrypto.so.1.0.0", "libssl.so.1.0.0"); - +#shibby + fixDynDep("miniupnpd", "libnfnetlink.so.0.2.0"); + # fixDynDep("libbcm.so", "libshared.so"); # fixDynDep("libbcm.so", "libc.so.0"); @@ -165,6 +167,11 @@ sub fixDyn fixDynDep("wl", "libbcmcrypto.so"); fixDynDep("nas", "libc.so.0"); fixDynDep("wl", "libc.so.0"); +#Roadkill for NocatSplash + fixDynDep("splashd","libglib-1.2.so.0.0.10"); +#Roadkill for php + fixDynDep("php-cli","libz.so.1.2.5"); + fixDynDep("php-cgi","libz.so.1.2.5"); } sub usersOf @@ -405,8 +412,8 @@ if ((!-d $root) || (!-d $uclibc) || (!-d $router)) { exit(1); } -#open(LOG, ">libfoo.debug"); -open(LOG, ">/dev/null"); +open(LOG, ">libfoo.debug"); +#open(LOG, ">/dev/null"); print "Loading...\r"; load($root); @@ -422,17 +429,17 @@ if ($ARGV[0] eq "--noopt") { $stripshared = "no"; } -genSO("${root}/lib/libc.so.0", "${uclibc}/lib/libc.a", "${stripshared}", "-Wl,-init=__uClibc_init ${uclibc}/lib/optinfo/interp.os"); +genSO("${root}/lib/libc.so.0", "${uclibc}/lib/libc.a", "", "-Wl,-init=__uClibc_init ${uclibc}/lib/optinfo/interp.os"); genSO("${root}/lib/libresolv.so.0", "${uclibc}/lib/libresolv.a", "${stripshared}"); genSO("${root}/lib/libcrypt.so.0", "${uclibc}/lib/libcrypt.a", "${stripshared}"); -genSO("${root}/lib/libm.so.0", "${uclibc}/lib/libm.a", "${stripshared}"); +genSO("${root}/lib/libm.so.0", "${uclibc}/lib/libm.a"); genSO("${root}/lib/libpthread.so.0", "${uclibc}/lib/libpthread.a", "${stripshared}", "-u pthread_mutexattr_init -Wl,-init=__pthread_initialize_minimal_internal"); genSO("${root}/lib/libutil.so.0", "${uclibc}/lib/libutil.a", "${stripshared}"); # genSO("${root}/lib/libdl.so.0", "${uclibc}/lib/libdl.a", "${stripshared}"); # genSO("${root}/lib/libnsl.so.0", "${uclibc}/lib/libnsl.a", "${stripshared}"); genSO("${root}/usr/lib/libcrypto.so.1.0.0", "${router}/openssl/libcrypto.a"); -genSO("${root}/usr/lib/libssl.so.1.0.0", "${router}/openssl/libssl.a", "", "-L${router}/openssl"); +genSO("${root}/usr/lib/libssl.so.1.0.0", "${router}/openssl/libssl.a", "${stripshared}", "-L${router}/openssl"); genSO("${root}/usr/lib/libzebra.so", "${router}/zebra/lib/libzebra.a"); genSO("${root}/usr/lib/libz.so.1", "${router}/zlib/libz.a"); @@ -458,6 +465,7 @@ genSO("${root}/usr/lib/liblzo2.so.2", "${router}/lzo/src/.libs/liblzo2.a"); # genSO("${root}/usr/lib/libusb-0.1.so.4", "${router}/libusb/libusb/.libs/libusb.a", "", "-L${router}/libusb10/libusb/.libs"); genSO("${root}/usr/lib/libbcmcrypto.so", "${router}/libbcmcrypto/libbcmcrypto.a"); +genSO("${root}/usr/lib/libnfnetlink.so.0.2.0", "${router}/libnfnetlink/src/.libs/libnfnetlink.a"); print "\n"; diff --git a/release/src/include/bcmparams.h b/release/src/include/bcmparams.h index 19a8ff608a..a93294aff2 100644 --- a/release/src/include/bcmparams.h +++ b/release/src/include/bcmparams.h @@ -18,7 +18,7 @@ #define VLAN_NUMPRIS 8 /* # of prio, start from 0 */ -#define DEV_NUMIFS 16 /* Max. # of devices/interfaces supported */ +#define DEV_NUMIFS 32 /* Max. # of devices/interfaces supported */ #define WL_MAXBSSCFG 16 /* maximum number of BSS Configs we can configure */ diff --git a/release/src/linux/linux/Documentation/Configure.help b/release/src/linux/linux/Documentation/Configure.help index a28ad007d7..3173feaf5b 100644 --- a/release/src/linux/linux/Documentation/Configure.help +++ b/release/src/linux/linux/Documentation/Configure.help @@ -2868,6 +2868,18 @@ CONFIG_IP_NF_IPTABLES If you want to compile it as a module, say M here and read . If unsure, say `N'. +account match support +CONFIG_IP_NF_MATCH_ACCOUNT + This match is used for gathering traffic statistics for particular + netblock. + + Short options are available by using 'iptables -m account -h' + Official Website: + Official Website: + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + recent match support CONFIG_IP_NF_MATCH_RECENT This match is used for creating one or many lists of recently diff --git a/release/src/linux/linux/arch/mips/bcm947xx/setup.c b/release/src/linux/linux/arch/mips/bcm947xx/setup.c index 14ec3cc53c..38572177a5 100644 --- a/release/src/linux/linux/arch/mips/bcm947xx/setup.c +++ b/release/src/linux/linux/arch/mips/bcm947xx/setup.c @@ -70,6 +70,10 @@ spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(bcm947xx_sbh); EXPORT_SYMBOL(bcm947xx_sbh_lock); +/* CPU freq Tomato RAF features */ +int bcm947xx_cpu_clk; +EXPORT_SYMBOL(bcm947xx_cpu_clk); + /* Convenience */ #define sbh bcm947xx_sbh #define sbh_lock bcm947xx_sbh_lock diff --git a/release/src/linux/linux/arch/mips/bcm947xx/time.c b/release/src/linux/linux/arch/mips/bcm947xx/time.c index f1e67f776c..ca38f24679 100644 --- a/release/src/linux/linux/arch/mips/bcm947xx/time.c +++ b/release/src/linux/linux/arch/mips/bcm947xx/time.c @@ -43,6 +43,7 @@ extern spinlock_t bcm947xx_sbh_lock; extern int panic_timeout; static int watchdog = 0; static u8 *mcr = NULL; +extern int bcm947xx_cpu_clk; //Tomato RAF features void __init bcm947xx_time_init(void) @@ -66,6 +67,7 @@ bcm947xx_time_init(void) printk("CPU: BCM%04x rev %d pkg %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh), sb_chippkg(sbh), (hz + 500000) / 1000000); + bcm947xx_cpu_clk = (hz + 500000) / 1000000; //Tomato RAF feature /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */ if (sb_chip(sbh) == BCM5354_CHIP_ID && diff --git a/release/src/linux/linux/arch/mips/kernel/proc.c b/release/src/linux/linux/arch/mips/kernel/proc.c index 622be896e9..721c908cae 100644 --- a/release/src/linux/linux/arch/mips/kernel/proc.c +++ b/release/src/linux/linux/arch/mips/kernel/proc.c @@ -16,6 +16,7 @@ #include unsigned int vced_count, vcei_count; +extern int bcm947xx_cpu_clk; //Tomato RAF features #ifndef CONFIG_CPU_HAS_LLSC unsigned long ll_ops, sc_ops; @@ -116,6 +117,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", loops_per_jiffy / (500000/HZ), (loops_per_jiffy / (5000/HZ)) % 100); + seq_printf(m, "cpu MHz \t\t: %d\n", bcm947xx_cpu_clk); //Tomato RAF features seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); seq_printf(m, "microsecond timers\t: %s\n", cpu_has_counter ? "yes" : "no"); diff --git a/release/src/linux/linux/config_base b/release/src/linux/linux/config_base index 320f965b4a..5c8b5a4d53 100644 --- a/release/src/linux/linux/config_base +++ b/release/src/linux/linux/config_base @@ -364,7 +364,7 @@ CONFIG_IP_NF_MATCH_CONDITION=m # CONFIG_IP_NF_MATCH_PSD is not set # CONFIG_IP_NF_MATCH_RANDOM is not set CONFIG_IP_NF_MATCH_RECENT=m -# CONFIG_IP_NF_MATCH_ACCOUNT is not set +CONFIG_IP_NF_MATCH_ACCOUNT=y # CONFIG_IP_NF_POOL is not set # CONFIG_IP_NF_MATCH_ECN is not set CONFIG_IP_NF_MATCH_IPP2P=m @@ -680,7 +680,7 @@ CONFIG_IMQ=m # CONFIG_IMQ_BEHAVIOR_AB is not set CONFIG_IMQ_BEHAVIOR_BA=y # CONFIG_IMQ_BEHAVIOR_BB is not set -CONFIG_IMQ_NUM_DEVS=2 +CONFIG_IMQ_NUM_DEVS=3 CONFIG_TUN=m # CONFIG_NET_RANDOM is not set # CONFIG_ETHERTAP is not set diff --git a/release/src/linux/linux/drivers/net/ppp_generic.c b/release/src/linux/linux/drivers/net/ppp_generic.c index 2b50f23982..f680a17c6e 100644 --- a/release/src/linux/linux/drivers/net/ppp_generic.c +++ b/release/src/linux/linux/drivers/net/ppp_generic.c @@ -1768,15 +1768,22 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) ppp->minseq = ppp->mrq.next->sequence; /* Pull completed packets off the queue and receive them. */ +/* shibby - fix mlppp while ((skb = ppp_mp_reconstruct(ppp)) != 0) { if (pskb_may_pull(skb, 2)) ppp_receive_nonmp_frame(ppp, skb); else { - ++ppp->dev->stats.rx_length_errors; + ++ppp->stats.rx_length_errors; kfree_skb(skb); ppp_receive_error(ppp); } } +shibby */ + +//shibby - backport from ddwrt source - fix mlppp + while ((skb = ppp_mp_reconstruct(ppp)) != 0) + ppp_receive_nonmp_frame(ppp, skb); +//end return; diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h dissimilarity index 69% index 6068d86d8b..e239c44e80 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h @@ -1,26 +1,24 @@ -/* - * accounting match (ipt_account.c) - * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) - * - * Version: 0.1.7 - * - * This software is distributed under the terms of GNU GPL - */ - -#ifndef _IPT_ACCOUNT_H_ -#define _IPT_ACCOUNT_H_ - -#define IPT_ACCOUNT_NAME_LEN 64 - -#define IPT_ACCOUNT_NAME "ipt_account" -#define IPT_ACCOUNT_VERSION "0.1.7" - -struct t_ipt_account_info { - char name[IPT_ACCOUNT_NAME_LEN]; - u_int32_t network; - u_int32_t netmask; - int shortlisting:1; -}; - -#endif - +/* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasidlo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _IPT_ACCOUNT_H_ +#define _IPT_ACCOUNT_H_ + +#define IPT_ACCOUNT_NAME_LEN 64 + +struct t_ipt_account_table; + +struct t_ipt_account_info { + char name[IPT_ACCOUNT_NAME_LEN + 1]; + u_int32_t network, netmask; + int shortlisting:1; + /* pointer to the table for fast matching */ + struct t_ipt_account_table *table; +}; + +#endif /* _IPT_ACCOUNT_H */ + diff --git a/release/src/linux/linux/include/linux/pkt_sched.h b/release/src/linux/linux/include/linux/pkt_sched.h index 7efba0e393..6a752c801d 100644 --- a/release/src/linux/linux/include/linux/pkt_sched.h +++ b/release/src/linux/linux/include/linux/pkt_sched.h @@ -80,8 +80,9 @@ struct tc_ratespec { unsigned char cell_log; unsigned char __reserved; - unsigned short feature; - short addend; + unsigned short feature; /* Always 0 in pre-atm patch kernels */ + char cell_align; /* Always 0 in pre-atm patch kernels */ + unsigned char __unused; unsigned short mpu; __u32 rate; }; @@ -280,9 +281,9 @@ struct tc_gred_sopt }; /* HTB section */ -#define TC_HTB_NUMPRIO 8 +#define TC_HTB_NUMPRIO 11 /* Toastman */ #define TC_HTB_MAXDEPTH 8 -#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ +#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ struct tc_htb_opt { @@ -354,7 +355,7 @@ enum /* CBQ section */ -#define TC_CBQ_MAXPRIO 8 +#define TC_CBQ_MAXPRIO 11 /* Toastman */ #define TC_CBQ_MAXLEVEL 8 #define TC_CBQ_DEF_EWMA 5 diff --git a/release/src/linux/linux/include/net/pkt_sched.h b/release/src/linux/linux/include/net/pkt_sched.h index 8bc7e609fe..37096827f3 100644 --- a/release/src/linux/linux/include/net/pkt_sched.h +++ b/release/src/linux/linux/include/net/pkt_sched.h @@ -459,6 +459,19 @@ static inline void qdisc_run(struct net_device *dev) qdisc_restart(dev)<0) /* NOTHING */; } +/* Lookup a qdisc_rate_table to determine how long it will take to send a + packet given its size. + */ +static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, int pktlen) +{ + int slot = pktlen + rtab->rate.cell_align; + if (slot < 0) + slot = 0; + slot >>= rtab->rate.cell_log; + if (slot > 255) + return rtab->data[255] + 1; + return rtab->data[slot]; +} /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. diff --git a/release/src/linux/linux/net/ipv4/netfilter/Config.in b/release/src/linux/linux/net/ipv4/netfilter/Config.in index 03ad8321fe..3218070756 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv4/netfilter/Config.in @@ -44,9 +44,6 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' random match support' CONFIG_IP_NF_MATCH_RANDOM $CONFIG_IP_NF_IPTABLES dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES dep_tristate ' account match support' CONFIG_IP_NF_MATCH_ACCOUNT $CONFIG_IP_NF_IPTABLES $CONFIG_PROC_FS - if [ "$CONFIG_IP_NF_MATCH_ACCOUNT" != "n" ]; then - bool ' account debugging output' CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG - fi dep_tristate ' IP address pool support' CONFIG_IP_NF_POOL $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_POOL" = "y" -o "$CONFIG_IP_NF_POOL" = "m" ]; then bool ' enable statistics on pool usage' CONFIG_IP_POOL_STATISTICS n diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c dissimilarity index 91% index 7fd3456221..8b862588a3 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c @@ -1,942 +1,818 @@ -/* - * accounting match (ipt_account.c) - * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) - * - * Version: 0.1.7 - * - * This software is distributed under the terms of GNU GPL - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include -#include - -#if defined(CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG) - #define dprintk(format,args...) printk(format,##args) -#else - #define dprintk(format,args...) -#endif - -static char version[] = -KERN_INFO IPT_ACCOUNT_NAME " " IPT_ACCOUNT_VERSION " : Piotr Gasid³o , http://www.barbara.eu.org/~quaker/ipt_account/\n"; - -/* rights for files created in /proc/net/ipt_account/ */ -static int permissions = 0644; -/* maximal netmask for single table */ -static int netmask = 16; - -/* module information */ -MODULE_AUTHOR("Piotr Gasidlo "); -MODULE_DESCRIPTION("Traffic accounting modules"); -MODULE_LICENSE("GPL"); -MODULE_PARM(permissions,"i"); -MODULE_PARM_DESC(permissions,"permissions on /proc/net/ipt_account/* files"); -MODULE_PARM(netmask, "i"); -MODULE_PARM_DESC(netmask, "maximum *save* size of one list (netmask)"); - -/* structure with statistics counters */ -struct t_ipt_account_stat { - u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; /* byte counters for all/tcp/udp/icmp/other traffic */ - u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; /* packet counters for all/tcp/udp/icmp/other traffic */ -}; - -/* stucture with statistics counters, used when table is created with --ashort switch */ -struct t_ipt_account_stat_short { - u_int64_t b_all; /* byte counters for all traffic */ - u_int64_t p_all; /* packet counters for all traffic */ -}; - -/* structure holding to/from statistics for single ip */ -struct t_ipt_account_ip_list { - struct t_ipt_account_stat src; - struct t_ipt_account_stat dest; - unsigned long time; /* time when this record was last updated */ - -}; - -/* same as above, for tables with --ashort switch */ -struct t_ipt_account_ip_list_short { - struct t_ipt_account_stat_short src; - struct t_ipt_account_stat_short dest; - unsigned long time; -}; - -/* structure describing single table */ -struct t_ipt_account_table { - char name[IPT_ACCOUNT_NAME_LEN]; /* table name ( = filename in /proc/net/ipt_account/) */ - union { /* table with statistics for each ip in network/netmask */ - struct t_ipt_account_ip_list *l; - struct t_ipt_account_ip_list_short *s; - } ip_list; - u_int32_t network; /* network/netmask covered by table*/ - u_int32_t netmask; - u_int32_t count; - int shortlisting:1; /* show only total columns of counters */ - int use_count; /* rules counter - counting number of rules using this table */ - struct t_ipt_account_table *next; - spinlock_t ip_list_lock; - struct proc_dir_entry *status_file; -}; - -/* we must use spinlocks to avoid parallel modifications of table list */ -static spinlock_t account_lock = SPIN_LOCK_UNLOCKED; - -static struct proc_dir_entry *proc_net_ipt_account = NULL; - -/* root pointer holding list of the tables */ -static struct t_ipt_account_table *account_tables = NULL; - -/* convert ascii to ip */ -int atoip(char *buffer, u_int32_t *ip) { - - char *bufferptr = buffer; - int part, shift; - - /* zero ip */ - *ip = 0; - - /* first must be a digit */ - if (!isdigit(*bufferptr)) - return 0; - - /* parse first 3 octets (III.III.III.iii) */ - for (part = 0, shift = 24; *bufferptr && shift; bufferptr++) { - if (isdigit(*bufferptr)) { - part = part * 10 + (*bufferptr - '0'); - continue; - } - if (*bufferptr == '.') { - if (part > 255) - return 0; - *ip |= part << shift; - shift -= 8; - part = 0; - continue; - } - return 0; - } - - /* we expect more digts */ - if (!*bufferptr) - return 0; - /* parse last octet (iii.iii.iii.III) */ - for (; *bufferptr; bufferptr++) { - if (isdigit(*bufferptr)) { - part = part * 10 + (*bufferptr - '0'); - continue; - } else { - if (part > 255) - return 0; - *ip |= part; - break; - } - } - return (bufferptr - buffer); -} - -/* convert ascii to 64bit integer */ -int atoi64(char *buffer, u_int64_t *i) { - char *bufferptr = buffer; - - /* zero integer */ - *i = 0; - - while (isdigit(*bufferptr)) { - *i = *i * 10 + (*bufferptr - '0'); - bufferptr++; - } - return (bufferptr - buffer); -} - -static void *account_seq_start(struct seq_file *s, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - - unsigned int *bucket; - - spin_lock_bh(&table->ip_list_lock); - if (*pos >= table->count) - return NULL; - - bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL); - if (!bucket) - return ERR_PTR(-ENOMEM); - *bucket = *pos; - return bucket; -} - -static void *account_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - - unsigned int *bucket = (unsigned int *)v; - - *pos = ++(*bucket); - if (*pos >= table->count) { - kfree(v); - return NULL; - } - return bucket; -} - -static void account_seq_stop(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - unsigned int *bucket = (unsigned int *)v; - kfree(bucket); - spin_unlock_bh(&table->ip_list_lock); -} - -static int account_seq_write(struct file *file, const char *ubuffer, - size_t ulength, loff_t *pos) -{ - struct proc_dir_entry *pde = ((struct seq_file *)file->private_data)->private; - struct t_ipt_account_table *table = pde->data; - char buffer[1024], *bufferptr; - int length; - - u_int32_t ip; - int len, i; - struct t_ipt_account_ip_list l; - struct t_ipt_account_ip_list_short s; - u_int64_t *p, dummy; - - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() entered.\n"); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() ulength = %zi.\n", ulength); - - length = ulength; - if (ulength > 1024) - length = 1024; - if (copy_from_user(buffer, ubuffer, length)) - return -EFAULT; - buffer[length - 1] = 0; - bufferptr = buffer; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() buffer = \'%s\' length = %i.\n", buffer, length); - - /* reset table counters */ - if (!memcmp(buffer, "reset", 5)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"reset\".\n"); - if (!table->shortlisting) { - spin_lock_bh(&table->ip_list_lock); - memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); - spin_unlock_bh(&table->ip_list_lock); - } else { - spin_lock_bh(&table->ip_list_lock); - memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); - spin_unlock_bh(&table->ip_list_lock); - } - return length; - } - - if (!memcmp(buffer, "ip", 2)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"ip\".\n"); - bufferptr += 2; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoip(bufferptr, &ip))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip (%ti).\n", bufferptr - buffer); - return length; /* expected ip */ - } - bufferptr += len; - if ((ip & table->netmask) != table->network) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask)); - return length; /* expected ip from table's network/netmask */ - } - if (!table->shortlisting) { - memset(&l, 0, sizeof(struct t_ipt_account_ip_list)); - while(*bufferptr) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!memcmp(bufferptr, "bytes_src", 9)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); - p = &l.src.b_all; - bufferptr += 9; - } else if (!memcmp(bufferptr, "bytes_dest", 10)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); - p = &l.dest.b_all; - bufferptr += 10; - } else if (!memcmp(bufferptr, "packets_src", 11)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); - p = &l.src.p_all; - bufferptr += 11; - } else if (!memcmp(bufferptr, "packets_dest", 12)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); - p = &l.dest.p_all; - bufferptr += 12; - } else if (!memcmp(bufferptr, "time", 4)) { - /* time hack, ignore time tokens */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); - bufferptr += 4; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, &dummy))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); - bufferptr += len; - continue; /* skip time token */ - } else - return length; /* expected token */ - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - for (i = 0; i < 5; i++) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, p))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); - bufferptr += len; - p++; - } - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); - spin_lock_bh(&table->ip_list_lock); - /* update counters, do not overwrite time field */ - memcpy(&table->ip_list.l[ip - table->network], &l, sizeof(struct t_ipt_account_ip_list) - sizeof(unsigned long)); - spin_unlock_bh(&table->ip_list_lock); - } else { - memset(&s, 0, sizeof(struct t_ipt_account_ip_list_short)); - while(*bufferptr) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!memcmp(bufferptr, "bytes_src", 9)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); - p = &s.src.b_all; - bufferptr += 9; - } else if (!memcmp(bufferptr, "bytes_dest", 10)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); - p = &s.dest.b_all; - bufferptr += 10; - } else if (!memcmp(bufferptr, "packets_src", 11)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); - p = &s.src.p_all; - bufferptr += 11; - } else if (!memcmp(bufferptr, "packets_dest", 12)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); - p = &s.dest.p_all; - bufferptr += 12; - } else if (!memcmp(bufferptr, "time", 4)) { - /* time hack, ignore time tokens */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); - bufferptr += 4; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, &dummy))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); - bufferptr += len; - continue; /* skip time token */ - } else { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected token (%ti).\n", bufferptr - buffer); - return length; /* expected token */ - } - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, p))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); - bufferptr += len; - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); - spin_lock_bh(&table->ip_list_lock); - /* update counters, do not overwrite time field */ - memcpy(&table->ip_list.s[ip - table->network], &s, sizeof(struct t_ipt_account_ip_list_short) - sizeof(unsigned long)); - spin_unlock_bh(&table->ip_list_lock); - } - } - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() left.\n"); - return length; -} - - -static int account_seq_show(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - unsigned int *bucket = (unsigned int *)v; - - u_int32_t address = table->network + *bucket; - struct timespec last; - - if (!table->shortlisting) { - jiffies_to_timespec(jiffies - table->ip_list.l[*bucket].time, &last); - seq_printf(s, - "ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu time = %lu\n", - HIPQUAD(address), - table->ip_list.l[*bucket].src.b_all, - table->ip_list.l[*bucket].src.b_tcp, - table->ip_list.l[*bucket].src.b_udp, - table->ip_list.l[*bucket].src.b_icmp, - table->ip_list.l[*bucket].src.b_other, - table->ip_list.l[*bucket].src.p_all, - table->ip_list.l[*bucket].src.p_tcp, - table->ip_list.l[*bucket].src.p_udp, - table->ip_list.l[*bucket].src.p_icmp, - table->ip_list.l[*bucket].src.p_other, - table->ip_list.l[*bucket].dest.b_all, - table->ip_list.l[*bucket].dest.b_tcp, - table->ip_list.l[*bucket].dest.b_udp, - table->ip_list.l[*bucket].dest.b_icmp, - table->ip_list.l[*bucket].dest.b_other, - table->ip_list.l[*bucket].dest.p_all, - table->ip_list.l[*bucket].dest.p_tcp, - table->ip_list.l[*bucket].dest.p_udp, - table->ip_list.l[*bucket].dest.p_icmp, - table->ip_list.l[*bucket].dest.p_other, - last.tv_sec - ); - } else { - jiffies_to_timespec(jiffies - table->ip_list.s[*bucket].time, &last); - seq_printf(s, - "ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu time = %lu\n", - HIPQUAD(address), - table->ip_list.s[*bucket].src.b_all, - table->ip_list.s[*bucket].src.p_all, - table->ip_list.s[*bucket].dest.b_all, - table->ip_list.s[*bucket].dest.p_all, - last.tv_sec - ); - } - return 0; -} - -static struct seq_operations account_seq_ops = { - .start = account_seq_start, - .next = account_seq_next, - .stop = account_seq_stop, - .show = account_seq_show -}; - -static int account_seq_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &account_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -} - -static struct file_operations account_file_ops = { - .owner = THIS_MODULE, - .open = account_seq_open, - .read = seq_read, - .write = account_seq_write, - .llseek = seq_lseek, - .release = seq_release -}; - -/* do raw accounting */ -static inline void do_account(struct t_ipt_account_stat *stat, const struct sk_buff *skb) { - - /* update packet & bytes counters in *stat structure */ - stat->b_all += skb->len; - stat->p_all++; - - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - stat->b_tcp += skb->len; - stat->p_tcp++; - break; - case IPPROTO_UDP: - stat->b_udp += skb->len; - stat->p_udp++; - break; - case IPPROTO_ICMP: - stat->b_icmp += skb->len; - stat->p_icmp++; - break; - default: - stat->b_other += skb->len; - stat->p_other++; - } -} - -static inline void do_account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) { - - /* update packet & bytes counters in *stat structure */ - stat->b_all += skb->len; - stat->p_all++; -} - -static int match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - const void *hdr, - u_int16_t datalen, - int *hotdrop) -{ - - const struct t_ipt_account_info *info = (struct t_ipt_account_info*)matchinfo; - struct t_ipt_account_table *table; - int ret; - unsigned long now; - - u_int32_t address; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() entered.\n"); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() match name = %s.\n", info->name); - - spin_lock_bh(&account_lock); - /* find the right table */ - table = account_tables; - while (table && strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next)); - spin_unlock_bh(&account_lock); - - if (table == NULL) { - /* ups, no table with that name */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table %s not found. Leaving.\n", info->name); - return 0; - } - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table found %s\n", table->name); - - /* lock table while updating statistics */ - spin_lock_bh(&table->ip_list_lock); - - /* default: no match */ - ret = 0; - - /* get current time */ - now = jiffies; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() got packet src = %u.%u.%u.%u, dst = %u.%u.%u.%u, proto = %u.\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->nh.iph->protocol); - - /* check whether traffic from source ip address ... */ - address = ntohl(skb->nh.iph->saddr); - /* ... is being accounted by this table */ - if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { - /* yes, account this packet */ - dprintk(KERN_INFO "ipt_account: match() accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); - /* update counters this host */ - if (!table->shortlisting) { - do_account(&table->ip_list.l[address - table->network].src, skb); - table->ip_list.l[address - table->network].time = now; - /* update also counters for all hosts in this table (network address) */ - if (table->netmask != INADDR_BROADCAST) { - do_account(&table->ip_list.l[0].src, skb); - table->ip_list.l[0].time = now; - } - } else { - do_account_short(&table->ip_list.s[address - table->network].src, skb); - table->ip_list.s[address - table->network].time = now; - /* update also counters for all hosts in this table (network address) */ - if (table->netmask != INADDR_BROADCAST) { - do_account_short(&table->ip_list.s[0].src, skb); - table->ip_list.s[0].time = now; - } - } - /* yes, it's a match */ - ret = 1; - } - - /* do the same thing with destination ip address */ - address = ntohl(skb->nh.iph->daddr); - if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); - if (!table->shortlisting) { - do_account(&table->ip_list.l[address - table->network].dest, skb); - table->ip_list.l[address - table->network].time = now; - if (table->netmask != INADDR_BROADCAST) { - do_account(&table->ip_list.l[0].dest, skb); - table->ip_list.s[0].time = now; - } - } else { - do_account_short(&table->ip_list.s[address - table->network].dest, skb); - table->ip_list.s[address - table->network].time = now; - if (table->netmask != INADDR_BROADCAST) { - do_account_short(&table->ip_list.s[0].dest, skb); - table->ip_list.s[0].time = now; - } - } - ret = 1; - } - spin_unlock_bh(&table->ip_list_lock); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() left.\n"); - - return ret; -} - -static int checkentry(const char *tablename, - const struct ipt_ip *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) -{ - const struct t_ipt_account_info *info = matchinfo; - struct t_ipt_account_table *table, *find_table, *last_table; - int ret = 0; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() entered.\n"); - - if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return 0; - if (!info->name || !info->name[0]) return 0; - - /* find whether table with this name already exists */ - spin_lock_bh(&account_lock); - find_table = account_tables; - while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); - if (find_table != NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); - /* if table exists, check whether table network/netmask equals rule network/netmask */ - if (find_table->network != info->network || find_table->netmask != info->netmask || find_table->shortlisting != info->shortlisting) { - spin_unlock_bh(&account_lock); - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong parameters (not equals existing table parameters).\n"); - ret = 0; - goto failure; - } - /* increment table use count */ - find_table->use_count++; - spin_unlock_bh(&account_lock); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); - ret = 1; - goto failure; - } - spin_unlock_bh(&account_lock); - - /* check netmask first, before allocating memory */ - if (info->netmask < ((1 << netmask) - 1)) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() too big netmask.\n"); - ret = 0; - goto failure; - } - - /* table doesn't exist - create new */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); - table = vmalloc(sizeof(struct t_ipt_account_table)); - if (table == NULL) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); - ret = 0; /* was -ENOMEM */ - goto failure; - } - - /* setup table parameters */ - table->ip_list_lock = SPIN_LOCK_UNLOCKED; - table->next = NULL; - table->use_count = 1; - table->network = info->network; - table->netmask = info->netmask; - table->shortlisting = info->shortlisting; - table->count = (~table->netmask) + 1; - strncpy(table->name,info->name,IPT_ACCOUNT_NAME_LEN); - table->name[IPT_ACCOUNT_NAME_LEN - 1] = '\0'; - - /* allocate memory for table->ip_list */ - if (!table->shortlisting) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); - table->ip_list.l = vmalloc(sizeof(struct t_ipt_account_ip_list) * table->count); - if (table->ip_list.l == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); - ret = 0; /* was -ENOMEM */ - goto failure_table; - } - memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); - } else { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); - table->ip_list.s = vmalloc(sizeof(struct t_ipt_account_ip_list_short) * table->count); - if (table->ip_list.s == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); - ret = 0; /* was -ENOMEM */ - goto failure_table; - } - memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); - } - - /* put table into chain */ - spin_lock_bh(&account_lock); - find_table = account_tables; - while( (last_table = find_table) && strncmp(info->name, find_table->name, IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); - if (find_table != NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); - if (find_table->network != info->network || find_table->netmask != info->netmask) { - spin_unlock_bh(&account_lock); - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong network/netmask.\n"); - ret = 0; - goto failure_ip_list; - } - find_table->use_count++; - spin_unlock_bh(&account_lock); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); - ret = 1; - goto failure_ip_list; - } - if (!last_table) - account_tables = table; - else - last_table->next = table; - spin_unlock_bh(&account_lock); - - /* create procfs status file */ - table->status_file = create_proc_entry(table->name, permissions, proc_net_ipt_account); - if (table->status_file == NULL) { - ret = 0; /* was -ENOMEM */ - goto failure_unlink; - } - table->status_file->owner = THIS_MODULE; - table->status_file->data = table; - wmb(); -// if (!table->shortlisting) - table->status_file->proc_fops = &account_file_ops; -// else -// table->status_file->proc_fops = &account_file_ops_short; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left.\n"); - /* everything went just okey */ - return 1; - - /* do cleanup in case of failure */ -failure_unlink: - /* remove table from list */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() removing table.\n"); - spin_lock_bh(&account_lock); - last_table = NULL; - table = account_tables; - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() no table found. Leaving.\n"); - spin_unlock_bh(&account_lock); - return 0; /* was -ENOMEM */ - } - while (strncmp(info->name, table->name, IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next)); - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table already destroyed. Leaving.\n"); - spin_unlock_bh(&account_lock); - return 0; /* was -ENOMEM */ - } - if (last_table) - last_table->next = table->next; - else - account_tables = table->next; - spin_unlock_bh(&account_lock); -failure_ip_list: - /* free memory allocated for statistics table */ - if (!table->shortlisting) - vfree(table->ip_list.l); - else - vfree(table->ip_list.s); -failure_table: - /* free table */ - vfree(table); -failure: - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left. Table not created.\n"); - /* failure return */ - return ret; -} - -static void destroy(void *matchinfo, - unsigned int matchinfosize) -{ - const struct t_ipt_account_info *info = matchinfo; - struct t_ipt_account_table *table, *last_table; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() entered.\n"); - - if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return; - - /* search for table */ - spin_lock_bh(&account_lock); - last_table = NULL; - table = account_tables; - if(table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no tables found. Leaving.\n"); - spin_unlock_bh(&account_lock); - return; - } - while( strncmp(info->name,table->name,IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next) ); - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no table %s not found. Leaving.\n", info->name); - spin_unlock_bh(&account_lock); - return; - } - - /* decrement table use-count */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() decrementing use count.\n"); - table->use_count--; - if (table->use_count) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table still in use. Leaving.\n"); - spin_unlock_bh(&account_lock); - return; - } - - /* remove table if use-count is zero */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table %s not used. Removing.\n", table->name); - - /* unlink table */ - if(last_table) - last_table->next = table->next; - else - account_tables = table->next; - spin_unlock_bh(&account_lock); - - /* wait while table is still in use */ - spin_lock_bh(&table->ip_list_lock); - spin_unlock_bh(&table->ip_list_lock); - - /* remove proc entries */ - remove_proc_entry(table->name, proc_net_ipt_account); - - /* remove table */ - if (!table->shortlisting) - vfree(table->ip_list.l); - else - vfree(table->ip_list.s); - vfree(table); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() left.\n"); - return; -} - -static struct ipt_match account_match = { - .name = "account", - .match = &match, - .checkentry = &checkentry, - .destroy = &destroy, - .me = THIS_MODULE -}; - -static int __init init(void) -{ - int err; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() entered.\n"); - printk(version); - /* check params */ - if (netmask > 32 || netmask < 0) { - printk(KERN_INFO "account: Wrong netmask given by netmask parameter (%i). Valid is 32 to 0.\n", netmask); - err = -EINVAL; - goto doexit; - } - - /* create /proc/net/ipt_account directory */ - proc_net_ipt_account = proc_mkdir("ipt_account", proc_net); - if (!proc_net_ipt_account) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to create procfs entry.\n"); - err = -ENOMEM; - goto doexit; - } - proc_net_ipt_account->owner = THIS_MODULE; - - err = ipt_register_match(&account_match); - if (err) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to register match.\n"); - remove_proc_entry("ipt_account", proc_net); - } -doexit: - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() left.\n"); - return err; -} - -static void __exit fini(void) -{ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() entered.\n"); - - ipt_unregister_match(&account_match); - /* remove /proc/net/ipt_account/ directory */ - remove_proc_entry("ipt_account", proc_net); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() left.\n"); -} - -module_init(init); -module_exit(fini); - +/* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasidlo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPT_ACCOUNT_VERSION "0.1.20" + +// #define DEBUG_IPT_ACCOUNT + +MODULE_AUTHOR("Piotr Gasidlo "); +MODULE_DESCRIPTION("Traffic accounting module"); +MODULE_LICENSE("GPL"); + +#include +#include + +/* defaults, can be overriden */ +static unsigned int netmask = 16; /* Safe netmask, if you try to create table + for larger netblock you will get error. + Increase by command line only when you + known what are you doing. */ + +#ifdef DEBUG_IPT_ACCOUNT +static int debug = 0; +#endif + +MODULE_PARM(netmask, "i"); +MODULE_PARM_DESC(netmask,"maximum *save* netmask"); +#ifdef DEBUG_IPT_ACCOUNT +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug,"enable debugging output"); +#endif + +/* structure with statistics counter, used when table is created without --ashort switch */ +struct t_ipt_account_stat_long { + u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; + u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; +}; + +/* same as above, for tables created with --ashort switch */ +struct t_ipt_account_stat_short { + u_int64_t b_all; + u_int64_t p_all; +}; + +/* structure holding to/from statistics for single ip when table is created without --ashort switch */ +struct t_ipt_account_stats_long { + struct t_ipt_account_stat_long src, dst; + struct timespec time; /* time, when statistics was last modified */ +}; + +/* same as above, for tables created with --ashort switch */ +struct t_ipt_account_stats_short { + struct t_ipt_account_stat_short src, dst; + struct timespec time; +}; + +/* structure describing single table */ +struct t_ipt_account_table { + struct list_head list; + atomic_t use; /* use counter, the number of rules which points to this table */ + + char name[IPT_ACCOUNT_NAME_LEN + 1]; /* table name ( = filename in /proc/net/ipt_account/) */ + u_int32_t network, netmask, count; /* network/netmask/hosts count coverted by table */ + + int shortlisting:1; /* gather only total statistics (set for tables created with --ashort switch) */ + int timesrc:1; /* update time when accounting outgoing traffic */ + int timedst:1; /* update time when accounting incomming traffic */ + + union { /* statistics for each ip in network/netmask */ + struct t_ipt_account_stats_long *l; + struct t_ipt_account_stats_short *s; + } stats; + rwlock_t stats_lock; /* lock, to assure that above union can be safely modified */ + + struct proc_dir_entry *pde; /* handle to proc entry */ +}; + +static LIST_HEAD(ipt_account_tables); +static rwlock_t ipt_account_lock = RW_LOCK_UNLOCKED; /* lock, to assure that table list can be safely modified */ +static DECLARE_MUTEX(ipt_account_mutex); /* additional checkentry protection */ + +static struct file_operations ipt_account_proc_fops; +static struct proc_dir_entry *ipt_account_procdir; + +/* + * Function creates new table and inserts it into linked list. + */ +static struct t_ipt_account_table * +ipt_account_table_init(struct t_ipt_account_info *info) +{ + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_init]: name = %s\n", info->name); +#endif + + /* + * Allocate memory for table. + */ + table = vmalloc(sizeof(struct t_ipt_account_table)); + if (!table) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table = vmalloc(sizeof(struct t_ipt_account_table)) failed.\n"); + goto cleanup_none; + } + memset(table, 0, sizeof(struct t_ipt_account_table)); + + /* + * Table attributes. + */ + strncpy(table->name, info->name, IPT_ACCOUNT_NAME_LEN); + table->name[IPT_ACCOUNT_NAME_LEN] = '\0'; + + table->network = info->network; + table->netmask = info->netmask; + table->count = (0xffffffff ^ table->netmask) + 1; + + /* + * Table properties. + */ + table->shortlisting = info->shortlisting; + table->timesrc = 1; + table->timedst = 1; + + /* + * Initialize use counter. + */ + atomic_set(&table->use, 1); + + /* + * Allocate memory for statistic counters. + */ + if (table->shortlisting) { + table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count); + if (!table->stats.s) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count) failed.\n"); + goto cleanup_table; + } + memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count); + } else { + table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count); + if (!table->stats.l) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count) failed.\n"); + goto cleanup_table; + } + memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count); + } + + /* + * Reset locks. + */ + table->stats_lock = RW_LOCK_UNLOCKED; + + /* + * Create /proc/ipt_account/name entry. + */ + table->pde = create_proc_entry(table->name, S_IWUSR | S_IRUSR, ipt_account_procdir); + if (!table->pde) { + goto cleanup_stats; + } + table->pde->proc_fops = &ipt_account_proc_fops; + table->pde->data = table; + + /* + * Insert table into list. + */ + write_lock_bh(&ipt_account_lock); + list_add(&table->list, &ipt_account_tables); + write_unlock_bh(&ipt_account_lock); + + return table; + + /* + * If something goes wrong we end here. + */ +cleanup_stats: + if (table->shortlisting) + vfree(table->stats.s); + else + vfree(table->stats.l); + +cleanup_table: + vfree(table); +cleanup_none: + return NULL; + +} + +/* + * Function destroys table. Table *must* be already unlinked. + */ +static void +ipt_account_table_destroy(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_destory]: name = %s\n", table->name); +#endif + remove_proc_entry(table->pde->name, table->pde->parent); + if (table->shortlisting) + vfree(table->stats.s); + else + vfree(table->stats.l); + vfree(table); +} + +/* + * Function increments use counter for table. + */ +static inline void +ipt_account_table_get(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_get]: name = %s\n", table->name); +#endif + atomic_inc(&table->use); +} + +/* + * Function decrements use counter for table. If use counter drops to zero, + * table is removed from linked list and destroyed. + */ +static inline void +ipt_account_table_put(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_put]: name = %s\n", table->name); +#endif + if (atomic_dec_and_test(&table->use)) { + write_lock_bh(&ipt_account_lock); + list_del(&table->list); + write_unlock_bh(&ipt_account_lock); + ipt_account_table_destroy(table); + } +} + +/* + * Helper function, which returns a structure pointer to a table with + * specified name. + */ +static struct t_ipt_account_table * +__ipt_account_table_find(char *name) +{ + struct list_head *pos; + list_for_each(pos, &ipt_account_tables) { + struct t_ipt_account_table *table = list_entry(pos, + struct t_ipt_account_table, list); + if (!strncmp(table->name, name, IPT_ACCOUNT_NAME_LEN)) + return table; + } + return NULL; +} + +/* + * Function, which returns a structure pointer to a table with + * specified name. When such table is found its use coutner + * is incremented. + */ +static inline struct t_ipt_account_table * +ipt_account_table_find_get(char *name) +{ + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_find_get]: name = %s\n", name); +#endif + read_lock_bh(&ipt_account_lock); + table = __ipt_account_table_find(name); + if (!table) { + read_unlock_bh(&ipt_account_lock); + return NULL; + } + atomic_inc(&table->use); + read_unlock_bh(&ipt_account_lock); + return table; +} + +/* + * Helper function, with updates statistics for specified IP. It's only + * used for tables created without --ashort switch. + */ +static inline void +__account_long(struct t_ipt_account_stat_long *stat, const struct sk_buff *skb) +{ + stat->b_all += skb->len; + stat->p_all++; + + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + stat->b_tcp += skb->len; + stat->p_tcp++; + break; + case IPPROTO_UDP: + stat->b_udp += skb->len; + stat->p_udp++; + break; + case IPPROTO_ICMP: + stat->b_icmp += skb->len; + stat->p_icmp++; + break; + default: + stat->b_other += skb->len; + stat->p_other++; + } +} + +/* + * Same as above, but used for tables created with --ashort switch. + */ +static inline void +__account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) +{ + stat->b_all += skb->len; + stat->p_all++; +} + +/* + * Match function. Here we do accounting stuff. + */ +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct t_ipt_account_info *info = (struct t_ipt_account_info *)matchinfo; + struct t_ipt_account_table *table = info->table; + u_int32_t address; + /* Get current time. */ + struct timespec now; + jiffies_to_timespec(jiffies, &now); + /* Default we assume no match. */ + int ret = 0; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [match]: name = %s\n", table->name); +#endif + /* Check whether traffic from source ip address ... */ + address = ntohl(skb->nh.iph->saddr); + /* ... is being accounted by this table. */ + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + write_lock_bh(&table->stats_lock); + /* Yes, account this packet. */ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); +#endif + /* Update counters this host. */ + if (!table->shortlisting) { + __account_long(&table->stats.l[address - table->network].src, skb); + if (table->timesrc) + table->stats.l[address - table->network].time = now; + /* Update also counters for all hosts in this table (network address) */ + if (table->count > 1) { + __account_long(&table->stats.l[0].src, skb); + table->stats.l[0].time = now; + } + } else { + __account_short(&table->stats.s[address - table->network].src, skb); + if (table->timedst) + table->stats.s[address - table->network].time = now; + if (table->count > 1) { + __account_short(&table->stats.s[0].src, skb); + table->stats.s[0].time = now; + } + } + write_unlock_bh(&table->stats_lock); + /* Yes, it's a match. */ + ret = 1; + } + + /* Do the same thing with destination ip address. */ + address = ntohl(skb->nh.iph->daddr); + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + write_lock_bh(&table->stats_lock); +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); +#endif + if (!table->shortlisting) { + __account_long(&table->stats.l[address - table->network].dst, skb); + table->stats.l[address - table->network].time = now; + if (table->count > 1) { + __account_long(&table->stats.l[0].dst, skb); + table->stats.l[0].time = now; + } + } else { + __account_short(&table->stats.s[address - table->network].dst, skb); + table->stats.s[address - table->network].time = now; + if (table->count > 1) { + __account_short(&table->stats.s[0].dst, skb); + table->stats.s[0].time = now; + } + } + write_unlock_bh(&table->stats_lock); + ret = 1; + } + + return ret; +} + +/* + * Checkentry function. + */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ipt_ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct t_ipt_account_info *info = matchinfo; + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: name = %s\n", info->name); +#endif + if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) + return 0; + + /* + * Sanity checks. + */ + if (info->netmask < ((~0L << (32 - netmask)) & 0xffffffff)) { + printk(KERN_ERR "ipt_account[checkentry]: too big netmask (increase module 'netmask' parameter).\n"); + return 0; + } + if ((info->network & info->netmask) != info->network) { + printk(KERN_ERR "ipt_account[checkentry]: wrong network/netmask.\n"); + return 0; + } + if (info->name[0] == '\0') { + printk(KERN_ERR "ipt_account[checkentry]: wrong table name.\n"); + return 0; + } + + /* + * We got new rule. Try to find table with the same name as given in info structure. + * Mutex magic based on ipt_hashlimit.c. + */ + down(&ipt_account_mutex); + table = ipt_account_table_find_get(info->name); + if (table) { + if (info->table != NULL) { + if (info->table != table) { + /* + * Shouldn't happen. + */ + printk(KERN_ERR "ipt_account[checkentry]: reloaded rule has invalid table pointer.\n"); + up(&ipt_account_mutex); + return 0; + } + up(&ipt_account_mutex); + return 1; + } else { +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, checking.\n"); +#endif + /* + * Table exists, but whether rule network/netmask/shortlisting matches + * table network/netmask/shortlisting. Failure on missmatch. + */ + if (table->network != info->network || table->netmask != info->netmask || table->shortlisting != info->shortlisting) { + printk(KERN_ERR "ipt_account [checkentry]: table found, rule network/netmask/shortlisting not match table network/netmask/shortlisting.\n"); + /* + * Remember to release table usage counter. + */ + ipt_account_table_put(table); + up(&ipt_account_mutex); + return 0; + } +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, reusing.\n"); +#endif + /* + * Link rule with table. + */ + info->table = table; + } + } else { +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table not found, creating new one.\n"); +#endif + /* + * Table not exist, create new one. + */ + info->table = table = ipt_account_table_init(info); + if (!table) { + up(&ipt_account_mutex); + return 0; + } + } + up(&ipt_account_mutex); + return 1; +} + +/* + * Destroy function. + */ +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct t_ipt_account_info *info = matchinfo; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [destroy]: name = %s\n", info->name); +#endif + /* + * Release table, by decreasing its usage counter. When + * counter hits zero, memory used by table structure is + * released and table is removed from list. + */ + ipt_account_table_put(info->table); + return; +} + +static struct ipt_match account_match = { + .name = "account", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + +/* + * Below functions (ipt_account_seq_start, ipt_account_seq_next, + * ipt_account_seq_stop, ipt_account_seq_show, ipt_account_proc_write) + * are used to implement proc stuff. + */ +static void *ipt_account_seq_start(struct seq_file *sf, loff_t *pos) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i; + + read_lock_bh(&table->stats_lock); + if (*pos >= table->count) + return NULL; + i = kmalloc(sizeof(unsigned int), GFP_ATOMIC); + if (!i) + return ERR_PTR(-ENOMEM); + *i = *pos; + return i; +} + +static void *ipt_account_seq_next(struct seq_file *sf, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i = (unsigned int *)v; + + *pos = ++(*i); + if (*i >= table->count) { + kfree(v); + return NULL; + } + return i; +} + +static void ipt_account_seq_stop(struct seq_file *sf, void *v) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + kfree(v); + read_unlock_bh(&table->stats_lock); +} + +static int ipt_account_seq_show(struct seq_file *sf, void *v) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i = (unsigned int *)v; + + struct timespec now; + jiffies_to_timespec(jiffies, &now); + + u_int32_t address = table->network + *i; + + if (!table->shortlisting) { + struct t_ipt_account_stats_long *l = &table->stats.l[*i]; + seq_printf(sf, + "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu\n", + HIPQUAD(address), + l->src.b_all, + l->src.b_tcp, + l->src.b_udp, + l->src.b_icmp, + l->src.b_other, + l->src.p_all, + l->src.p_tcp, + l->src.p_udp, + l->src.p_icmp, + l->src.p_other, + l->dst.b_all, + l->dst.b_tcp, + l->dst.b_udp, + l->dst.b_icmp, + l->dst.b_other, + l->dst.p_all, + l->dst.p_tcp, + l->dst.p_udp, + l->dst.p_icmp, + l->dst.p_other, + now.tv_sec - l->time.tv_sec + ); + } else { + struct t_ipt_account_stats_short *s = &table->stats.s[*i]; + seq_printf(sf, + "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n", + HIPQUAD(address), + s->src.b_all, + s->src.p_all, + s->dst.b_all, + s->dst.p_all, + now.tv_sec - s->time.tv_sec + ); + } + + return 0; +} + +static struct seq_operations ipt_account_seq_ops = { + .start = ipt_account_seq_start, + .next = ipt_account_seq_next, + .stop = ipt_account_seq_stop, + .show = ipt_account_seq_show +}; + +static ssize_t ipt_account_proc_write(struct file *file, const char __user *input, size_t size, loff_t *ofs) +{ + char buffer[1024]; + struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); + struct t_ipt_account_table *table = pde->data; + + u_int32_t o[4], ip; + struct t_ipt_account_stats_long l; + struct t_ipt_account_stats_short s; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_proc_write]: name = %s.\n", table->name); +#endif + if (copy_from_user(buffer, input, 1024)) + return -EFAULT; + buffer[1023] = '\0'; + + if (!strncmp(buffer, "reset\n", 6)) { + /* + * User requested to clear all table. Ignorant, does + * he known how match time it took us to fill it? ;-) + */ + write_lock_bh(&table->stats_lock); + if (table->shortlisting) + memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count); + else + memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count); + write_unlock_bh(&table->stats_lock); + } else if (!strncmp(buffer, "time=any\n", 9)) { + table->timesrc = table->timedst = 1; + } else if (!strncmp(buffer, "time=src\n", 9)) { + table->timesrc = 1; + table->timedst = 0; + } else if (!strncmp(buffer, "time=dst\n", 9)) { + table->timesrc = 0; + table->timedst = 1; + } else if (!table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu", + &o[0], &o[1], &o[2], &o[3], + &l.src.b_all, &l.src.b_tcp, &l.src.b_udp, &l.src.b_icmp, &l.src.b_other, + &l.src.p_all, &l.src.p_tcp, &l.src.p_udp, &l.src.p_icmp, &l.src.p_other, + &l.dst.b_all, &l.dst.b_tcp, &l.dst.b_udp, &l.dst.b_icmp, &l.dst.b_other, + &l.dst.p_all, &l.dst.p_tcp, &l.dst.p_udp, &l.dst.p_icmp, &l.dst.p_other, + &l.time.tv_sec) == 25) { + /* + * We got line formated like long listing row. We have to + * check, if IP is accounted by table. If so, we + * simply replace row with user's one. + */ + ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3]; + if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) { + /* + * Ignore user input time. Set current time. + */ + jiffies_to_timespec(jiffies, &l.time); + write_lock_bh(&table->stats_lock); + table->stats.l[ip - table->network] = l; + write_unlock_bh(&table->stats_lock); + } + } else if (table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n", + &o[0], &o[1], &o[2], &o[3], + &s.src.b_all, + &s.src.p_all, + &s.dst.b_all, + &s.dst.p_all, + &s.time.tv_sec) == 9) { + /* + * We got line formated like short listing row. Do the + * same action like above. + */ + ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3]; + if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) { + jiffies_to_timespec(jiffies, &s.time); + write_lock_bh(&table->stats_lock); + table->stats.s[ip - table->network] = s; + write_unlock_bh(&table->stats_lock); + } + } else { + /* + * We don't understand what user have just wrote. + */ + return -EIO; + } + + return size; +} + +static int ipt_account_proc_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &ipt_account_seq_ops); + if (!ret) { + struct seq_file *sf = file->private_data; + struct proc_dir_entry *pde = PDE(inode); + struct t_ipt_account_table *table = pde->data; + + sf->private = pde; + + ipt_account_table_get(table); + } + return ret; +} + +static int ipt_account_proc_release(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *pde = PDE(inode); + struct t_ipt_account_table *table = pde->data; + int ret; + + ret = seq_release(inode, file); + + if (!ret) + ipt_account_table_put(table); + + return ret; +} + +static struct file_operations ipt_account_proc_fops = { + .owner = THIS_MODULE, + .open = ipt_account_proc_open, + .read = seq_read, + .write = ipt_account_proc_write, + .llseek = seq_lseek, + .release = ipt_account_proc_release +}; + +/* + * Module init function. + */ +static int __init init(void) +{ + int ret = 0; + + printk(KERN_INFO "ipt_account %s : Piotr Gasidlo , http://www.barbara.eu.org/~quaker/ipt_account/\n", IPT_ACCOUNT_VERSION); + + /* Check module parameters. */ + if (netmask > 32 || netmask < 0) { + printk(KERN_ERR "ipt_account[__init]: Wrong netmask given as parameter (%i). Valid is 32 to 0.\n", netmask); + ret = -EINVAL; + goto cleanup_none; + } + + /* Register match. */ + if (ipt_register_match(&account_match)) { + ret = -EINVAL; + goto cleanup_none; + } + + /* Create /proc/net/ipt_account/ entry. */ + ipt_account_procdir = proc_mkdir("ipt_account", proc_net); + if (!ipt_account_procdir) { + printk(KERN_ERR "ipt_account [__init]: ipt_account_procdir = proc_mkdir(\"ipt_account\", proc_net) failed.\n"); + ret = -ENOMEM; + goto cleanup_match; + } + + return ret; + + /* If something goes wrong we end here. */ +cleanup_match: + ipt_unregister_match(&account_match); +cleanup_none: + return ret; +} + +/* + * Module exit function. + */ +static void __exit fini(void) +{ + /* Remove /proc/net/ipt_account/ */ + remove_proc_entry(ipt_account_procdir->name, ipt_account_procdir->parent); + ipt_unregister_match(&account_match); +} + +module_init(init); +module_exit(fini); + diff --git a/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c b/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c index acdb77992b..66f0e177f9 100644 --- a/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c +++ b/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c @@ -226,6 +226,9 @@ ctl_table ipv4_table[] = { &sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_ICMP_RATEMASK, "icmp_ratemask", &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_IPFRAG_SECRET_INTERVAL, "ipfrag_secret_interval", + &sysctl_ipfrag_secret_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, + &sysctl_jiffies}, {NET_TCP_TW_REUSE, "tcp_tw_reuse", &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_FRTO, "tcp_frto", diff --git a/release/src/linux/linux/net/sched/police.c b/release/src/linux/linux/net/sched/police.c index 78fb8c55b4..13badfa7d1 100644 --- a/release/src/linux/linux/net/sched/police.c +++ b/release/src/linux/linux/net/sched/police.c @@ -31,8 +31,8 @@ #include #include -#define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) -#define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) +#define L2T(p,L) qdisc_l2t((p)->R_tab,L) +#define L2T_P(p,L) qdisc_l2t((p)->P_tab,L) static u32 idx_gen; static struct tcf_police *tcf_police_ht[16]; diff --git a/release/src/linux/linux/net/sched/sch_cbq.c b/release/src/linux/linux/net/sched/sch_cbq.c index dda9232ba7..66a0e86588 100644 --- a/release/src/linux/linux/net/sched/sch_cbq.c +++ b/release/src/linux/linux/net/sched/sch_cbq.c @@ -190,7 +190,7 @@ struct cbq_sched_data }; -#define L2T(cl,len) ((cl)->R_tab->data[(len)>>(cl)->R_tab->rate.cell_log]) +#define L2T(cl,len) qdisc_l2t((cl)->R_tab,len) static __inline__ unsigned cbq_hash(u32 h) diff --git a/release/src/linux/linux/net/sched/sch_htb.c b/release/src/linux/linux/net/sched/sch_htb.c index c6bbd9476a..d63e938627 100644 --- a/release/src/linux/linux/net/sched/sch_htb.c +++ b/release/src/linux/linux/net/sched/sch_htb.c @@ -74,7 +74,7 @@ #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */ //#define HTB_DEBUG 1 /* compile debugging support (activated by tc tool) */ #define HTB_RATECM 1 /* whether to use rate computer */ -#define HTB_HYSTERESIS 0/* whether to use mode hysteresis for speedup */ +//#define HTB_HYSTERESIS 0/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ @@ -205,12 +205,10 @@ struct htb_class static __inline__ long L2T(struct htb_class *cl,struct qdisc_rate_table *rate, int size) { - int slot = size >> rate->rate.cell_log; - if (slot > 255) { - cl->xstats.giants++; - slot = 255; - } - return rate->data[slot]; + long result = qdisc_l2t(rate, size); + if (result > rate->data[255]) + cl->xstats.giants++; + return result; } struct htb_sched diff --git a/release/src/linux/linux/net/sched/sch_tbf.c b/release/src/linux/linux/net/sched/sch_tbf.c index ef3df913de..fe950eb176 100644 --- a/release/src/linux/linux/net/sched/sch_tbf.c +++ b/release/src/linux/linux/net/sched/sch_tbf.c @@ -132,8 +132,8 @@ struct tbf_sched_data struct Qdisc *qdisc; /* Inner qdisc, default - bfifo queue */ }; -#define L2T(q,L) ((q)->R_tab->data[(L)>>(q)->R_tab->rate.cell_log]) -#define L2T_P(q,L) ((q)->P_tab->data[(L)>>(q)->P_tab->rate.cell_log]) +#define L2T(q,L) qdisc_l2t((q)->R_tab,L) +#define L2T_P(q,L) qdisc_l2t((q)->P_tab,L) static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) { diff --git a/release/src/router/busybox/.gitignore b/release/src/router/busybox/.gitignore index 7d2cca67c5..0a0c65bc3e 100644 --- a/release/src/router/busybox/.gitignore +++ b/release/src/router/busybox/.gitignore @@ -18,6 +18,7 @@ Config.in # Normal output # /busybox +/busybox_old /busybox_unstripped* # diff --git a/release/src/router/busybox/Config.in b/release/src/router/busybox/Config.in index f74330b9da..17bdc895ac 100644 --- a/release/src/router/busybox/Config.in +++ b/release/src/router/busybox/Config.in @@ -83,20 +83,21 @@ config FEATURE_BUFFERS_GO_IN_BSS endchoice config SHOW_USAGE - bool "Show terse applet usage messages" + bool "Show 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. + Enabling this option, BusyBox applets will show terse help messages + when invoked with wrong arguments. + If you do not want to show any (helpful) usage message when + issuing wrong command syntax, you can say 'N' here, + saving approximately 7k. config FEATURE_VERBOSE_USAGE bool "Show verbose applet usage messages" default y depends on SHOW_USAGE help - All BusyBox applets will show more verbose help messages when + All BusyBox applets will show 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. @@ -106,8 +107,8 @@ config FEATURE_COMPRESS_USAGE default y depends on SHOW_USAGE help - Store usage messages in compressed form, uncompress them on-the-fly - when --help is called. + Store usage messages in .bz compressed form, uncompress them + on-the-fly when --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 @@ -248,8 +249,9 @@ config UNICODE_PRESERVE_BROKEN default n depends on UNICODE_SUPPORT help - With this option on, invalid UTF-8 bytes are not substituted - with the selected substitution character. + With this option on, on line-editing input (such as used by shells) + invalid UTF-8 bytes are not substituted with the selected + substitution character. For example, this means that entering 'l', 's', ' ', 0xff, [Enter] at shell prompt will list file named 0xff (single char name with char value 255), not file named '?'. @@ -283,10 +285,19 @@ config FEATURE_CLEAN_UP Don't enable this unless you have a really good reason to clean things up manually. +config FEATURE_UTMP + bool "Support utmp file" + default y + help + The file /var/run/utmp is used to track who is currently logged in. + With this option on, certain applets (getty, login, telnetd etc) + will create and delete entries there. + "who" applet requires this option. + config FEATURE_WTMP bool "Support wtmp file" default y - select FEATURE_UTMP + depends on FEATURE_UTMP help The file /var/run/wtmp is used to track when users have logged into and logged out of the system. @@ -294,15 +305,6 @@ config FEATURE_WTMP will append new entries there. "last" applet requires this option. -config FEATURE_UTMP - bool "Support utmp file" - default y - help - The file /var/run/utmp is used to track who is currently logged in. - With this option on, certain applets (getty, login, telnetd etc) - will create and delete entries there. - "who" applet requires this option. - config FEATURE_PIDFILE bool "Support writing pidfiles" default y @@ -327,21 +329,39 @@ config FEATURE_SUID 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: + The applets which require root rights (need suid bit or + to be run by root) and will refuse to execute otherwise: + crontab, login, passwd, su, vlock, wall. + + The applets which will use root rights if they have them + (via suid bit, or because run by root), but would try to work + without root right nevertheless: + findfs, ping[6], traceroute[6], mount. - crontab, dnsd, findfs, ipcrm, ipcs, login, passwd, ping, su, - traceroute, vlock. + Note that if you DONT select this option, but DO make busybox + suid root, ALL applets will run under root, which is a huge + security hole (think "cp /some/file /etc/passwd"). config FEATURE_SUID_CONFIG bool "Runtime SUID/SGID configuration via /etc/busybox.conf" - default y if FEATURE_SUID + default y 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: - = [Ssx-][Ssx-][x-] (|).(|) + APPLET = [Ssx-][Ssx-][x-] [USER.GROUP] + + s: USER or GROUP is allowed to execute APPLET. + APPLET will run under USER or GROUP + (reagardless of who's running it). + S: USER or GROUP is NOT allowed to execute APPLET. + APPLET will run under USER or GROUP. + This option is not very sensical. + x: USER/GROUP/others are allowed to execute APPLET. + No UID/GID change will be done when it is run. + -: USER/GROUP/others are not allowed to execute APPLET. An example might help: @@ -351,7 +371,8 @@ config FEATURE_SUID_CONFIG 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 + # of group disk (but not anyone else) + # and runs with euid=0 (egid is not changed) cp = --- # disable applet cp for everyone @@ -377,7 +398,7 @@ config FEATURE_SUID_CONFIG_QUIET config SELINUX bool "Support NSA Security Enhanced Linux" default n - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Enable support for SELinux in applets ls, ps, and id. Also provide the option of compiling in SELinux applets. @@ -458,7 +479,10 @@ config PIE default n depends on !STATIC help - (TODO: what is it and why/when is it useful?) + Hardened code option. PIE binaries are loaded at a different + address at each invocation. This has some overhead, + particularly on x86-32 which is short on registers. + Most people will leave this set to 'N'. config NOMMU @@ -555,7 +579,6 @@ config FEATURE_SHARED_BUSYBOX config LFS bool "Build with Large File Support (for accessing files > 2 GB)" default y - 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 @@ -577,12 +600,39 @@ config CROSS_COMPILER_PREFIX Native builds leave this empty. +config SYSROOT + string "Path to sysroot" + default "" + help + If you want to build BusyBox with a cross compiler, then you + might also need to specify where /usr/include and /usr/lib + will be found. + + For example, BusyBox can be built against an installed + Android NDK, platform version 9, for ARM ABI with + + CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm + + Native builds leave this empty. + config EXTRA_CFLAGS string "Additional CFLAGS" default "" help Additional CFLAGS to pass to the compiler verbatim. +config EXTRA_LDFLAGS + string "Additional LDFLAGS" + default "" + help + Additional LDFLAGS to pass to the linker verbatim. + +config EXTRA_LDLIBS + string "Additional LDLIBS" + default "" + help + Additional LDLIBS to pass to the linker with -l. + endmenu menu 'Debugging Options' @@ -659,9 +709,6 @@ config EFENCE endchoice -### config PARSE -### bool "Uniform config file parser debugging applet: parse" - endmenu menu 'Installation Options ("make install" behavior)' @@ -692,7 +739,6 @@ config INSTALL_APPLET_SCRIPT_WRAPPERS 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 you plan to use busybox --install for installing links, or plan to use @@ -747,7 +793,7 @@ source editors/Config.in source findutils/Config.in source init/Config.in source loginutils/Config.in -source e2fsprogs/old_e2fsprogs/Config.in +source e2fsprogs/Config.in source modutils/Config.in source util-linux/Config.in source miscutils/Config.in diff --git a/release/src/router/busybox/INSTALL b/release/src/router/busybox/INSTALL index ec2b028fdb..750cfc45bf 100644 --- a/release/src/router/busybox/INSTALL +++ b/release/src/router/busybox/INSTALL @@ -47,8 +47,11 @@ 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 +available. If you do not have /proc, then point that config option to the location of your busybox binary, usually /bin/busybox. +Another solution is to patch the kernel (see +examples/linux-*_proc_self_exe.patch) to make exec("/proc/self/exe") +always work. Configuring Busybox: ==================== @@ -70,7 +73,9 @@ 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). +and "make randconfig" (produce a random configuration). The configs/ directory +contains a number of additional configuration files ending in _defconfig which +are useful in specific cases. "make help" will list them. 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 @@ -97,7 +102,7 @@ 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, +also configure a standalone 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). diff --git a/release/src/router/busybox/Makefile b/release/src/router/busybox/Makefile index a10bd5a3d2..8d5ea165f3 100644 --- a/release/src/router/busybox/Makefile +++ b/release/src/router/busybox/Makefile @@ -1,6 +1,6 @@ VERSION = 1 -PATCHLEVEL = 18 -SUBLEVEL = 5 +PATCHLEVEL = 20 +SUBLEVEL = 2 EXTRAVERSION = NAME = Unnamed @@ -469,9 +469,9 @@ libs-y := \ coreutils/ \ coreutils/libcoreutils/ \ debianutils/ \ - e2fsprogs/old_e2fsprogs/ \ - e2fsprogs/old_e2fsprogs/e2p/ \ - e2fsprogs/old_e2fsprogs/ext2fs/ \ + e2fsprogs/ \ + e2fsprogs/e2p/ \ + e2fsprogs/ext2fs/ \ editors/ \ findutils/ \ init/ \ @@ -965,10 +965,14 @@ CLEAN_FILES += busybox busybox_unstripped* busybox.links \ # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 MRPROPER_FILES += .config .config.old include/asm .version .old_version \ + include/NUM_APPLETS.h \ include/autoconf.h \ include/bbconfigopts.h \ + include/bbconfigopts_bz2.h \ include/usage_compressed.h \ include/applet_tables.h \ + include/applets.h \ + include/usage.h \ applets/usage \ .kernelrelease Module.symvers tags TAGS cscope* \ busybox_old @@ -1010,8 +1014,8 @@ $(mrproper-dirs): mrproper: clean archmrproper $(mrproper-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) - @find -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f - @find -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f + @find . -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f + @find . -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f # distclean # @@ -1040,7 +1044,7 @@ rpm: FORCE # Brief documentation of the typical targets used # --------------------------------------------------------------------------- -boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig) +boards := $(wildcard $(srctree)/configs/*_defconfig) boards := $(notdir $(boards)) -include $(srctree)/Makefile.help @@ -1129,15 +1133,6 @@ clean: $(clean-dirs) -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: ; diff --git a/release/src/router/busybox/Makefile.flags b/release/src/router/busybox/Makefile.flags index 37af9b0dea..e2ce6291e5 100644 --- a/release/src/router/busybox/Makefile.flags +++ b/release/src/router/busybox/Makefile.flags @@ -58,14 +58,14 @@ CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 #CFLAGS += $(call cc-option,-Wconversion,) ifneq ($(CONFIG_DEBUG),y) -CFLAGS += $(call cc-option,-Os,) +CFLAGS += $(call cc-option,-Os,$(call cc-option,-O2,)) else CFLAGS += $(call cc-option,-g,) #CFLAGS += "-D_FORTIFY_SOURCE=2" ifeq ($(CONFIG_DEBUG_PESSIMIZE),y) CFLAGS += $(call cc-option,-O0,) else -CFLAGS += $(call cc-option,-Os,) +CFLAGS += $(call cc-option,-Os,$(call cc-option,-O2,)) endif endif @@ -97,10 +97,33 @@ CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS))) #")) endif +# Note: both "" (string consisting of two quote chars) and empty string +# are possible, and should be skipped below. +ifneq ($(subst "",,$(CONFIG_SYSROOT)),) +CFLAGS += --sysroot=$(CONFIG_SYSROOT) +export SYSROOT=$(CONFIG_SYSROOT) +endif + +# Android has no separate crypt library +# gcc-4.2.1 fails if we try to feed C source on stdin: +# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - +# fall back to using a temp file: +CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) +ifeq ($(CRYPT_AVAILABLE),y) LDLIBS += m crypt +else +LDLIBS += m +endif ifeq ($(CONFIG_PAM),y) -LDLIBS += pam pam_misc +# libpam uses libpthread, so for static builds busybox must be linked to +# libpthread. On some platforms that requires an explicit -lpthread, so +# it should be in LDLIBS. For non-static builds, scripts/trylink will +# take care of removing -lpthread if possible. (Not bothering to check +# CONFIG_STATIC because even in a non-static build it could be that the +# only libpam available is libpam.a, so -lpthread could still be +# needed.) +LDLIBS += pam pam_misc pthread endif ifeq ($(CONFIG_SELINUX),y) @@ -125,6 +148,16 @@ ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) SKIP_STRIP = y endif +ifneq ($(CONFIG_EXTRA_LDFLAGS),) +EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) +#")) +endif + +ifneq ($(CONFIG_EXTRA_LDLIBS),) +LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS))) +#")) +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!) diff --git a/release/src/router/busybox/Makefile.help b/release/src/router/busybox/Makefile.help index 999d0298e5..119dd6f89d 100644 --- a/release/src/router/busybox/Makefile.help +++ b/release/src/router/busybox/Makefile.help @@ -25,6 +25,10 @@ help: @echo ' You can use these commands if the commands on the host' @echo ' is unusable. Afterwards use it like:' @echo ' make SED="$(objtree)/sed"' + @$(if $(boards), \ + $(foreach b, $(boards), \ + printf " %-21s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \ + echo '') @echo @echo 'Installation:' @echo ' install - install busybox into CONFIG_PREFIX' diff --git a/release/src/router/busybox/README b/release/src/router/busybox/README index a3a725a5df..b940e357a7 100644 --- a/release/src/router/busybox/README +++ b/release/src/router/busybox/README @@ -44,7 +44,7 @@ Using busybox: 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 + command shell that calls the built-in 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.) @@ -169,7 +169,7 @@ Portability: 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 + these environments, don't be surprised 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. diff --git a/release/src/router/busybox/TODO b/release/src/router/busybox/TODO index 8b9f87f79d..44364690fa 100644 --- a/release/src/router/busybox/TODO +++ b/release/src/router/busybox/TODO @@ -2,6 +2,8 @@ Busybox TODO Harvest patches from http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/ +https://dev.openwrt.org/browser/trunk/package/busybox/patches/ + 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 diff --git a/release/src/router/busybox/applets/.gitignore b/release/src/router/busybox/applets/.gitignore index cc932fcc08..459938d678 100644 --- a/release/src/router/busybox/applets/.gitignore +++ b/release/src/router/busybox/applets/.gitignore @@ -1,2 +1,3 @@ /applet_tables /usage +/usage_pod diff --git a/release/src/router/busybox/applets/Kbuild.src b/release/src/router/busybox/applets/Kbuild.src index 9b9808f25c..b612399489 100644 --- a/release/src/router/busybox/applets/Kbuild.src +++ b/release/src/router/busybox/applets/Kbuild.src @@ -42,3 +42,6 @@ quiet_cmd_gen_applet_tables = GEN include/applet_tables.h include/applet_tables.h: applets/applet_tables $(call cmd,gen_applet_tables) + +include/NUM_APPLETS.h: applets/applet_tables + $(call cmd,gen_applet_tables) diff --git a/release/src/router/busybox/applets/applet_tables.c b/release/src/router/busybox/applets/applet_tables.c index 32dcdb73dc..152d5f4418 100644 --- a/release/src/router/busybox/applets/applet_tables.c +++ b/release/src/router/busybox/applets/applet_tables.c @@ -7,13 +7,19 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ - +#include +#include +#include #include #include #include +#include + +#undef ARRAY_SIZE +#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) #include "../include/autoconf.h" -#include "../include/busybox.h" +#include "../include/applet_metadata.h" struct bb_applet { const char *name; @@ -75,7 +81,7 @@ int main(int argc, char **argv) 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); + printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main); } printf("\n"); diff --git a/release/src/router/busybox/applets/busybox.mkll b/release/src/router/busybox/applets/busybox.mkll index 6d61f7e82d..68dbf21626 100755 --- a/release/src/router/busybox/applets/busybox.mkll +++ b/release/src/router/busybox/applets/busybox.mkll @@ -14,7 +14,7 @@ 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) + dir=substr($2,7) gsub("_","/",dir) if(dir=="/ROOT") dir="" file=$3 diff --git a/release/src/router/busybox/applets/install.sh b/release/src/router/busybox/applets/install.sh index 32049b1579..95b4719d4b 100755 --- a/release/src/router/busybox/applets/install.sh +++ b/release/src/router/busybox/applets/install.sh @@ -3,12 +3,15 @@ export LC_ALL=POSIX export LC_CTYPE=POSIX -prefix=${1} +prefix=$1 if [ -z "$prefix" ]; then echo "usage: applets/install.sh DESTINATION [--symlinks/--hardlinks/--scriptwrapper]" - exit 1; + exit 1 fi + h=`sort busybox.links | uniq` + +linkopts="" scriptwrapper="n" cleanup="0" noclobber="0" @@ -33,12 +36,12 @@ if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then libdir=/lib fi - mkdir -p $prefix/$libdir || exit 1 + 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 + 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 @@ -46,35 +49,35 @@ 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 - ` + 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 +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 + 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 + ln $linkopts busybox "$prefix/$i" || exit 1 else - rm -f $prefix$i - echo "#!/bin/busybox" > $prefix$i - chmod +x $prefix/$i + rm -f "$prefix/$i" + echo "#!/bin/busybox" >"$prefix/$i" + chmod +x "$prefix/$i" fi - echo " $prefix$i" + echo " $prefix/$i" else if [ "$2" = "--hardlinks" ]; then bb_path="$prefix/bin/busybox" @@ -89,20 +92,20 @@ for i in $h; do /sbin) bb_path="../bin/busybox" ;; - /usr/bin|/usr/sbin) + /usr/bin | /usr/sbin) bb_path="../../bin/busybox" ;; *) - echo "Unknown installation directory: $appdir" - exit 1 + 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 + 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" + echo " $prefix/$i already exists" fi fi done diff --git a/release/src/router/busybox/applets/usage_pod.c b/release/src/router/busybox/applets/usage_pod.c index da0baefc6d..0b1c4aadb8 100644 --- a/release/src/router/busybox/applets/usage_pod.c +++ b/release/src/router/busybox/applets/usage_pod.c @@ -31,8 +31,8 @@ #include "usage.h" #define MAKE_USAGE(aname, usage) { aname, usage }, static struct usage_data { - const char *aname; - const char *usage; + const char *aname; + const char *usage; } usage_array[] = { #include "applets.h" }; diff --git a/release/src/router/busybox/applets_sh/README b/release/src/router/busybox/applets_sh/README new file mode 100644 index 0000000000..9dcd38ae38 --- /dev/null +++ b/release/src/router/busybox/applets_sh/README @@ -0,0 +1,5 @@ +This directory contains examples of applets implemented as shell scripts. + +So far these scripts are not hooked to the build system and are not +installed by "make install". If you want to use them, +you need to install them by hand. diff --git a/release/src/router/busybox/applets_sh/dos2unix b/release/src/router/busybox/applets_sh/dos2unix new file mode 100755 index 0000000000..0fd5206f64 --- /dev/null +++ b/release/src/router/busybox/applets_sh/dos2unix @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/\r$//' "$@" diff --git a/release/src/router/busybox/applets_sh/nologin b/release/src/router/busybox/applets_sh/nologin new file mode 100755 index 0000000000..3768eaaa7e --- /dev/null +++ b/release/src/router/busybox/applets_sh/nologin @@ -0,0 +1,4 @@ +#!/bin/sh +cat /etc/nologin.txt 2>/dev/null || echo "This account is not available" +sleep 5 +exit 1 diff --git a/release/src/router/busybox/applets_sh/tac b/release/src/router/busybox/applets_sh/tac new file mode 100755 index 0000000000..c5a8e39c11 --- /dev/null +++ b/release/src/router/busybox/applets_sh/tac @@ -0,0 +1,7 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +for i in "$@" +do +sed -e '1!G;h;$!d' "$i" +done diff --git a/release/src/router/busybox/applets_sh/unix2dos b/release/src/router/busybox/applets_sh/unix2dos new file mode 100755 index 0000000000..70e0429061 --- /dev/null +++ b/release/src/router/busybox/applets_sh/unix2dos @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/$/\r/' "$@" diff --git a/release/src/router/busybox/archival/Config.src b/release/src/router/busybox/archival/Config.src index 81788ecd94..ae1afc5942 100644 --- a/release/src/router/busybox/archival/Config.src +++ b/release/src/router/busybox/archival/Config.src @@ -32,10 +32,10 @@ config FEATURE_SEAMLESS_GZ Make tar, rpm, modprobe etc understand .gz data. config FEATURE_SEAMLESS_Z - bool "Make tar and gunzip understand .Z data" + bool "tar, rpm, modprobe etc understand .Z data" default n help - Make tar and gunzip understand .Z data. + Make tar, rpm, modprobe etc understand .Z data. config AR bool "ar" @@ -187,6 +187,18 @@ config FEATURE_GZIP_LONG_OPTIONS help Enable use of long options, increases size by about 106 Bytes +config GZIP_FAST + int "Trade memory for gzip speed (0:small,slow - 2:fast,big)" + default 0 + range 0 2 + depends on GZIP + help + Enable big memory options for gzip. + 0: small buffers, small hash-tables + 1: larger buffers, larger hash-tables + 2: larger buffers, largest hash-tables + Larger models may give slightly better compression + config LZOP bool "lzop" default y @@ -330,15 +342,12 @@ config UNLZMA is generally considerably better than that achieved by the bzip2 compressors. - The BusyBox unlzma applet is limited to de-compression only. + The BusyBox unlzma applet is limited to decompression 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 y + default n depends on UNLZMA help This option reduces decompression time by about 25% at the cost of diff --git a/release/src/router/busybox/archival/ar.c b/release/src/router/busybox/archival/ar.c index a2e3306ac6..88236e878d 100644 --- a/release/src/router/busybox/archival/ar.c +++ b/release/src/router/busybox/archival/ar.c @@ -17,8 +17,18 @@ * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html */ +//usage:#define ar_trivial_usage +//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES" +//usage:#define ar_full_usage "\n\n" +//usage: "Extract or list FILES from an ar archive\n" +//usage: "\n -o Preserve original dates" +//usage: "\n -p Extract to stdout" +//usage: "\n -t List" +//usage: "\n -x Extract" +//usage: "\n -v Verbose" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "ar.h" #if ENABLE_FEATURE_AR_CREATE @@ -71,7 +81,7 @@ static void output_ar_header(archive_handle_t *handle) } /* - * when replacing files in an existing archive, copy from the the + * when replacing files in an existing archive, copy from the * original archive those files that are to be left intact */ static void FAST_FUNC copy_data(archive_handle_t *handle) diff --git a/release/src/router/busybox/archival/bbunzip.c b/release/src/router/busybox/archival/bbunzip.c index a69e1b3ca8..94d8a81c94 100644 --- a/release/src/router/busybox/archival/bbunzip.c +++ b/release/src/router/busybox/archival/bbunzip.c @@ -5,7 +5,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" enum { OPT_STDOUT = 1 << 0, @@ -33,7 +33,7 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext) } int FAST_FUNC bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), const char *expected_ext ) @@ -42,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv, IF_DESKTOP(long long) int status; char *filename, *new_name; smallint exitcode = 0; - unpack_info_t info; + transformer_aux_data_t aux; do { /* NB: new_name is *maybe* malloc'ed! */ @@ -98,21 +98,23 @@ int FAST_FUNC bbunpack(char **argv, "use -f to force it"); } - /* memset(&info, 0, sizeof(info)); */ - info.mtime = 0; /* so far it has one member only */ - status = unpacker(&info); + init_transformer_aux_data(&aux); + aux.check_signature = 1; + status = unpacker(&aux); if (status < 0) exitcode = 1; - xclose(STDOUT_FILENO); /* with error check! */ + + if (!(option_mask32 & OPT_STDOUT)) + xclose(STDOUT_FILENO); /* with error check! */ if (filename) { char *del = new_name; if (status >= 0) { /* TODO: restore other things? */ - if (info.mtime) { + if (aux.mtime != 0) { struct timeval times[2]; - times[1].tv_sec = times[0].tv_sec = info.mtime; + times[1].tv_sec = times[0].tv_sec = aux.mtime; times[1].tv_usec = times[0].tv_usec = 0; /* Note: we closed it first. * On some systems calling utimes @@ -143,6 +145,9 @@ int FAST_FUNC bbunpack(char **argv, } } while (*argv && *++argv); + if (option_mask32 & OPT_STDOUT) + xclose(STDOUT_FILENO); /* with error check! */ + return exitcode; } @@ -167,18 +172,19 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define uncompress_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define uncompress_full_usage "\n\n" +//usage: "Decompress .Z file[s]\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Overwrite" + #if ENABLE_UNCOMPRESS static -IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux) { - IF_DESKTOP(long long) int status = -1; - - if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) { - bb_error_msg("invalid magic"); - } else { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } - return status; + return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uncompress_main(int argc UNUSED_PARAM, char **argv) @@ -218,6 +224,27 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) * 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. */ + +//usage:#define gunzip_trivial_usage +//usage: "[-cft] [FILE]..." +//usage:#define gunzip_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -t Test file integrity" +//usage: +//usage:#define gunzip_example_usage +//usage: "$ ls -la /tmp/BusyBox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" +//usage: "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" +//usage: "$ ls -la /tmp/BusyBox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" +//usage: +//usage:#define zcat_trivial_usage +//usage: "FILE" +//usage:#define zcat_full_usage "\n\n" +//usage: "Decompress to stdout" + #if ENABLE_GUNZIP static char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) @@ -245,31 +272,9 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN return filename; } static -IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) +IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) { - IF_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_SEAMLESS_Z && magic2 == 0x9d) { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } else if (magic2 == 0x8b) { - status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info); - } 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; + return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } /* * Linux kernel build uses gzip -d -n. We accept and ignore it. @@ -308,20 +313,19 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) //usage: "[-cf] [FILE]..." //usage:#define bunzip2_full_usage "\n\n" //usage: "Decompress FILEs (or stdin)\n" -//usage: "\nOptions:" //usage: "\n -c Write to stdout" //usage: "\n -f Force" //usage:#define bzcat_trivial_usage //usage: "FILE" //usage:#define bzcat_full_usage "\n\n" //usage: "Decompress to stdout" -//applet:IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat)) +//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) #if ENABLE_BUNZIP2 static -IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) { - return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); + return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) @@ -344,11 +348,52 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define unlzma_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define unlzma_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define lzma_trivial_usage +//usage: "-d [-cf] [FILE]..." +//usage:#define lzma_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define lzcat_trivial_usage +//usage: "FILE" +//usage:#define lzcat_full_usage "\n\n" +//usage: "Decompress to stdout" +//usage: +//usage:#define unxz_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define unxz_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define xz_trivial_usage +//usage: "-d [-cf] [FILE]..." +//usage:#define xz_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define xzcat_trivial_usage +//usage: "FILE" +//usage:#define xzcat_full_usage "\n\n" +//usage: "Decompress to stdout" + #if ENABLE_UNLZMA static -IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) { - return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) @@ -371,18 +416,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_UNXZ static -IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) { - struct { - uint32_t v1; - uint16_t v2; - } magic; - xread(STDIN_FILENO, &magic, 6); - if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) { - bb_error_msg("invalid magic"); - return -1; - } - return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) diff --git a/release/src/router/busybox/archival/bzip2.c b/release/src/router/busybox/archival/bzip2.c index ab08ffc1a9..dd77c8efcf 100644 --- a/release/src/router/busybox/archival/bzip2.c +++ b/release/src/router/busybox/archival/bzip2.c @@ -7,10 +7,19 @@ * about bzip2 library code. */ +//usage:#define bzip2_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define bzip2_full_usage "\n\n" +//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n" +//usage: "\n -1..9 Compression level" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" -#define CONFIG_BZIP2_FEATURE_SPEED 1 +#define CONFIG_BZIP2_FAST 1 /* Speed test: * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache). @@ -18,7 +27,7 @@ * (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: + * Test run of all CONFIG_BZIP2_FAST 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 @@ -102,7 +111,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo } static -IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM) { IF_DESKTOP(long long) int total; ssize_t count; diff --git a/release/src/router/busybox/archival/cpio.c b/release/src/router/busybox/archival/cpio.c index 9fa8badc53..98cc18fa07 100644 --- a/release/src/router/busybox/archival/cpio.c +++ b/release/src/router/busybox/archival/cpio.c @@ -12,7 +12,36 @@ * */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" + +//usage:#define cpio_trivial_usage +//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") +//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") +//usage: " [EXTR_FILE]..." +//usage:#define cpio_full_usage "\n\n" +//usage: "Extract or list files from a cpio archive" +//usage: IF_FEATURE_CPIO_O(", or" +//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") +//usage: " using file list on stdin" +//usage: ) +//usage: "\n" +//usage: "\nMain operation mode:" +//usage: "\n -t List" +//usage: "\n -i Extract EXTR_FILEs (or all)" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -o Create (requires -H newc)" +//usage: ) +//usage: IF_FEATURE_CPIO_P( +//usage: "\n -p DIR Copy files to DIR" +//usage: ) +//usage: "\n -d Make leading directories" +//usage: "\n -m Preserve mtime" +//usage: "\n -v Verbose" +//usage: "\n -u Overwrite" +//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -H newc Archive format" +//usage: ) /* GNU cpio 2.9 --help (abridged): @@ -20,7 +49,7 @@ -t, --list List the archive -i, --extract Extract files from an archive -o, --create Create the archive - -p, --pass-through Copy-pass mode [was ist das?!] + -p, --pass-through Copy-pass mode Options valid in any mode: --block-size=SIZE I/O block size = SIZE * 512 bytes @@ -78,27 +107,28 @@ --sparse Write files with blocks of zeros as sparse files -u, --unconditional Replace all files unconditionally */ + enum { - CPIO_OPT_EXTRACT = (1 << 0), - CPIO_OPT_TEST = (1 << 1), - CPIO_OPT_NUL_TERMINATED = (1 << 2), - CPIO_OPT_UNCONDITIONAL = (1 << 3), - CPIO_OPT_VERBOSE = (1 << 4), - CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), - CPIO_OPT_PRESERVE_MTIME = (1 << 6), - CPIO_OPT_DEREF = (1 << 7), - CPIO_OPT_FILE = (1 << 8), + OPT_EXTRACT = (1 << 0), + OPT_TEST = (1 << 1), + OPT_NUL_TERMINATED = (1 << 2), + OPT_UNCONDITIONAL = (1 << 3), + OPT_VERBOSE = (1 << 4), + OPT_CREATE_LEADING_DIR = (1 << 5), + OPT_PRESERVE_MTIME = (1 << 6), + OPT_DEREF = (1 << 7), + OPT_FILE = (1 << 8), OPTBIT_FILE = 8, IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) IF_LONG_OPTS( OPTBIT_QUIET ,) IF_LONG_OPTS( OPTBIT_2STDOUT ,) - CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, - CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, - CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, - CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, - CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, + OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, + OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, + OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, + OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, + OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, }; #define OPTION_STR "it0uvdmLF:" @@ -138,7 +168,7 @@ static NOINLINE int cpio_o(void) char *line; struct stat st; - line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) + line = (option_mask32 & OPT_NUL_TERMINATED) ? bb_get_chunk_from_file(stdin, NULL) : xmalloc_fgetline(stdin); @@ -153,7 +183,7 @@ static NOINLINE int cpio_o(void) free(line); continue; } - if ((option_mask32 & CPIO_OPT_DEREF) + if ((option_mask32 & OPT_DEREF) ? stat(name, &st) : lstat(name, &st) ) { @@ -310,22 +340,22 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #if !ENABLE_FEATURE_CPIO_O opt = getopt32(argv, OPTION_STR, &cpio_filename); argv += optind; - if (opt & CPIO_OPT_FILE) { /* -F */ + if (opt & OPT_FILE) { /* -F */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } #else opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); argv += optind; - if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ + if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } - if (opt & CPIO_OPT_PASSTHROUGH) { + if (opt & OPT_PASSTHROUGH) { pid_t pid; struct fd_pair pp; if (argv[0] == NULL) bb_show_usage(); - if (opt & CPIO_OPT_CREATE_LEADING_DIR) + if (opt & OPT_CREATE_LEADING_DIR) mkdir(argv[0], 0777); /* Crude existence check: * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); @@ -354,18 +384,19 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) goto dump; } /* parent */ + USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */ xchdir(*argv++); close(pp.wr); xmove_fd(pp.rd, STDIN_FILENO); - //opt &= ~CPIO_OPT_PASSTHROUGH; - opt |= CPIO_OPT_EXTRACT; + //opt &= ~OPT_PASSTHROUGH; + opt |= OPT_EXTRACT; goto skip; } /* -o */ - if (opt & CPIO_OPT_CREATE) { + if (opt & OPT_CREATE) { if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ bb_show_usage(); - if (opt & CPIO_OPT_FILE) { + if (opt & OPT_FILE) { xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } dump: @@ -375,35 +406,35 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #endif /* One of either extract or test options must be given */ - if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { + if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) { bb_show_usage(); } - if (opt & CPIO_OPT_TEST) { + if (opt & OPT_TEST) { /* if both extract and test options are given, ignore extract option */ - opt &= ~CPIO_OPT_EXTRACT; + opt &= ~OPT_EXTRACT; archive_handle->action_header = header_list; } - if (opt & CPIO_OPT_EXTRACT) { + if (opt & OPT_EXTRACT) { archive_handle->action_data = data_extract_all; - if (opt & CPIO_OPT_2STDOUT) + if (opt & OPT_2STDOUT) archive_handle->action_data = data_extract_to_stdout; } - if (opt & CPIO_OPT_UNCONDITIONAL) { + if (opt & OPT_UNCONDITIONAL) { archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; } - if (opt & CPIO_OPT_VERBOSE) { + if (opt & 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_CREATE_LEADING_DIR) { + if (opt & OPT_CREATE_LEADING_DIR) { archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; } - if (opt & CPIO_OPT_PRESERVE_MTIME) { + if (opt & OPT_PRESERVE_MTIME) { archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; } @@ -419,7 +450,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) continue; if (archive_handle->cpio__blocks != (off_t)-1 - && !(opt & CPIO_OPT_QUIET) + && !(opt & OPT_QUIET) ) { fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); } diff --git a/release/src/router/busybox/archival/dpkg.c b/release/src/router/busybox/archival/dpkg.c index c37ae33490..bf9e9992c1 100644 --- a/release/src/router/busybox/archival/dpkg.c +++ b/release/src/router/busybox/archival/dpkg.c @@ -28,9 +28,36 @@ * */ +//usage:#define dpkg_trivial_usage +//usage: "[-ilCPru] [-F OPT] PACKAGE" +//usage:#define dpkg_full_usage "\n\n" +//usage: "Install, remove and manage Debian packages\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--install Install the package" +//usage: "\n -l,--list List of installed packages" +//usage: "\n --configure Configure an unpackaged package" +//usage: "\n -P,--purge Purge all files of a package" +//usage: "\n -r,--remove Remove all but the configuration files for a package" +//usage: "\n --unpack Unpack a package, but don't configure it" +//usage: "\n --force-depends Ignore dependency problems" +//usage: "\n --force-confnew Overwrite existing config files when installing" +//usage: "\n --force-confold Keep old config files when installing" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i Install the package" +//usage: "\n -l List of installed packages" +//usage: "\n -C Configure an unpackaged package" +//usage: "\n -P Purge all files of a package" +//usage: "\n -r Remove all but the configuration files for a package" +//usage: "\n -u Unpack a package, but don't configure it" +//usage: "\n -F depends Ignore dependency problems" +//usage: "\n -F confnew Overwrite existing config files when installing" +//usage: "\n -F confold Keep old config files when installing" +//usage: ) + #include "libbb.h" #include -#include "archive.h" +#include "bb_archive.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. @@ -674,28 +701,21 @@ static unsigned get_status(const unsigned status_node, const int 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"); diff --git a/release/src/router/busybox/archival/dpkg_deb.c b/release/src/router/busybox/archival/dpkg_deb.c index aee7b4cf50..a04ec94077 100644 --- a/release/src/router/busybox/archival/dpkg_deb.c +++ b/release/src/router/busybox/archival/dpkg_deb.c @@ -4,8 +4,22 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define dpkg_deb_trivial_usage +//usage: "[-cefxX] FILE [argument" +//usage:#define dpkg_deb_full_usage "\n\n" +//usage: "Perform actions on Debian packages (.debs)\n" +//usage: "\n -c List contents of filesystem tree" +//usage: "\n -e Extract control files to [argument] directory" +//usage: "\n -f Display control field name starting with [argument]" +//usage: "\n -x Extract packages filesystem tree to directory" +//usage: "\n -X Verbose extract" +//usage: +//usage:#define dpkg_deb_example_usage +//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #define DPKG_DEB_OPT_CONTENTS 1 #define DPKG_DEB_OPT_CONTROL 2 diff --git a/release/src/router/busybox/archival/gzip.c b/release/src/router/busybox/archival/gzip.c index 38c5ae7fd6..80db4f9699 100644 --- a/release/src/router/busybox/archival/gzip.c +++ b/release/src/router/busybox/archival/gzip.c @@ -39,8 +39,23 @@ gzip: bogus: No such file or directory aa: 85.1% -- replaced with aa.gz */ +//usage:#define gzip_trivial_usage +//usage: "[-cfd] [FILE]..." +//usage:#define gzip_full_usage "\n\n" +//usage: "Compress FILEs (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define gzip_example_usage +//usage: "$ ls -la /tmp/busybox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" +//usage: "$ gzip /tmp/busybox.tar\n" +//usage: "$ ls -la /tmp/busybox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* =========================================================================== @@ -66,7 +81,15 @@ aa: 85.1% -- replaced with aa.gz /* =========================================================================== */ -#define SMALL_MEM +#if CONFIG_GZIP_FAST == 0 +# define SMALL_MEM +#elif CONFIG_GZIP_FAST == 1 +# define MEDIUM_MEM +#elif CONFIG_GZIP_FAST == 2 +# define BIG_MEM +#else +# error "Invalid CONFIG_GZIP_FAST value" +#endif #ifndef INBUFSIZ # ifdef SMALL_MEM @@ -1658,7 +1681,7 @@ static ulg flush_block(char *buf, ulg stored_len, int eof) /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * IN assertion: all calls 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. */ @@ -1689,7 +1712,7 @@ static ulg flush_block(char *buf, ulg stored_len, int 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 + * IN assertion: all calls 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) \ @@ -1992,7 +2015,7 @@ static void zip(ulg time_stamp) /* ======================================================================== */ static -IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM) { struct stat s; diff --git a/release/src/router/busybox/archival/libarchive/Kbuild.src b/release/src/router/busybox/archival/libarchive/Kbuild.src index b0bc4e5aad..58457fc220 100644 --- a/release/src/router/busybox/archival/libarchive/Kbuild.src +++ b/release/src/router/busybox/archival/libarchive/Kbuild.src @@ -28,10 +28,13 @@ COMMON_FILES:= \ init_handle.o DPKG_FILES:= \ - get_header_ar.o \ unpack_ar_archive.o \ + filter_accept_list_reassign.o \ + get_header_ar.o \ get_header_tar.o \ - filter_accept_list_reassign.o + get_header_tar_gz.o \ + get_header_tar_bz2.o \ + get_header_tar_lzma.o \ INSERT @@ -42,20 +45,22 @@ lib-$(CONFIG_UNXZ) += decompress_unxz.o lib-$(CONFIG_CPIO) += get_header_cpio.o lib-$(CONFIG_DPKG) += $(DPKG_FILES) lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) -lib-$(CONFIG_GUNZIP) += decompress_unzip.o -lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o +lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o +lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o lib-$(CONFIG_TAR) += get_header_tar.o lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o -lib-$(CONFIG_UNZIP) += decompress_unzip.o +lib-$(CONFIG_UNZIP) += decompress_gunzip.o lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o +lib-$(CONFIG_MODINFO) += open_transformer.o +lib-$(CONFIG_INSMOD) += open_transformer.o lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o -lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o -lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o -lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o +lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o -lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o +lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o diff --git a/release/src/router/busybox/archival/libarchive/bz/blocksort.c b/release/src/router/busybox/archival/libarchive/bz/blocksort.c index f70c3701d0..e600cb7a76 100644 --- a/release/src/router/busybox/archival/libarchive/bz/blocksort.c +++ b/release/src/router/busybox/archival/libarchive/bz/blocksort.c @@ -385,7 +385,7 @@ int mainGtU( * but speeds up compression 10% overall */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 +#if CONFIG_BZIP2_FAST >= 1 #define TIMES_8(code) \ code; code; code; code; \ @@ -496,7 +496,7 @@ void mainSimpleSort(uint32_t* ptr, i++; /* 1.5% overall speedup, +290 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 3 +#if CONFIG_BZIP2_FAST >= 3 /*-- copy 2 --*/ if (i > hi) break; v = ptr[i]; @@ -750,7 +750,7 @@ void mainSort(EState* state, j = block[0] << 8; i = nblock - 1; /* 3%, +300 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 +#if CONFIG_BZIP2_FAST >= 2 for (; i >= 3; i -= 4) { quadrant[i] = 0; j = (j >> 8) | (((uint16_t)block[i]) << 8); @@ -787,7 +787,7 @@ void mainSort(EState* state, s = block[0] << 8; i = nblock - 1; -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 +#if CONFIG_BZIP2_FAST >= 2 for (; i >= 3; i -= 4) { s = (s >> 8) | (block[i] << 8); j = ftab[s] - 1; diff --git a/release/src/router/busybox/archival/libarchive/bz/bzlib_private.h b/release/src/router/busybox/archival/libarchive/bz/bzlib_private.h index 6430ce4073..43e674bec8 100644 --- a/release/src/router/busybox/archival/libarchive/bz/bzlib_private.h +++ b/release/src/router/busybox/archival/libarchive/bz/bzlib_private.h @@ -183,7 +183,7 @@ typedef struct EState { /* 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 +#if CONFIG_BZIP2_FAST >= 5 /* second dimension: only 3 needed; 4 makes index calculations faster */ uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; #endif diff --git a/release/src/router/busybox/archival/libarchive/bz/compress.c b/release/src/router/busybox/archival/libarchive/bz/compress.c index 6f1c70a084..e9f1afdaf3 100644 --- a/release/src/router/busybox/archival/libarchive/bz/compress.c +++ b/release/src/router/busybox/archival/libarchive/bz/compress.c @@ -61,7 +61,7 @@ void bsFinishWrite(EState* s) /*---------------------------------------------------*/ static /* Helps only on level 5, on other levels hurts. ? */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 ALWAYS_INLINE #endif void bsW(EState* s, int32_t n, uint32_t v) @@ -251,7 +251,7 @@ 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; + int32_t nGroups; /* * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; @@ -331,7 +331,7 @@ void sendMTFValues(EState* s) for (v = 0; v < alphaSize; v++) s->rfreq[t][v] = 0; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 /* * Set up an auxiliary length table which is used to fast-track * the common case (nGroups == 6). @@ -361,7 +361,7 @@ void sendMTFValues(EState* s) */ for (t = 0; t < nGroups; t++) cost[t] = 0; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ register uint32_t cost01, cost23, cost45; @@ -420,7 +420,7 @@ void sendMTFValues(EState* s) * Increment the symbol frequencies for the selected table. */ /* 1% faster compress. +800 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 4 +#if CONFIG_BZIP2_FAST >= 4 if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ #define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ @@ -512,7 +512,6 @@ void sendMTFValues(EState* s) } } - nBytes = s->numZ; bsW(s, 16, inUse16); inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ @@ -528,7 +527,6 @@ void sendMTFValues(EState* s) } /*--- Now the selectors. ---*/ - nBytes = s->numZ; bsW(s, 3, nGroups); bsW(s, 15, nSelectors); for (i = 0; i < nSelectors; i++) { @@ -538,8 +536,6 @@ void sendMTFValues(EState* s) } /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - for (t = 0; t < nGroups; t++) { int32_t curr = s->len[t][0]; bsW(s, 5, curr); @@ -551,7 +547,6 @@ void sendMTFValues(EState* s) } /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; selCtr = 0; gs = 0; while (1) { diff --git a/release/src/router/busybox/archival/libarchive/bz/huffman.c b/release/src/router/busybox/archival/libarchive/bz/huffman.c index 676b1af66a..bbec11adbd 100644 --- a/release/src/router/busybox/archival/libarchive/bz/huffman.c +++ b/release/src/router/busybox/archival/libarchive/bz/huffman.c @@ -48,7 +48,7 @@ in the file LICENSE. /* 90 bytes, 0.3% of overall compress speed */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 +#if CONFIG_BZIP2_FAST >= 1 /* macro works better than inline (gcc 4.2.1) */ #define DOWNHEAP1(heap, weight, Heap) \ diff --git a/release/src/router/busybox/archival/libarchive/data_align.c b/release/src/router/busybox/archival/libarchive/data_align.c index 2e56fa8ff0..a6b84a440f 100644 --- a/release/src/router/busybox/archival/libarchive/data_align.c +++ b/release/src/router/busybox/archival/libarchive/data_align.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) { diff --git a/release/src/router/busybox/archival/libarchive/data_extract_all.c b/release/src/router/busybox/archival/libarchive/data_extract_all.c index 1b25c8bd65..3f67b835fe 100644 --- a/release/src/router/busybox/archival/libarchive/data_extract_all.c +++ b/release/src/router/busybox/archival/libarchive/data_extract_all.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { @@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) int res; #if ENABLE_FEATURE_TAR_SELINUX - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif diff --git a/release/src/router/busybox/archival/libarchive/data_extract_to_command.c b/release/src/router/busybox/archival/libarchive/data_extract_to_command.c index 2bbab76416..a2ce33b51f 100644 --- a/release/src/router/busybox/archival/libarchive/data_extract_to_command.c +++ b/release/src/router/busybox/archival/libarchive/data_extract_to_command.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" enum { //TAR_FILETYPE, @@ -64,13 +64,13 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) file_header_t *file_header = archive_handle->file_header; #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif @@ -99,8 +99,12 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) close(p[1]); xdup2(p[0], STDIN_FILENO); signal(SIGPIPE, SIG_DFL); - execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); - bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); + execl(archive_handle->tar__to_command_shell, + archive_handle->tar__to_command_shell, + "-c", + archive_handle->tar__to_command, + NULL); + bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell); } close(p[0]); /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) diff --git a/release/src/router/busybox/archival/libarchive/data_extract_to_stdout.c b/release/src/router/busybox/archival/libarchive/data_extract_to_stdout.c index 91f3f35395..f849f3b428 100644 --- a/release/src/router/busybox/archival/libarchive/data_extract_to_stdout.c +++ b/release/src/router/busybox/archival/libarchive/data_extract_to_stdout.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) { diff --git a/release/src/router/busybox/archival/libarchive/data_skip.c b/release/src/router/busybox/archival/libarchive/data_skip.c index a055424e2a..588167f01c 100644 --- a/release/src/router/busybox/archival/libarchive/data_skip.c +++ b/release/src/router/busybox/archival/libarchive/data_skip.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC data_skip(archive_handle_t *archive_handle) { diff --git a/release/src/router/busybox/archival/libarchive/decompress_bunzip2.c b/release/src/router/busybox/archival/libarchive/decompress_bunzip2.c index 4e46e6849c..dc252bb822 100644 --- a/release/src/router/busybox/archival/libarchive/decompress_bunzip2.c +++ b/release/src/router/busybox/archival/libarchive/decompress_bunzip2.c @@ -40,7 +40,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* Constants for Huffman coding */ #define MAX_GROUPS 6 @@ -721,7 +721,7 @@ void FAST_FUNC dealloc_bunzip(bunzip_data *bd) /* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream(int src_fd, int dst_fd) +unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) bunzip_data *bd; @@ -729,6 +729,9 @@ unpack_bz2_stream(int src_fd, int dst_fd) int i; unsigned len; + if (check_signature16(aux, src_fd, BZIP2_MAGIC)) + return -1; + outbuf = xmalloc(IOBUF_SIZE); len = 0; while (1) { /* "Process one BZ... stream" loop */ @@ -752,7 +755,14 @@ unpack_bz2_stream(int src_fd, int dst_fd) } } - if (i != RETVAL_LAST_BLOCK) { + if (i != RETVAL_LAST_BLOCK + /* Observed case when i == RETVAL_OK: + * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file + * (to be exact, z.bz2 is exactly these 14 bytes: + * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). + */ + && i != RETVAL_OK + ) { bb_error_msg("bunzip error %d", i); break; } @@ -787,17 +797,6 @@ unpack_bz2_stream(int src_fd, int dst_fd) return i ? i : IF_DESKTOP(total_written) + 0; } -IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream_prime(int src_fd, int dst_fd) -{ - uint16_t magic2; - xread(src_fd, &magic2, 2); - if (magic2 != BZIP2_MAGIC) { - bb_error_msg_and_die("invalid magic"); - } - return unpack_bz2_stream(src_fd, dst_fd); -} - #ifdef TESTING static char *const bunzip_errors[] = { @@ -812,7 +811,7 @@ int main(int argc, char **argv) int i; char c; - int i = unpack_bz2_stream_prime(0, 1); + int i = unpack_bz2_stream(0, 1); if (i < 0) fprintf(stderr, "%s\n", bunzip_errors[-i]); else if (read(STDIN_FILENO, &c, 1)) diff --git a/release/src/router/busybox/archival/libarchive/decompress_unzip.c b/release/src/router/busybox/archival/libarchive/decompress_gunzip.c similarity index 96% rename from release/src/router/busybox/archival/libarchive/decompress_unzip.c rename to release/src/router/busybox/archival/libarchive/decompress_gunzip.c index a29eef8370..2d5ab3eb3f 100644 --- a/release/src/router/busybox/archival/libarchive/decompress_unzip.c +++ b/release/src/router/busybox/archival/libarchive/decompress_gunzip.c @@ -35,7 +35,7 @@ #include #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" typedef struct huft_t { unsigned char e; /* number of extra bits or operation */ @@ -1034,22 +1034,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out) /* For unzip */ IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) +inflate_unzip(transformer_aux_data_t *aux, int in, int out) { IF_DESKTOP(long long) int n; DECLARE_STATE; ALLOC_STATE; - to_read = compr_size; + to_read = aux->bytes_in; // 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; + aux->crc32 = gunzip_crc; + aux->bytes_out = gunzip_bytes_out; DEALLOC_STATE; return n; } @@ -1107,7 +1107,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) return res; } -static int check_header_gzip(STATE_PARAM unpack_info_t *info) +static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) { union { unsigned char raw[8]; @@ -1169,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } } - if (info) - info->mtime = SWAP_LE32(header.formatted.mtime); + if (aux) + aux->mtime = SWAP_LE32(header.formatted.mtime); /* Read the header checksum */ if (header.formatted.flags & 0x02) { @@ -1182,33 +1182,58 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) +unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { uint32_t v32; - IF_DESKTOP(long long) int n; + IF_DESKTOP(long long) int total, n; DECLARE_STATE; - n = 0; +#if !ENABLE_FEATURE_SEAMLESS_Z + if (check_signature16(aux, src_fd, GZIP_MAGIC)) + return -1; +#else + if (aux && aux->check_signature) { + uint16_t magic2; + + if (full_read(src_fd, &magic2, 2) != 2) { + bad_magic: + bb_error_msg("invalid magic"); + return -1; + } + if (magic2 == COMPRESS_MAGIC) { + aux->check_signature = 0; + return unpack_Z_stream(aux, src_fd, dst_fd); + } + if (magic2 != GZIP_MAGIC) + goto bad_magic; + } +#endif + + total = 0; ALLOC_STATE; to_read = -1; // bytebuffer_max = 0x8000; bytebuffer = xmalloc(bytebuffer_max); - gunzip_src_fd = in; + gunzip_src_fd = src_fd; again: - if (!check_header_gzip(PASS_STATE info)) { + if (!check_header_gzip(PASS_STATE aux)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } - n += inflate_unzip_internal(PASS_STATE in, out); - if (n < 0) + + n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); + if (n < 0) { + total = -1; goto ret; + } + total += n; if (!top_up(PASS_STATE 8)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } @@ -1216,7 +1241,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((~gunzip_crc) != v32) { bb_error_msg("crc error"); - n = -1; + total = -1; goto ret; } @@ -1224,7 +1249,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((uint32_t)gunzip_bytes_out != v32) { bb_error_msg("incorrect length"); - n = -1; + total = -1; } if (!top_up(PASS_STATE 2)) @@ -1242,11 +1267,5 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) ret: free(bytebuffer); DEALLOC_STATE; - return n; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) -{ - return unpack_gz_stream_with_info(in, out, NULL); + return total; } diff --git a/release/src/router/busybox/archival/libarchive/decompress_uncompress.c b/release/src/router/busybox/archival/libarchive/decompress_uncompress.c index 44d894244d..e9bbfb9bd8 100644 --- a/release/src/router/busybox/archival/libarchive/decompress_uncompress.c +++ b/release/src/router/busybox/archival/libarchive/decompress_uncompress.c @@ -25,7 +25,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* Default input buffer size */ @@ -73,7 +73,7 @@ */ IF_DESKTOP(long long) int FAST_FUNC -unpack_Z_stream(int fd_in, int fd_out) +unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) IF_DESKTOP(long long) int retval = -1; @@ -103,16 +103,19 @@ unpack_Z_stream(int fd_in, int fd_out) /* block compress mode -C compatible with 2.0 */ int block_mode; /* = BLOCK_MODE; */ + if (check_signature16(aux, src_fd, COMPRESS_MAGIC)) + return -1; + inbuf = xzalloc(IBUFSIZ + 64); outbuf = xzalloc(OBUFSIZ + 2048); - htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */ + htab = xzalloc(HSIZE); /* wasn'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) { + if (full_read(src_fd, inbuf, 1) != 1) { bb_error_msg("short read"); goto err; } @@ -162,8 +165,9 @@ unpack_Z_stream(int fd_in, int fd_out) } if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { - rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); -//error check?? + rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ); + if (rsize < 0) + bb_error_msg_and_die(bb_msg_read_error); insize += rsize; } @@ -195,6 +199,8 @@ unpack_Z_stream(int fd_in, int fd_out) if (oldcode == -1) { + if (code >= 256) + bb_error_msg_and_die("corrupted data"); /* %ld", code); */ oldcode = code; finchar = (int) oldcode; outbuf[outpos++] = (unsigned char) finchar; @@ -239,6 +245,8 @@ unpack_Z_stream(int fd_in, int fd_out) /* Generate output characters in reverse order */ while ((long) code >= (long) 256) { + if (stackp <= &htabof(0)) + bb_error_msg_and_die("corrupted data"); *--stackp = tab_suffixof(code); code = tab_prefixof(code); } @@ -263,8 +271,7 @@ unpack_Z_stream(int fd_in, int fd_out) } if (outpos >= OBUFSIZ) { - full_write(fd_out, outbuf, outpos); -//error check?? + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) outpos = 0; } @@ -292,8 +299,7 @@ unpack_Z_stream(int fd_in, int fd_out) } while (rsize > 0); if (outpos > 0) { - full_write(fd_out, outbuf, outpos); -//error check?? + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) } diff --git a/release/src/router/busybox/archival/libarchive/decompress_unlzma.c b/release/src/router/busybox/archival/libarchive/decompress_unlzma.c index a047143411..cfde8ea56e 100644 --- a/release/src/router/busybox/archival/libarchive/decompress_unlzma.c +++ b/release/src/router/busybox/archival/libarchive/decompress_unlzma.c @@ -9,7 +9,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #if ENABLE_FEATURE_LZMA_FAST # define speed_inline ALWAYS_INLINE @@ -213,7 +213,7 @@ enum { IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(int src_fd, int dst_fd) +unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) lzma_header_t header; diff --git a/release/src/router/busybox/archival/libarchive/decompress_unxz.c b/release/src/router/busybox/archival/libarchive/decompress_unxz.c index e90dfb06f7..79b48a152e 100644 --- a/release/src/router/busybox/archival/libarchive/decompress_unxz.c +++ b/release/src/router/busybox/archival/libarchive/decompress_unxz.c @@ -10,7 +10,7 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #define XZ_FUNC FAST_FUNC #define XZ_EXTERN static @@ -38,7 +38,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) #include "unxz/xz_dec_stream.c" IF_DESKTOP(long long) int FAST_FUNC -unpack_xz_stream(int src_fd, int dst_fd) +unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { struct xz_buf iobuf; struct xz_dec *state; @@ -49,13 +49,17 @@ unpack_xz_stream(int src_fd, int dst_fd) global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); memset(&iobuf, 0, sizeof(iobuf)); - /* Preload XZ file signature */ - membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); + membuf = xmalloc(2 * BUFSIZ); iobuf.in = membuf; - iobuf.in_size = HEADER_MAGIC_SIZE; iobuf.out = membuf + BUFSIZ; iobuf.out_size = BUFSIZ; + if (!aux || aux->check_signature == 0) { + /* Preload XZ file signature */ + strcpy((char*)membuf, HEADER_MAGIC); + iobuf.in_size = HEADER_MAGIC_SIZE; + } /* else: let xz code read & check it */ + /* Limit memory usage to about 64 MiB. */ state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); diff --git a/release/src/router/busybox/archival/libarchive/filter_accept_all.c b/release/src/router/busybox/archival/libarchive/filter_accept_all.c index e69deb6798..c33f7d3e36 100644 --- a/release/src/router/busybox/archival/libarchive/filter_accept_all.c +++ b/release/src/router/busybox/archival/libarchive/filter_accept_all.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* Accept any non-null name, its not really a filter at all */ char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) diff --git a/release/src/router/busybox/archival/libarchive/filter_accept_list.c b/release/src/router/busybox/archival/libarchive/filter_accept_list.c index a7640af79f..a2d4b23e98 100644 --- a/release/src/router/busybox/archival/libarchive/filter_accept_list.c +++ b/release/src/router/busybox/archival/libarchive/filter_accept_list.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* * Accept names that are in the accept list, ignoring reject list. diff --git a/release/src/router/busybox/archival/libarchive/filter_accept_list_reassign.c b/release/src/router/busybox/archival/libarchive/filter_accept_list_reassign.c index d80f71668a..3d19abe448 100644 --- a/release/src/router/busybox/archival/libarchive/filter_accept_list_reassign.c +++ b/release/src/router/busybox/archival/libarchive/filter_accept_list_reassign.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ diff --git a/release/src/router/busybox/archival/libarchive/filter_accept_reject_list.c b/release/src/router/busybox/archival/libarchive/filter_accept_reject_list.c index 3e86cca654..39c811337e 100644 --- a/release/src/router/busybox/archival/libarchive/filter_accept_reject_list.c +++ b/release/src/router/busybox/archival/libarchive/filter_accept_reject_list.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* * Accept names that are in the accept list and not in the reject list diff --git a/release/src/router/busybox/archival/libarchive/find_list_entry.c b/release/src/router/busybox/archival/libarchive/find_list_entry.c index 5efd1af2e0..56032c65af 100644 --- a/release/src/router/busybox/archival/libarchive/find_list_entry.c +++ b/release/src/router/busybox/archival/libarchive/find_list_entry.c @@ -7,7 +7,7 @@ #include #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* Find a string in a shell pattern list */ const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) diff --git a/release/src/router/busybox/archival/libarchive/get_header_ar.c b/release/src/router/busybox/archival/libarchive/get_header_ar.c index df603b1114..23c4124963 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_ar.c +++ b/release/src/router/busybox/archival/libarchive/get_header_ar.c @@ -5,7 +5,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "ar.h" static unsigned read_num(const char *str, int base) diff --git a/release/src/router/busybox/archival/libarchive/get_header_cpio.c b/release/src/router/busybox/archival/libarchive/get_header_cpio.c index 3d99b492ab..1a0058b63a 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_cpio.c +++ b/release/src/router/busybox/archival/libarchive/get_header_cpio.c @@ -5,7 +5,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" typedef struct hardlinks_t { struct hardlinks_t *next; diff --git a/release/src/router/busybox/archival/libarchive/get_header_tar.c b/release/src/router/busybox/archival/libarchive/get_header_tar.c index 78b0ae25fe..b168653d80 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_tar.c +++ b/release/src/router/busybox/archival/libarchive/get_header_tar.c @@ -12,12 +12,41 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" typedef uint32_t aliased_uint32_t FIX_ALIASING; typedef off_t aliased_off_t FIX_ALIASING; +const char* FAST_FUNC strip_unsafe_prefix(const char *str) +{ + const char *cp = str; + while (1) { + char *cp2; + if (*cp == '/') { + cp++; + continue; + } + if (strncmp(cp, "/../"+1, 3) == 0) { + cp += 3; + continue; + } + cp2 = strstr(cp, "/../"); + if (!cp2) + break; + cp = cp2 + 4; + } + if (cp != str) { + static smallint warned = 0; + if (!warned) { + warned = 1; + bb_error_msg("removing leading '%.*s' from member names", + (int)(cp - str), str); + } + } + return cp; +} + /* NB: _DESTROYS_ str[len] character! */ static unsigned long long getOctal(char *str, int len) { @@ -50,34 +79,31 @@ static unsigned long long getOctal(char *str, int len) * * NB: tarballs with NEGATIVE unix times encoded that way were seen! */ - v = first; - /* Sign-extend using 6th bit: */ - v <<= sizeof(unsigned long long)*8 - 7; - v = (long long)v >> (sizeof(unsigned long long)*8 - 7); + /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */ + first <<= 1; + first >>= 1; /* now 7th bit = 6th bit */ + v = first; /* sign-extend 8 bits to 64 */ while (--len != 0) - v = (v << 8) + (unsigned char) *str++; + v = (v << 8) + (uint8_t) *++str; } return v; } #define GET_OCTAL(a) getOctal((a), sizeof(a)) -#if ENABLE_FEATURE_TAR_SELINUX -/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. - * This is what Red Hat's patched version of tar uses. - */ -# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" -static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) +/* "global" is 0 or 1 */ +static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) { char *buf, *p; - char *result; + unsigned blk_sz; + + blk_sz = (sz + 511) & (~511); + p = buf = xmalloc(blk_sz + 1); + xread(archive_handle->src_fd, buf, blk_sz); + archive_handle->offset += blk_sz; - p = buf = xmalloc(sz + 1); /* prevent bb_strtou from running off the buffer */ buf[sz] = '\0'; - xread(archive_handle->src_fd, buf, sz); - archive_handle->offset += sz; - result = NULL; while (sz != 0) { char *end, *value; unsigned len; @@ -104,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns * (we do not bother to check that it *was* a newline) */ p[-1] = '\0'; - /* Is it selinux security context? */ value = end + 1; + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = xstrdup(value); + continue; + } +#endif + +#if ENABLE_FEATURE_TAR_SELINUX + /* Scan for SELinux contexts, via "RHT.security.selinux" keyword. + * This is what Red Hat's patched version of tar uses. + */ +# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; - result = xstrdup(value); - break; + free(archive_handle->tar__sctx[global]); + archive_handle->tar__sctx[global] = xstrdup(value); + continue; } +#endif } free(buf); - return result; } -#endif char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) { @@ -195,43 +235,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) || memcmp(tar.magic, "\0\0\0\0", 5) != 0) ) { #if ENABLE_FEATURE_TAR_AUTODETECT - char FAST_FUNC (*get_header_ptr)(archive_handle_t *); - uint16_t magic2; - autodetect: - magic2 = *(uint16_t*)tar.name; - /* tar gz/bz autodetect: check for gz/bz2 magic. - * If we see the magic, and it is the very first block, - * we can switch to get_header_tar_gz/bz2/lzma(). - * Needs seekable fd. I wish recv(MSG_PEEK) works - * on any fd... */ -# if ENABLE_FEATURE_SEAMLESS_GZ - if (magic2 == GZIP_MAGIC) { - get_header_ptr = get_header_tar_gz; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_BZ2 - if (magic2 == BZIP2_MAGIC - && tar.name[2] == 'h' && isdigit(tar.name[3]) - ) { /* bzip2 */ - get_header_ptr = get_header_tar_bz2; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_XZ - //TODO: if (magic2 == XZ_MAGIC1)... - //else -# endif - goto err; /* Two different causes for lseek() != 0: * unseekable fd (would like to support that too, but...), * or not first block (false positive, it's not .gz/.bz2!) */ if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) goto err; - while (get_header_ptr(archive_handle) == EXIT_SUCCESS) - continue; - return EXIT_FAILURE; + if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0) err: -#endif /* FEATURE_TAR_AUTODETECT */ + bb_error_msg_and_die("invalid tar magic"); + archive_handle->offset = 0; + goto again_after_align; +#endif bb_error_msg_and_die("invalid tar magic"); } @@ -319,10 +334,20 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* 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': + case '1': /* hardlink */ + /* we mark hardlinks as regular files with zero size and a link name */ file_header->mode |= S_IFREG; - break; + /* on size of link fields from star(4) + * ... For tar archives written by pre POSIX.1-1988 + * implementations, the size field usually contains the size of + * the file and needs to be ignored as no data may follow this + * header type. For POSIX.1- 1988 compliant archives, the size + * field needs to be 0. For POSIX.1-2001 compliant archives, + * the size field may be non zero, indicating that file data is + * included in the archive. + * i.e; always assume this is zero for safety. + */ + goto size0; case '7': /* case 0: */ case '0': @@ -379,12 +404,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'S': /* Sparse file */ case 'V': /* Volume header */ #endif -#if !ENABLE_FEATURE_TAR_SELINUX case 'g': /* pax global header */ - case 'x': /* pax extended header */ -#else + case 'x': { /* pax extended header */ + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); + goto again_after_align; + } skip_ext_hdr: -#endif { off_t sz; bb_error_msg("warning: skipping header '%c'", tar.typeflag); @@ -396,18 +423,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* return get_header_tar(archive_handle); */ goto again_after_align; } -#if ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - char **pp; - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; - free(*pp); - *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); - goto again; - } -#endif default: bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); } @@ -422,12 +437,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) p_linkname = NULL; } #endif - if (strncmp(file_header->name, "/../"+1, 3) == 0 - || strstr(file_header->name, "/../") - ) { - bb_error_msg_and_die("name with '..' encountered: '%s'", - file_header->name); - } + + /* Everything up to and including last ".." component is stripped */ + overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name)); /* Strip trailing '/' in directories */ /* Must be done after mode is set as '/' is used to check if it's a directory */ diff --git a/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c b/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c index 60d32069fb..0ee00df53d 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c +++ b/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c @@ -4,14 +4,14 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) { /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); + open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c b/release/src/router/busybox/archival/libarchive/get_header_tar_gz.c similarity index 67% copy from release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c copy to release/src/router/busybox/archival/libarchive/get_header_tar_gz.c index 60d32069fb..03284342b1 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_tar_bz2.c +++ b/release/src/router/busybox/archival/libarchive/get_header_tar_gz.c @@ -4,14 +4,14 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" -char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) +char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) { /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); + open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/release/src/router/busybox/archival/libarchive/get_header_tar_lzma.c b/release/src/router/busybox/archival/libarchive/get_header_tar_lzma.c index da08e0c725..d565a217d9 100644 --- a/release/src/router/busybox/archival/libarchive/get_header_tar_lzma.c +++ b/release/src/router/busybox/archival/libarchive/get_header_tar_lzma.c @@ -7,14 +7,14 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) { /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/release/src/router/busybox/archival/libarchive/header_list.c b/release/src/router/busybox/archival/libarchive/header_list.c index c4fc75f380..0621aa406a 100644 --- a/release/src/router/busybox/archival/libarchive/header_list.c +++ b/release/src/router/busybox/archival/libarchive/header_list.c @@ -3,7 +3,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC header_list(const file_header_t *file_header) { diff --git a/release/src/router/busybox/archival/libarchive/header_skip.c b/release/src/router/busybox/archival/libarchive/header_skip.c index 2bfc5253ca..f5987bfe27 100644 --- a/release/src/router/busybox/archival/libarchive/header_skip.c +++ b/release/src/router/busybox/archival/libarchive/header_skip.c @@ -3,7 +3,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) { diff --git a/release/src/router/busybox/archival/libarchive/header_verbose_list.c b/release/src/router/busybox/archival/libarchive/header_verbose_list.c index bc4e4154b1..87dd82136d 100644 --- a/release/src/router/busybox/archival/libarchive/header_verbose_list.c +++ b/release/src/router/busybox/archival/libarchive/header_verbose_list.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC header_verbose_list(const file_header_t *file_header) { diff --git a/release/src/router/busybox/archival/libarchive/init_handle.c b/release/src/router/busybox/archival/libarchive/init_handle.c index 6644ea13b4..cbae06ac33 100644 --- a/release/src/router/busybox/archival/libarchive/init_handle.c +++ b/release/src/router/busybox/archival/libarchive/init_handle.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" archive_handle_t* FAST_FUNC init_handle(void) { diff --git a/release/src/router/busybox/archival/libarchive/open_transformer.c b/release/src/router/busybox/archival/libarchive/open_transformer.c index 26ae565f5f..dae04aa575 100644 --- a/release/src/router/busybox/archival/libarchive/open_transformer.c +++ b/release/src/router/busybox/archival/libarchive/open_transformer.c @@ -4,16 +4,64 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" + +void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux) +{ + memset(aux, 0, sizeof(*aux)); +} + +int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) +{ + if (aux && aux->check_signature) { + uint16_t magic2; + if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) { + bb_error_msg("invalid magic"); +#if 0 /* possible future extension */ + if (aux->check_signature > 1) + xfunc_die(); +#endif + return -1; + } + } + return 0; +} + +void check_errors_in_children(int signo) +{ + int status; + + if (!signo) { + /* block waiting for any child */ + if (wait(&status) < 0) + return; /* probably there are no children */ + goto check_status; + } + + /* Wait for any child without blocking */ + for (;;) { + if (wait_any_nohang(&status) < 0) + /* wait failed?! I'm confused... */ + return; + check_status: + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + /* this child exited with 0 */ + continue; + /* Cannot happen? + if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ + bb_got_signal = 1; + } +} /* transformer(), more than meets the eye */ -/* - * On MMU machine, the transform_prog is removed by macro magic - * in include/archive.h. On NOMMU, transformer is removed. - */ +#if BB_MMU void FAST_FUNC open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), - const char *transform_prog) + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) +) +#else +void FAST_FUNC open_transformer(int fd, const char *transform_prog) +#endif { struct fd_pair fd_pipe; int pid; @@ -25,13 +73,18 @@ void FAST_FUNC open_transformer(int fd, close(fd_pipe.rd); /* we don't want to read from the parent */ // FIXME: error check? #if BB_MMU - transformer(fd, fd_pipe.wr); - if (ENABLE_FEATURE_CLEAN_UP) { - close(fd_pipe.wr); /* send EOF */ - close(fd); + { + transformer_aux_data_t aux; + init_transformer_aux_data(&aux); + aux.check_signature = check_signature; + transformer(&aux, fd, fd_pipe.wr); + if (ENABLE_FEATURE_CLEAN_UP) { + close(fd_pipe.wr); /* send EOF */ + close(fd); + } + /* must be _exit! bug was actually seen here */ + _exit(EXIT_SUCCESS); } - /* must be _exit! bug was actually seen here */ - _exit(EXIT_SUCCESS); #else { char *argv[4]; @@ -52,3 +105,117 @@ void FAST_FUNC open_transformer(int fd, close(fd_pipe.wr); /* don't want to write to the child */ xmove_fd(fd_pipe.rd, fd); } + + +#if SEAMLESS_COMPRESSION + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected) +{ + union { + uint8_t b[4]; + uint16_t b16[2]; + uint32_t b32[1]; + } magic; + int offset = -2; + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_NOMMU(const char *xformer_prog;) + + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xread(fd, magic.b16, sizeof(magic.b16[0])); + if (ENABLE_FEATURE_SEAMLESS_GZ + && magic.b16[0] == GZIP_MAGIC + ) { + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && magic.b16[0] == BZIP2_MAGIC + ) { + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_XZ + && magic.b16[0] == XZ_MAGIC1 + ) { + offset = -6; + xread(fd, magic.b32, sizeof(magic.b32[0])); + if (magic.b32[0] == XZ_MAGIC2) { + USE_FOR_MMU(xformer = unpack_xz_stream;) + USE_FOR_NOMMU(xformer_prog = "unxz";) + goto found_magic; + } + } + + /* No known magic seen */ + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") + " magic"); + xlseek(fd, offset, SEEK_CUR); + return 1; + + found_magic: +# if BB_MMU + open_transformer_with_no_sig(fd, xformer); +# else + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, offset, SEEK_CUR); + open_transformer_with_sig(fd, xformer, xformer_prog); +# endif + return 0; +} + +int FAST_FUNC open_zipped(const char *fname) +{ + char *sfx; + int fd; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return fd; + + sfx = strrchr(fname, '.'); + if (sfx) { + sfx++; + if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) + /* .lzma has no header/signature, just trust it */ + open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma"); + else + if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) + || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) + || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) + ) { + setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1); + } + } + + return fd; +} + +#endif /* SEAMLESS_COMPRESSION */ + +void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) +{ + int fd; + char *image; + + fd = open_zipped(fname); + if (fd < 0) + return NULL; + + image = xmalloc_read(fd, maxsz_p); + if (!image) + bb_perror_msg("read error from '%s'", fname); + close(fd); + + return image; +} diff --git a/release/src/router/busybox/archival/libarchive/seek_by_jump.c b/release/src/router/busybox/archival/libarchive/seek_by_jump.c index 7c2c52ae1c..4fcd99ac80 100644 --- a/release/src/router/busybox/archival/libarchive/seek_by_jump.c +++ b/release/src/router/busybox/archival/libarchive/seek_by_jump.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" void FAST_FUNC seek_by_jump(int fd, off_t amount) { diff --git a/release/src/router/busybox/archival/libarchive/seek_by_read.c b/release/src/router/busybox/archival/libarchive/seek_by_read.c index ad931a8de5..c0fde96608 100644 --- a/release/src/router/busybox/archival/libarchive/seek_by_read.c +++ b/release/src/router/busybox/archival/libarchive/seek_by_read.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.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. diff --git a/release/src/router/busybox/archival/libarchive/unpack_ar_archive.c b/release/src/router/busybox/archival/libarchive/unpack_ar_archive.c index 18dbfd54db..214d17e23a 100644 --- a/release/src/router/busybox/archival/libarchive/unpack_ar_archive.c +++ b/release/src/router/busybox/archival/libarchive/unpack_ar_archive.c @@ -4,7 +4,7 @@ */ #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "ar.h" void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) diff --git a/release/src/router/busybox/archival/lzop.c b/release/src/router/busybox/archival/lzop.c index 094e78cf98..fbe08417df 100644 --- a/release/src/router/busybox/archival/lzop.c +++ b/release/src/router/busybox/archival/lzop.c @@ -25,8 +25,33 @@ "Minimalized" for busybox by Alain Knaff */ +//usage:#define lzop_trivial_usage +//usage: "[-cfvd123456789CF] [FILE]..." +//usage:#define lzop_full_usage "\n\n" +//usage: " -1..9 Compression level" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -v Verbose" +//usage: "\n -F Don't store or verify checksum" +//usage: "\n -C Also write checksum of compressed block" +//usage: +//usage:#define lzopcat_trivial_usage +//usage: "[-vCF] [FILE]..." +//usage:#define lzopcat_full_usage "\n\n" +//usage: " -v Verbose" +//usage: "\n -F Don't store or verify checksum" +//usage: +//usage:#define unlzop_trivial_usage +//usage: "[-cfvCF] [FILE]..." +//usage:#define unlzop_full_usage "\n\n" +//usage: " -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -v Verbose" +//usage: "\n -F Don't store or verify checksum" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "liblzo_interface.h" /* lzo-2.03/src/lzo_ptr.h */ @@ -176,7 +201,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 2 literals that replace the match */ - copy2(ip-3+1,m_pos,pd(op,m_pos)); + copy2(ip-3+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) @@ -186,7 +211,8 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, *litp = (unsigned char)(lit - 3); o_m1_b++; - *op++ = *m_pos++; *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; goto copy_literal_run; } copy_m1: @@ -215,7 +241,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, ) { t = *ip++; /* copy over the 3 literals that replace the match */ - copy3(ip-1-2,m_pos,pd(op,m_pos)); + copy3(ip-1-2, m_pos, pd(op, m_pos)); /* set new length of previous literal run */ lit += 3 + t + 3; *litp = (unsigned char)(lit - 3); @@ -264,7 +290,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, lit += 3; *litp = (unsigned char)((*litp & ~3) | lit); /* copy over the 3 literals that replace the match */ - copy3(ip-3,m_pos,pd(op,m_pos)); + copy3(ip-3, m_pos, pd(op, m_pos)); o_m3_a++; } /* test if a literal run follows */ @@ -275,7 +301,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 3 literals that replace the match */ - copy3(ip-4+1,m_pos,pd(op,m_pos)); + copy3(ip-4+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) @@ -401,7 +427,7 @@ struct globals { #define INIT_G() do { } while (0) //#define G (*ptr_to_globals) //#define INIT_G() do { -// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); +// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); //} while (0) @@ -1051,7 +1077,7 @@ static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_e return xasprintf("%s.lzo", filename); } -static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) return do_lzo_decompress(); diff --git a/release/src/router/busybox/archival/rpm.c b/release/src/router/busybox/archival/rpm.c index 380226f9b9..6757a6cebf 100644 --- a/release/src/router/busybox/archival/rpm.c +++ b/release/src/router/busybox/archival/rpm.c @@ -7,8 +7,20 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define rpm_trivial_usage +//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" +//usage:#define rpm_full_usage "\n\n" +//usage: "Manipulate RPM packages\n" +//usage: "\nCommands:" +//usage: "\n -i Install package" +//usage: "\n -qp Query package" +//usage: "\n -i Show information" +//usage: "\n -l List contents" +//usage: "\n -d List documents" +//usage: "\n -c List config files" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "rpm.h" #define RPM_CHAR_TYPE 1 @@ -224,7 +236,7 @@ static void extract_cpio(int fd, const char *source_rpm) archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ - setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); + setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1); while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; } diff --git a/release/src/router/busybox/archival/rpm2cpio.c b/release/src/router/busybox/archival/rpm2cpio.c index ce8cd2c2cf..f3dfa51594 100644 --- a/release/src/router/busybox/archival/rpm2cpio.c +++ b/release/src/router/busybox/archival/rpm2cpio.c @@ -6,8 +6,14 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define rpm2cpio_trivial_usage +//usage: "package.rpm" +//usage:#define rpm2cpio_full_usage "\n\n" +//usage: "Output a cpio archive of the rpm file" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" #include "rpm.h" enum { rpm_fd = STDIN_FILENO }; @@ -60,54 +66,22 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) /* Skip the main header */ skip_header(); -#if 0 + //if (SEAMLESS_COMPRESSION) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); + /* This works, but doesn't report uncompress errors (they happen in child) */ - setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); + setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1); if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); -#else - /* BLOAT */ - { - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); - - xread(rpm_fd, magic.b16, sizeof(magic.b16[0])); - if (magic.b16[0] == GZIP_MAGIC) { - unpack = unpack_gz_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { - unpack = unpack_bz2_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] != XZ_MAGIC2) - goto no_magic; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(rpm_fd, -6, SEEK_CUR); - unpack = unpack_xz_stream; - } else { - no_magic: - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) - bb_error_msg_and_die("error unpacking"); - } -#endif if (ENABLE_FEATURE_CLEAN_UP) { close(rpm_fd); } - return 0; + if (SEAMLESS_COMPRESSION) { + check_errors_in_children(0); + return bb_got_signal; + } + return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/archival/tar.c b/release/src/router/busybox/archival/tar.c index c0b92615d0..cf972c24c6 100644 --- a/release/src/router/busybox/archival/tar.c +++ b/release/src/router/busybox/archival/tar.c @@ -23,9 +23,28 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +/* TODO: security with -C DESTDIR option can be enhanced. + * Consider tar file created via: + * $ tar cvf bug.tar anything.txt + * $ ln -s /tmp symlink + * $ tar --append -f bug.tar symlink + * $ rm symlink + * $ mkdir symlink + * $ tar --append -f bug.tar symlink/evil.py + * + * This will result in an archive which contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink + * symlink/evil.py + * + * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given. + * This doesn't feel right, and IIRC GNU tar doesn't do that. + */ + #include #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" /* FIXME: Stop using this non-standard feature */ #ifndef FNM_LEADING_DIR # define FNM_LEADING_DIR 0 @@ -245,7 +264,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, 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); + /* users report that files with negative st_mtime cause trouble, so: */ + PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0); /* Enter the user and group names */ safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname)); @@ -297,15 +317,42 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, } 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 + /* header.size field is 12 bytes long */ + /* Does octal-encoded size fit? */ + uoff_t filesize = statbuf->st_size; + if (sizeof(filesize) <= 4 + || filesize <= (uoff_t)0777777777777LL ) { + PUT_OCTAL(header.size, filesize); + } + /* Does base256-encoded size fit? + * It always does unless off_t is wider than 64 bits. + */ + else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS +#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */ + && (filesize <= 0x3fffffffffffffffffffffffLL) +#endif + ) { + /* GNU tar uses "base-256 encoding" for very large numbers. + * Encoding is binary, with highest bit always set as a marker + * and sign in next-highest bit: + * 80 00 .. 00 - zero + * bf ff .. ff - largest positive number + * ff ff .. ff - minus 1 + * c0 00 .. 00 - smallest negative number + */ + char *p8 = header.size + sizeof(header.size); + do { + *--p8 = (uint8_t)filesize; + filesize >>= 8; + } while (p8 != header.size); + *p8 |= 0x80; + } else { bb_error_msg_and_die("can't store file '%s' " "of size %"OFF_FMT"u, 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; @@ -378,17 +425,8 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb DBG("writeFileToTarball('%s')", fileName); - /* 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++; - } + /* Strip leading '/' and such (must be before memorizing hardlink's name) */ + header_name = strip_unsafe_prefix(fileName); if (header_name[0] == '\0') return TRUE; @@ -636,7 +674,7 @@ static llist_t *append_file_list_to_list(llist_t *list) llist_t *newlist = NULL; while (list) { - src_stream = xfopen_for_read(llist_pop(&list)); + src_stream = xfopen_stdin(llist_pop(&list)); while ((line = xmalloc_fgetline(src_stream)) != NULL) { /* kill trailing '/' unless the string is just "/" */ char *cp = last_char_is(line, '/'); @@ -652,60 +690,17 @@ static llist_t *append_file_list_to_list(llist_t *list) # define append_file_list_to_list(x) 0 #endif -#if ENABLE_FEATURE_SEAMLESS_Z -static char FAST_FUNC 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"); - } - - open_transformer(archive_handle->src_fd, unpack_Z_stream, "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 - //usage:#define tar_trivial_usage -//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") -//usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") -//usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " -//usage: IF_FEATURE_TAR_FROM("[-X FILE] ") -//usage: "[-f TARFILE] [-C DIR] [FILE]..." +//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" +//usage: IF_FEATURE_SEAMLESS_Z("Z") +//usage: IF_FEATURE_SEAMLESS_GZ("z") +//usage: IF_FEATURE_SEAMLESS_BZ2("j") +//usage: IF_FEATURE_SEAMLESS_LZMA("a") +//usage: IF_FEATURE_TAR_CREATE("h") +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") +//usage: "vO] " +//usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ") +//usage: "[-f TARFILE] [-C DIR] [FILE]..." //usage:#define tar_full_usage "\n\n" //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") @@ -716,10 +711,12 @@ static void handle_SIGCHLD(int status) //usage: ) //usage: "\n x Extract" //usage: "\n t List" -//usage: "\nOptions:" //usage: "\n f Name of TARFILE ('-' for stdin/out)" //usage: "\n C Change to DIR before operation" //usage: "\n v Verbose" +//usage: IF_FEATURE_SEAMLESS_Z( +//usage: "\n Z (De)compress using compress" +//usage: ) //usage: IF_FEATURE_SEAMLESS_GZ( //usage: "\n z (De)compress using gzip" //usage: ) @@ -729,9 +726,6 @@ static void handle_SIGCHLD(int status) //usage: IF_FEATURE_SEAMLESS_LZMA( //usage: "\n a (De)compress using lzma" //usage: ) -//usage: IF_FEATURE_SEAMLESS_Z( -//usage: "\n Z (De)compress using compress" -//usage: ) //usage: "\n O Extract to stdout" //usage: IF_FEATURE_TAR_CREATE( //usage: "\n h Follow symlinks" @@ -801,6 +795,8 @@ enum { OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite + + OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_COMPRESS), }; #if ENABLE_FEATURE_TAR_LONG_OPTIONS static const char tar_longopts[] ALIGN1 = @@ -859,7 +855,6 @@ static const char tar_longopts[] ALIGN1 = int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tar_main(int argc UNUSED_PARAM, char **argv) { - char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar; archive_handle_t *tar_handle; char *base_dir = NULL; const char *tar_filename = "-"; @@ -882,8 +877,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) /* 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_FEATURE_TAR_FROM("X::T::") // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // cumulative lists for --exclude #endif @@ -956,6 +950,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) putenv((char*)"TAR_FILETYPE=f"); signal(SIGPIPE, SIG_IGN); tar_handle->action_data = data_extract_to_command; + IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());) } if (opt & OPT_KEEP_OLD) @@ -975,18 +970,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->ah_flags |= ARCHIVE_O_TRUNC; } - 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 (opt & OPT_NOPRESERVE_TIME) tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; @@ -1039,7 +1022,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } else { if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY - && get_header_ptr == get_header_tar + && !(opt & OPT_ANY_COMPRESS) ) { tar_handle->src_fd = open_zipped(tar_filename); if (tar_handle->src_fd < 0) @@ -1053,10 +1036,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) 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 + //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); /* Create an archive */ if (opt & OPT_CREATE) { @@ -1073,7 +1055,30 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->reject, zipMode); } - while (get_header_ptr(tar_handle) == EXIT_SUCCESS) + if (opt & OPT_ANY_COMPRESS) { + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_NOMMU(const char *xformer_prog;) + + if (opt & OPT_COMPRESS) + USE_FOR_MMU(xformer = unpack_Z_stream;) + USE_FOR_NOMMU(xformer_prog = "uncompress";) + if (opt & OPT_GZIP) + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + if (opt & OPT_BZIP2) + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + if (opt & OPT_LZMA) + USE_FOR_MMU(xformer = unpack_lzma_stream;) + USE_FOR_NOMMU(xformer_prog = "unlzma";) + + open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); + /* Can't lseek over pipes */ + tar_handle->seek = seek_by_read; + /*tar_handle->offset = 0; - already is */ + } + + while (get_header_tar(tar_handle) == EXIT_SUCCESS) continue; /* Check that every file that should have been extracted was */ @@ -1089,5 +1094,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); + if (SEAMLESS_COMPRESSION || OPT_COMPRESS) { + check_errors_in_children(0); + return bb_got_signal; + } return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/archival/unzip.c b/release/src/router/busybox/archival/unzip.c index 5d62c08cbf..3c76cdafcf 100644 --- a/release/src/router/busybox/archival/unzip.c +++ b/release/src/router/busybox/archival/unzip.c @@ -19,8 +19,20 @@ * Zip64 + other methods */ +//usage:#define unzip_trivial_usage +//usage: "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]" +//usage:#define unzip_full_usage "\n\n" +//usage: "Extract files from ZIP archives\n" +//usage: "\n -l List archive contents (with -q for short form)" +//usage: "\n -n Never overwrite files (default)" +//usage: "\n -o Overwrite" +//usage: "\n -p Send output to stdout" +//usage: "\n -q Quiet" +//usage: "\n -x XLST Exclude these files" +//usage: "\n -d DIR Extract files into DIR" + #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" enum { #if BB_BIG_ENDIAN @@ -223,7 +235,7 @@ 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 */ + xfunc_die(); /* bb_make_directory is noisy */ } free(name); } @@ -237,15 +249,17 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd) bb_copyfd_exact_size(zip_fd, dst_fd, size); } else { /* Method 8 - inflate */ - inflate_unzip_result res; - if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) + transformer_aux_data_t aux; + init_transformer_aux_data(&aux); + aux.bytes_in = zip_header->formatted.cmpsize; + if (inflate_unzip(&aux, zip_fd, dst_fd) < 0) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ - if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { + if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) { bb_error_msg_and_die("crc error"); } /* Validate decompression - size */ - if (zip_header->formatted.ucmpsize != res.bytes_out) { + if (zip_header->formatted.ucmpsize != aux.bytes_out) { /* Don't die. Who knows, maybe len calculation * was botched somewhere. After all, crc matched! */ bb_error_msg("bad length"); @@ -583,7 +597,7 @@ int unzip_main(int argc, char **argv) } unzip_create_leading_dirs(dst_fn); if (bb_make_directory(dst_fn, dir_mode, 0)) { - bb_error_msg_and_die("exiting"); + xfunc_die(); } } else { if (!S_ISDIR(stat_buf.st_mode)) { @@ -607,6 +621,7 @@ int unzip_main(int argc, char **argv) i = 'y'; } else { printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); + fflush_all(); if (!fgets(key_buf, sizeof(key_buf), stdin)) { bb_perror_msg_and_die("can't read input"); } diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/config_base index 373651d2fd..7deec4af6b 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/config_base @@ -1,7 +1,8 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.20.2 +# Mon Jan 21 02:12:11 2013 + # CONFIG_HAVE_DOT_CONFIG=y @@ -62,7 +63,10 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +CONFIG_SYSROOT="" CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" # # Debugging Options @@ -89,8 +93,10 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y @@ -98,7 +104,9 @@ CONFIG_FEATURE_EDITING=y CONFIG_FEATURE_EDITING_MAX_LEN=1024 # CONFIG_FEATURE_EDITING_VI is not set CONFIG_FEATURE_EDITING_HISTORY=50 -# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set CONFIG_FEATURE_EDITING_FANCY_PROMPT=y @@ -106,6 +114,7 @@ CONFIG_FEATURE_EDITING_FANCY_PROMPT=y CONFIG_FEATURE_NON_POSIX_CP=y # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y # CONFIG_MONOTONIC_SYSCALL is not set CONFIG_IOCTL_HEX2STR_ERROR=y # CONFIG_FEATURE_HWIB is not set @@ -136,6 +145,7 @@ CONFIG_FEATURE_SEAMLESS_GZ=y CONFIG_GUNZIP=y CONFIG_GZIP=y # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 # CONFIG_LZOP is not set # CONFIG_LZOP_COMPR_HIGH is not set # CONFIG_RPM2CPIO is not set @@ -158,7 +168,7 @@ CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_LZMA is not set # CONFIG_UNXZ is not set # CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNZIP=y # # Coreutils @@ -169,12 +179,19 @@ CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y # CONFIG_FEATURE_DATE_NANO is not set CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +# CONFIG_FEATURE_TOUCH_SUSV3 is not set CONFIG_TR=y # CONFIG_FEATURE_TR_CLASSES is not set # CONFIG_FEATURE_TR_EQUIV is not set # CONFIG_BASE64 is not set +# CONFIG_WHO is not set +# CONFIG_USERS is not set # CONFIG_CAL is not set # CONFIG_CATV is not set # CONFIG_CHGRP is not set @@ -211,11 +228,8 @@ CONFIG_EXPR_MATH_SUPPORT_64=y # CONFIG_FSYNC is not set CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set # CONFIG_INSTALL is not set # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y @@ -225,7 +239,7 @@ CONFIG_FEATURE_LS_RECURSIVE=y CONFIG_FEATURE_LS_SORTFILES=y CONFIG_FEATURE_LS_TIMESTAMPS=y CONFIG_FEATURE_LS_USERNAME=y -# CONFIG_FEATURE_LS_COLOR is not set +CONFIG_FEATURE_LS_COLOR=y # CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set CONFIG_MD5SUM=y CONFIG_MKDIR=y @@ -279,7 +293,6 @@ CONFIG_USLEEP=y # CONFIG_UUENCODE is not set CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y -# CONFIG_WHO is not set # CONFIG_WHOAMI is not set # CONFIG_YES is not set @@ -308,7 +321,7 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # CONFIG_CHVT is not set # CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set +CONFIG_CLEAR=y # CONFIG_DEALLOCVT is not set # CONFIG_DUMPKMAP is not set # CONFIG_KBD_MODE is not set @@ -360,6 +373,7 @@ CONFIG_FEATURE_VI_MAX_LEN=4096 CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -426,6 +440,7 @@ CONFIG_FEATURE_KILL_DELAY=0 # CONFIG_FEATURE_INITRD is not set CONFIG_INIT_TERMINAL_TYPE="" # CONFIG_MESG is not set +# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set # # Login/Password Management Utilities @@ -450,6 +465,7 @@ CONFIG_LAST_SYSTEM_ID=0 # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set # CONFIG_GETTY is not set CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -514,6 +530,7 @@ CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y # CONFIG_FBSET is not set @@ -528,7 +545,7 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set -# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_GPT_LABEL=y # CONFIG_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set # CONFIG_FLOCK is not set @@ -570,7 +587,7 @@ CONFIG_FEATURE_MOUNT_LABEL=y CONFIG_FEATURE_MOUNT_CIFS=y CONFIG_FEATURE_MOUNT_FLAGS=y CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set # CONFIG_RDEV is not set # CONFIG_READPROFILE is not set @@ -599,7 +616,7 @@ CONFIG_FEATURE_VOLUMEID_EXT=y # CONFIG_FEATURE_VOLUMEID_BTRFS is not set # CONFIG_FEATURE_VOLUMEID_REISERFS is not set CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y # CONFIG_FEATURE_VOLUMEID_JFS is not set # CONFIG_FEATURE_VOLUMEID_XFS is not set CONFIG_FEATURE_VOLUMEID_NTFS=y @@ -619,8 +636,13 @@ CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y # CONFIG_CONSPY is not set # CONFIG_NANDWRITE is not set # CONFIG_NANDDUMP is not set +# CONFIG_SETSERIAL is not set # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set @@ -708,6 +730,7 @@ CONFIG_NC=y # CONFIG_NC_SERVER is not set CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set +# CONFIG_WHOIS is not set # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y @@ -723,8 +746,8 @@ CONFIG_ETHER_WAKE=y # CONFIG_FTPD is not set # CONFIG_FEATURE_FTP_WRITE is not set # CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set +CONFIG_FTPGET=y +CONFIG_FTPPUT=y # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set # CONFIG_HOSTNAME is not set # CONFIG_HTTPD is not set @@ -786,8 +809,8 @@ CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y # CONFIG_FEATURE_NETSTAT_PRG is not set CONFIG_NSLOOKUP=y -# CONFIG_NTPD is not set -# CONFIG_FEATURE_NTPD_SERVER is not set +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y CONFIG_PING=y # CONFIG_PING6 is not set CONFIG_FEATURE_FANCY_PING=y @@ -816,18 +839,23 @@ CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_UDHCPD is not set +# CONFIG_UDHCPC6 is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y # CONFIG_FEATURE_UDHCPC_ARPING is not set -# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_FEATURE_UDHCP_PORT=y CONFIG_UDHCP_DEBUG=0 +CONFIG_FEATURE_UDHCP_8021Q=y # CONFIG_FEATURE_UDHCP_RFC3397 is not set # CONFIG_FEATURE_UDHCP_RFC5969 is not set CONFIG_UDHCPC_DEFAULT_SCRIPT="" CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 +# CONFIG_DHCP6C is not set +# CONFIG_FEATURE_DHCP6_AUTH is not set +# CONFIG_DHCP6RELAY is not set CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" # CONFIG_UDPSVD is not set CONFIG_VCONFIG=y @@ -860,10 +888,15 @@ CONFIG_FEATURE_MIME_CHARSET="" # Process Utilities # # CONFIG_IOSTAT is not set +# CONFIG_LSOF is not set # CONFIG_MPSTAT is not set # CONFIG_PMAP is not set # CONFIG_POWERTOP is not set +# CONFIG_PSTREE is not set +# CONFIG_PWDX is not set # CONFIG_SMEMCAP is not set +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set CONFIG_FREE=y # CONFIG_FUSER is not set CONFIG_KILL=y @@ -877,6 +910,7 @@ CONFIG_PIDOF=y # CONFIG_PKILL is not set CONFIG_PS=y CONFIG_FEATURE_PS_WIDE=y +# CONFIG_FEATURE_PS_LONG is not set # CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set @@ -890,7 +924,6 @@ CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y # CONFIG_FEATURE_TOP_SMP_PROCESS is not set # CONFIG_FEATURE_TOPMEM is not set # CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y CONFIG_WATCH=y # @@ -928,6 +961,7 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # CONFIG_ASH=y CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_IDLE_TIMEOUT is not set # CONFIG_ASH_JOB_CONTROL is not set CONFIG_ASH_ALIAS=y # CONFIG_ASH_GETOPTS is not set @@ -968,6 +1002,7 @@ CONFIG_SH_MATH_SUPPORT=y CONFIG_FEATURE_SH_EXTRA_QUIET=y # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities @@ -976,6 +1011,7 @@ CONFIG_SYSLOGD=y CONFIG_FEATURE_ROTATE_LOGFILE=y CONFIG_FEATURE_REMOTE_LOG=y # CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/config_nc similarity index 92% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/config_nc index 373651d2fd..a6310d00d0 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/config_nc @@ -1,7 +1,8 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.20.2 +# Mon Jan 21 02:12:11 2013 + # CONFIG_HAVE_DOT_CONFIG=y @@ -21,7 +22,6 @@ 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 is not set # CONFIG_FEATURE_COMPRESS_USAGE is not set # CONFIG_FEATURE_INSTALLER is not set # CONFIG_INSTALL_NO_USR is not set @@ -62,7 +62,10 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +CONFIG_SYSROOT="" CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" # # Debugging Options @@ -89,8 +92,10 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y @@ -98,7 +103,9 @@ CONFIG_FEATURE_EDITING=y CONFIG_FEATURE_EDITING_MAX_LEN=1024 # CONFIG_FEATURE_EDITING_VI is not set CONFIG_FEATURE_EDITING_HISTORY=50 -# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set CONFIG_FEATURE_EDITING_FANCY_PROMPT=y @@ -106,6 +113,7 @@ CONFIG_FEATURE_EDITING_FANCY_PROMPT=y CONFIG_FEATURE_NON_POSIX_CP=y # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y # CONFIG_MONOTONIC_SYSCALL is not set CONFIG_IOCTL_HEX2STR_ERROR=y # CONFIG_FEATURE_HWIB is not set @@ -136,6 +144,7 @@ CONFIG_FEATURE_SEAMLESS_GZ=y CONFIG_GUNZIP=y CONFIG_GZIP=y # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 # CONFIG_LZOP is not set # CONFIG_LZOP_COMPR_HIGH is not set # CONFIG_RPM2CPIO is not set @@ -158,7 +167,7 @@ CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_LZMA is not set # CONFIG_UNXZ is not set # CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNZIP=y # # Coreutils @@ -169,12 +178,19 @@ CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y # CONFIG_FEATURE_DATE_NANO is not set CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +# CONFIG_FEATURE_TOUCH_SUSV3 is not set CONFIG_TR=y # CONFIG_FEATURE_TR_CLASSES is not set # CONFIG_FEATURE_TR_EQUIV is not set # CONFIG_BASE64 is not set +# CONFIG_WHO is not set +# CONFIG_USERS is not set # CONFIG_CAL is not set # CONFIG_CATV is not set # CONFIG_CHGRP is not set @@ -208,14 +224,10 @@ CONFIG_EXPR=y CONFIG_EXPR_MATH_SUPPORT_64=y # CONFIG_FALSE is not set # CONFIG_FOLD is not set -# CONFIG_FSYNC is not set CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set # CONFIG_INSTALL is not set # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y @@ -225,16 +237,11 @@ CONFIG_FEATURE_LS_RECURSIVE=y CONFIG_FEATURE_LS_SORTFILES=y CONFIG_FEATURE_LS_TIMESTAMPS=y CONFIG_FEATURE_LS_USERNAME=y -# CONFIG_FEATURE_LS_COLOR is not set -# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set CONFIG_MD5SUM=y CONFIG_MKDIR=y # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set -# CONFIG_MKNOD is not set CONFIG_MV=y # CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set CONFIG_NOHUP=y # CONFIG_OD is not set # CONFIG_PRINTENV is not set @@ -254,7 +261,6 @@ CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y # CONFIG_FEATURE_FLOAT_SLEEP is not set CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set # CONFIG_SPLIT is not set # CONFIG_FEATURE_SPLIT_FANCY is not set # CONFIG_STAT is not set @@ -279,7 +285,6 @@ CONFIG_USLEEP=y # CONFIG_UUENCODE is not set CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y -# CONFIG_WHO is not set # CONFIG_WHOAMI is not set # CONFIG_YES is not set @@ -308,7 +313,6 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # CONFIG_CHVT is not set # CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set # CONFIG_DEALLOCVT is not set # CONFIG_DUMPKMAP is not set # CONFIG_KBD_MODE is not set @@ -318,7 +322,6 @@ CONFIG_FEATURE_HUMAN_READABLE=y # CONFIG_RESET is not set # CONFIG_RESIZE is not set # CONFIG_FEATURE_RESIZE_PRINT is not set -# CONFIG_SETCONSOLE is not set # CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set # CONFIG_SETFONT is not set # CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set @@ -360,6 +363,7 @@ CONFIG_FEATURE_VI_MAX_LEN=4096 CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -426,6 +430,7 @@ CONFIG_FEATURE_KILL_DELAY=0 # CONFIG_FEATURE_INITRD is not set CONFIG_INIT_TERMINAL_TYPE="" # CONFIG_MESG is not set +# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set # # Login/Password Management Utilities @@ -450,6 +455,7 @@ CONFIG_LAST_SYSTEM_ID=0 # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set # CONFIG_GETTY is not set CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -468,12 +474,8 @@ CONFIG_LOGIN=y # Linux Ext2 FS Progs # # CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set # CONFIG_FSCK is not set # CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set -# CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set # # Linux Module Utilities @@ -485,7 +487,6 @@ CONFIG_LOGIN=y CONFIG_INSMOD=y CONFIG_RMMOD=y CONFIG_LSMOD=y -# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set CONFIG_MODPROBE=y # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set @@ -493,7 +494,6 @@ CONFIG_MODPROBE=y # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set @@ -514,6 +514,7 @@ CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y # CONFIG_FBSET is not set @@ -521,24 +522,19 @@ CONFIG_FEATURE_DMESG_PRETTY=y # CONFIG_FEATURE_FBSET_READMODE is not set # CONFIG_FDFLUSH is not set # CONFIG_FDFORMAT is not set -# CONFIG_FDISK is not set -CONFIG_FDISK_SUPPORT_LARGE_DISKS=y -# CONFIG_FEATURE_FDISK_WRITABLE is not set # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set -# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_GPT_LABEL=y # CONFIG_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set # CONFIG_FREERAMDISK is not set # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set # CONFIG_MKFS_MINIX is not set # CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set -# CONFIG_MKFS_VFAT is not set # CONFIG_GETOPT is not set # CONFIG_FEATURE_GETOPT_LONG is not set # CONFIG_HEXDUMP is not set @@ -551,14 +547,12 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_IPCS is not set # CONFIG_LOSETUP is not set # CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set # CONFIG_MDEV is not set # CONFIG_FEATURE_MDEV_CONF is not set # CONFIG_FEATURE_MDEV_RENAME is not set # CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set # CONFIG_FEATURE_MDEV_EXEC is not set # CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -# CONFIG_MKSWAP is not set CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y CONFIG_MOUNT=y @@ -570,7 +564,7 @@ CONFIG_FEATURE_MOUNT_LABEL=y CONFIG_FEATURE_MOUNT_CIFS=y CONFIG_FEATURE_MOUNT_FLAGS=y CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set # CONFIG_RDEV is not set # CONFIG_READPROFILE is not set @@ -599,7 +593,7 @@ CONFIG_FEATURE_VOLUMEID_EXT=y # CONFIG_FEATURE_VOLUMEID_BTRFS is not set # CONFIG_FEATURE_VOLUMEID_REISERFS is not set CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y # CONFIG_FEATURE_VOLUMEID_JFS is not set # CONFIG_FEATURE_VOLUMEID_XFS is not set CONFIG_FEATURE_VOLUMEID_NTFS=y @@ -619,8 +613,13 @@ CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y # CONFIG_CONSPY is not set # CONFIG_NANDWRITE is not set # CONFIG_NANDDUMP is not set +# CONFIG_SETSERIAL is not set # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set @@ -647,7 +646,6 @@ CONFIG_FEATURE_CROND_DIR="/var/spool/cron" # CONFIG_DEVFSD_MODLOAD is not set # CONFIG_DEVFSD_FG_NP is not set # CONFIG_DEVFSD_VERBOSE is not set -CONFIG_FEATURE_DEVFS=y # CONFIG_DEVMEM is not set # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set @@ -708,7 +706,7 @@ CONFIG_NC=y # CONFIG_NC_SERVER is not set CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set -# CONFIG_FEATURE_IPV6 is not set +# CONFIG_WHOIS is not set # CONFIG_FEATURE_UNIX_LOCAL is not set CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set @@ -723,8 +721,6 @@ CONFIG_ETHER_WAKE=y # CONFIG_FTPD is not set # CONFIG_FEATURE_FTP_WRITE is not set # CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set # CONFIG_HOSTNAME is not set # CONFIG_HTTPD is not set @@ -786,10 +782,9 @@ CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y # CONFIG_FEATURE_NETSTAT_PRG is not set CONFIG_NSLOOKUP=y -# CONFIG_NTPD is not set -# CONFIG_FEATURE_NTPD_SERVER is not set +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y CONFIG_PING=y -# CONFIG_PING6 is not set CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y @@ -809,30 +804,32 @@ CONFIG_FEATURE_TELNETD_STANDALONE=y # CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set # CONFIG_TFTP_DEBUG is not set CONFIG_TRACEROUTE=y -# CONFIG_TRACEROUTE6 is not set CONFIG_FEATURE_TRACEROUTE_VERBOSE=y CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_UDHCPD is not set +# CONFIG_UDHCPC6 is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y # CONFIG_FEATURE_UDHCPC_ARPING is not set -# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_FEATURE_UDHCP_PORT=y CONFIG_UDHCP_DEBUG=0 +CONFIG_FEATURE_UDHCP_8021Q=y # CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set CONFIG_UDHCPC_DEFAULT_SCRIPT="" CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 +# CONFIG_DHCP6C is not set +# CONFIG_FEATURE_DHCP6_AUTH is not set +# CONFIG_DHCP6RELAY is not set CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" # CONFIG_UDPSVD is not set CONFIG_VCONFIG=y CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set CONFIG_FEATURE_WGET_TIMEOUT=y @@ -854,16 +851,20 @@ CONFIG_FEATURE_MIME_CHARSET="" # CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set # CONFIG_REFORMIME is not set # CONFIG_FEATURE_REFORMIME_COMPAT is not set -# CONFIG_SENDMAIL is not set # # Process Utilities # # CONFIG_IOSTAT is not set +# CONFIG_LSOF is not set # CONFIG_MPSTAT is not set # CONFIG_PMAP is not set # CONFIG_POWERTOP is not set +# CONFIG_PSTREE is not set +# CONFIG_PWDX is not set # CONFIG_SMEMCAP is not set +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set CONFIG_FREE=y # CONFIG_FUSER is not set CONFIG_KILL=y @@ -877,6 +878,7 @@ CONFIG_PIDOF=y # CONFIG_PKILL is not set CONFIG_PS=y CONFIG_FEATURE_PS_WIDE=y +# CONFIG_FEATURE_PS_LONG is not set # CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set @@ -890,7 +892,6 @@ CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y # CONFIG_FEATURE_TOP_SMP_PROCESS is not set # CONFIG_FEATURE_TOPMEM is not set # CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y CONFIG_WATCH=y # @@ -928,6 +929,7 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # CONFIG_ASH=y CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_IDLE_TIMEOUT is not set # CONFIG_ASH_JOB_CONTROL is not set CONFIG_ASH_ALIAS=y # CONFIG_ASH_GETOPTS is not set @@ -968,6 +970,7 @@ CONFIG_SH_MATH_SUPPORT=y CONFIG_FEATURE_SH_EXTRA_QUIET=y # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities @@ -976,7 +979,7 @@ CONFIG_SYSLOGD=y CONFIG_FEATURE_ROTATE_LOGFILE=y CONFIG_FEATURE_REMOTE_LOG=y # CONFIG_FEATURE_SYSLOGD_DUP is not set -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +# CONFIG_FEATURE_SYSLOGD_CFG is not set # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 # CONFIG_LOGREAD is not set @@ -984,3 +987,35 @@ CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 CONFIG_KLOGD=y CONFIG_FEATURE_KLOGD_KLOGCTL=y CONFIG_LOGGER=y +# CONFIG_FEATURE_2_4_MODULES is not set +CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y +# CONFIG_FEATURE_DEVFS is not set +CONFIG_MKNOD=y +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=512 +CONFIG_SENDMAIL=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_FTPPUT=y +CONFIG_FTPGET=y +CONFIG_CLEAR=y +CONFIG_NICE=y +CONFIG_SETCONSOLE=y +CONFIG_MKFIFO=y +CONFIG_E2FSCK=y +CONFIG_MKE2FS=y +CONFIG_FDISK=y +CONFIG_FEATURE_FDISK_WRITABLE=y +CONFIG_MKFS_VFAT=y +CONFIG_MKSWAP=y +CONFIG_FLOCK=y +CONFIG_FSYNC=y +CONFIG_TUNE2FS=y +CONFIG_E2LABEL=y +CONFIG_LSUSB=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_IPV6=y +CONFIG_PING6=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_UDHCP_RFC5969=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y diff --git a/release/src/router/busybox/configs/TEST_nommu_defconfig b/release/src/router/busybox/configs/TEST_nommu_defconfig new file mode 100644 index 0000000000..15e12b1d26 --- /dev/null +++ b/release/src/router/busybox/configs/TEST_nommu_defconfig @@ -0,0 +1,926 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.16.0 +# Wed Jan 27 21:01:26 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +CONFIG_EXTRA_COMPAT=y +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +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_UNICODE_SUPPORT is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_LONG_OPTS=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_PIE 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 +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# 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_SMALL=1 +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_EDITING_ASK_TERMINAL=y +CONFIG_FEATURE_NON_POSIX_CP=y +CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y +CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_MONOTONIC_SYSCALL=y +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY=y +CONFIG_GUNZIP=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=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_FEATURE_TAR_NOPRESERVE_TIME=y +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAL=y +CONFIG_CAT=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=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_FSYNC=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_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_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_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, sha256sum, sha512sum +# +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_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=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_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=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_FEATURE_FIND_LINKS=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_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_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_MESG=y + +# +# Login/Password Management Utilities +# +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=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_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +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_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +CONFIG_FEATURE_INSMOD_TRY_MMAP=y +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +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_EXT2=y +CONFIG_MKFS_MINIX=y + +# +# Minix filesystem support +# +CONFIG_FEATURE_MINIX2=y +CONFIG_MKFS_REISER=y +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=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_LSPCI=y +CONFIG_LSUSB=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_UUID=y +CONFIG_MORE=y +CONFIG_FEATURE_USE_TERMIOS=y +CONFIG_VOLUMEID=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=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_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +CONFIG_SETARCH=y +CONFIG_SWAPONOFF=y +CONFIG_FEATURE_SWAPON_PRI=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_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +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_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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_DEVMEM=y +CONFIG_EJECT=y +CONFIG_FEATURE_EJECT_SCSI=y +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +CONFIG_IONICE=y +CONFIG_INOTIFYD=y +CONFIG_LAST=y +CONFIG_FEATURE_LAST_SMALL=y +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=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_TASKSET=y +CONFIG_FEATURE_TASKSET_FANCY=y +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WALL=y +CONFIG_WATCHDOG=y + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +CONFIG_FEATURE_UNIX_LOCAL=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_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=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_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=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_IFPLUGD=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_FEATURE_NETSTAT_PRG=y +CONFIG_NSLOOKUP=y +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_PSCAN=y +CONFIG_ROUTE=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_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +CONFIG_TFTP_DEBUG=y +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y +CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +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_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +CONFIG_UDPSVD=y + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=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_ADDITIONAL_COLUMNS=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_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_UPTIME=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +CONFIG_FEATURE_RUNSVDIR_LOG=y +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +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 + +# +# Shells +# +# CONFIG_FEATURE_SH_IS_ASH is not set +CONFIG_FEATURE_SH_IS_HUSH=y +# CONFIG_FEATURE_SH_IS_NONE is not set +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF 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_BASH_COMPAT=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_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_MSH=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +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 diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/TEST_noprintf_defconfig similarity index 75% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/TEST_noprintf_defconfig index 373651d2fd..f4338df711 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/TEST_noprintf_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.17.0.git +# Mon Jun 7 13:37:55 2010 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,56 +12,54 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set -# CONFIG_EXTRA_COMPAT is not set -# CONFIG_INCLUDE_SUSv2 is not set +CONFIG_DESKTOP=y +CONFIG_EXTRA_COMPAT=y +CONFIG_INCLUDE_SUSv2=y # CONFIG_USE_PORTABLE_CODE is not set -CONFIG_PLATFORM_LINUX=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 is not set +CONFIG_FEATURE_VERBOSE_USAGE=y # CONFIG_FEATURE_COMPRESS_USAGE is not set # CONFIG_FEATURE_INSTALLER is not set -# CONFIG_INSTALL_NO_USR is not set # CONFIG_LOCALE_SUPPORT is not set CONFIG_UNICODE_SUPPORT=y # CONFIG_UNICODE_USING_LOCALE is not set -# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set -CONFIG_SUBST_WCHAR=0 -CONFIG_LAST_SUPPORTED_WCHAR=0 -# CONFIG_UNICODE_COMBINING_WCHARS is not set -# CONFIG_UNICODE_WIDE_WCHARS is not set -# CONFIG_UNICODE_BIDI_SUPPORT is not set +CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=65535 +CONFIG_UNICODE_COMBINING_WCHARS=y +CONFIG_UNICODE_WIDE_WCHARS=y +CONFIG_UNICODE_BIDI_SUPPORT=y # CONFIG_UNICODE_NEUTRAL_TABLE is not set -# CONFIG_UNICODE_PRESERVE_BROKEN is not set +CONFIG_UNICODE_PRESERVE_BROKEN=y CONFIG_LONG_OPTS=y CONFIG_FEATURE_DEVPTS=y # CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_WTMP is not set -# CONFIG_FEATURE_UTMP is not set +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y CONFIG_FEATURE_PIDFILE=y -CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_SUID is not set # CONFIG_FEATURE_SUID_CONFIG is not set # CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set # CONFIG_FEATURE_PREFER_APPLETS is not set CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" -CONFIG_FEATURE_SYSLOG=y +# CONFIG_FEATURE_SYSLOG is not set # CONFIG_FEATURE_HAVE_RPC is not set # # Build Options # -# CONFIG_STATIC is not set +CONFIG_STATIC=y # CONFIG_PIE is not set # CONFIG_NOMMU is not set # CONFIG_BUILD_LIBBUSYBOX is not set # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +CONFIG_CROSS_COMPILER_PREFIX="i486-linux-uclibc-" CONFIG_EXTRA_CFLAGS="" # @@ -69,14 +67,15 @@ CONFIG_EXTRA_CFLAGS="" # # CONFIG_DEBUG is not set # CONFIG_DEBUG_PESSIMIZE is not set -# CONFIG_WERROR is not set +CONFIG_WERROR=y CONFIG_NO_DEBUG_LIB=y # CONFIG_DMALLOC is not set # CONFIG_EFENCE is not set # -# Installation Options ("make install" behavior) +# 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 @@ -90,25 +89,24 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set -CONFIG_FEATURE_USE_TERMIOS=y CONFIG_FEATURE_EDITING=y CONFIG_FEATURE_EDITING_MAX_LEN=1024 -# CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 +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 is not set +CONFIG_FEATURE_USERNAME_COMPLETION=y CONFIG_FEATURE_EDITING_FANCY_PROMPT=y -# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +CONFIG_FEATURE_EDITING_ASK_TERMINAL=y CONFIG_FEATURE_NON_POSIX_CP=y # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set -CONFIG_FEATURE_COPYBUF_KB=4 -# CONFIG_MONOTONIC_SYSCALL is not set -CONFIG_IOCTL_HEX2STR_ERROR=y -# CONFIG_FEATURE_HWIB is not set +CONFIG_FEATURE_COPYBUF_KB=64 +CONFIG_MONOTONIC_SYSCALL=y +# CONFIG_IOCTL_HEX2STR_ERROR is not set +CONFIG_FEATURE_HWIB=y # # Applets @@ -117,11 +115,11 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y -# CONFIG_FEATURE_SEAMLESS_Z is not set +CONFIG_FEATURE_SEAMLESS_Z=y # CONFIG_AR is not set # CONFIG_FEATURE_AR_LONG_FILENAMES is not set # CONFIG_FEATURE_AR_CREATE is not set @@ -133,22 +131,21 @@ CONFIG_FEATURE_SEAMLESS_GZ=y # CONFIG_DPKG is not set # CONFIG_DPKG_DEB is not set # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set -CONFIG_GUNZIP=y -CONFIG_GZIP=y +# CONFIG_GUNZIP is not set +# CONFIG_GZIP is not set # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set # CONFIG_LZOP is not set # CONFIG_LZOP_COMPR_HIGH is not set # CONFIG_RPM2CPIO is not set # CONFIG_RPM is not set -CONFIG_TAR=y -CONFIG_FEATURE_TAR_CREATE=y +# CONFIG_TAR is not set +# CONFIG_FEATURE_TAR_CREATE is not set # CONFIG_FEATURE_TAR_AUTODETECT is not set -CONFIG_FEATURE_TAR_FROM=y -CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +# CONFIG_FEATURE_TAR_FROM is not set +# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set -CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set -# CONFIG_FEATURE_TAR_TO_COMMAND is not set # CONFIG_FEATURE_TAR_UNAME_GNAME is not set # CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set # CONFIG_FEATURE_TAR_SELINUX is not set @@ -164,96 +161,94 @@ CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # Coreutils # CONFIG_BASENAME=y -CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_CAT is not set +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y -CONFIG_TEST=y -CONFIG_FEATURE_TEST_64=y -CONFIG_TR=y +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_TEST is not set +# CONFIG_FEATURE_TEST_64 is not set +# CONFIG_TR is not set # CONFIG_FEATURE_TR_CLASSES is not set # CONFIG_FEATURE_TR_EQUIV is not set -# CONFIG_BASE64 is not set # CONFIG_CAL is not set # CONFIG_CATV is not set # CONFIG_CHGRP is not set -CONFIG_CHMOD=y -CONFIG_CHOWN=y +# CONFIG_CHMOD is not set +# CONFIG_CHOWN is not set # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set -CONFIG_CHROOT=y +# CONFIG_CHROOT is not set # CONFIG_CKSUM is not set # CONFIG_COMM is not set -CONFIG_CP=y +# CONFIG_CP is not set # CONFIG_FEATURE_CP_LONG_OPTIONS is not set -CONFIG_CUT=y -CONFIG_DD=y -CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +# CONFIG_CUT is not set +# CONFIG_DD is not set +# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set -CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_FEATURE_DD_IBS_OBS is not set +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set -CONFIG_DIRNAME=y +# CONFIG_DIRNAME is not set # CONFIG_DOS2UNIX is not set # CONFIG_UNIX2DOS is not set -CONFIG_DU=y -CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y -CONFIG_ECHO=y -CONFIG_FEATURE_FANCY_ECHO=y -CONFIG_ENV=y +# CONFIG_DU is not set +# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set +# CONFIG_ECHO is not set +# CONFIG_FEATURE_FANCY_ECHO is not set +# CONFIG_ENV is not set # CONFIG_FEATURE_ENV_LONG_OPTIONS is not set # CONFIG_EXPAND is not set # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set -CONFIG_EXPR=y -CONFIG_EXPR_MATH_SUPPORT_64=y -# CONFIG_FALSE is not set +# CONFIG_EXPR is not set +# CONFIG_EXPR_MATH_SUPPORT_64 is not set +CONFIG_FALSE=y # CONFIG_FOLD is not set # CONFIG_FSYNC is not set -CONFIG_HEAD=y -CONFIG_FEATURE_FANCY_HEAD=y +# CONFIG_HEAD is not set +# CONFIG_FEATURE_FANCY_HEAD is not set # CONFIG_HOSTID is not set # CONFIG_ID is not set # CONFIG_INSTALL is not set # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set -CONFIG_LN=y +# CONFIG_LN is not set # CONFIG_LOGNAME is not set -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_LS is not set +# CONFIG_FEATURE_LS_FILETYPES is not set +# CONFIG_FEATURE_LS_FOLLOWLINKS is not set +# CONFIG_FEATURE_LS_RECURSIVE is not set +# CONFIG_FEATURE_LS_SORTFILES is not set +# CONFIG_FEATURE_LS_TIMESTAMPS is not set +# CONFIG_FEATURE_LS_USERNAME is not set # CONFIG_FEATURE_LS_COLOR is not set # CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set -CONFIG_MD5SUM=y -CONFIG_MKDIR=y +# CONFIG_MD5SUM is not set +# CONFIG_MKDIR is not set # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set # CONFIG_MKFIFO is not set # CONFIG_MKNOD is not set -CONFIG_MV=y +# CONFIG_MV is not set # CONFIG_FEATURE_MV_LONG_OPTIONS is not set # CONFIG_NICE is not set -CONFIG_NOHUP=y +# CONFIG_NOHUP is not set # CONFIG_OD is not set # CONFIG_PRINTENV is not set -CONFIG_PRINTF=y -CONFIG_PWD=y +# CONFIG_PRINTF is not set +# CONFIG_PWD is not set # CONFIG_READLINK is not set # CONFIG_FEATURE_READLINK_FOLLOW is not set # CONFIG_REALPATH is not set -CONFIG_RM=y -CONFIG_RMDIR=y +# CONFIG_RM is not set +# CONFIG_RMDIR is not set # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set # CONFIG_SEQ is not set # CONFIG_SHA1SUM is not set # CONFIG_SHA256SUM is not set # CONFIG_SHA512SUM is not set -CONFIG_SLEEP=y -CONFIG_FEATURE_FANCY_SLEEP=y +# CONFIG_SLEEP is not set +# CONFIG_FEATURE_FANCY_SLEEP is not set # CONFIG_FEATURE_FLOAT_SLEEP is not set -CONFIG_SORT=y +# CONFIG_SORT is not set # CONFIG_FEATURE_SORT_BIG is not set # CONFIG_SPLIT is not set # CONFIG_FEATURE_SPLIT_FANCY is not set @@ -261,46 +256,30 @@ CONFIG_SORT=y # CONFIG_FEATURE_STAT_FORMAT is not set # CONFIG_STTY is not set # CONFIG_SUM is not set -CONFIG_SYNC=y +# CONFIG_SYNC is not set # CONFIG_TAC is not set -CONFIG_TAIL=y -CONFIG_FEATURE_FANCY_TAIL=y +# CONFIG_TAIL is not set +# CONFIG_FEATURE_FANCY_TAIL is not set # CONFIG_TEE is not set # CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +# CONFIG_TOUCH is not set CONFIG_TRUE=y # CONFIG_TTY is not set -CONFIG_UNAME=y +# CONFIG_UNAME is not set # CONFIG_UNEXPAND is not set # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set # CONFIG_UNIQ is not set -CONFIG_USLEEP=y +# CONFIG_USLEEP is not set # CONFIG_UUDECODE is not set # CONFIG_UUENCODE is not set -CONFIG_WC=y -CONFIG_FEATURE_WC_LARGE=y +# CONFIG_WC is not set +# CONFIG_FEATURE_WC_LARGE is not set # CONFIG_WHO is not set # CONFIG_WHOAMI is not set # CONFIG_YES is not set - -# -# 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, sha256sum, sha512sum -# +# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set +# CONFIG_FEATURE_AUTOWIDTH is not set +# CONFIG_FEATURE_HUMAN_READABLE is not set # CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set # @@ -333,48 +312,48 @@ CONFIG_DEFAULT_SETFONT_DIR="" # Debian Utilities # # CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set +CONFIG_PIPE_PROGRESS=y # CONFIG_RUN_PARTS is not set # CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set # CONFIG_FEATURE_RUN_PARTS_FANCY is not set # CONFIG_START_STOP_DAEMON is not set # CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set # CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set -CONFIG_WHICH=y +# CONFIG_WHICH is not set # # Editors # -# CONFIG_PATCH is not set -CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y -CONFIG_CMP=y +# CONFIG_AWK is not set +# CONFIG_FEATURE_AWK_LIBM is not set +# CONFIG_CMP is not set # CONFIG_DIFF is not set # CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set # CONFIG_FEATURE_DIFF_DIR is not set # CONFIG_ED is not set -CONFIG_SED=y -CONFIG_VI=y -CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_PATCH is not set +# CONFIG_SED is not set +# CONFIG_VI is not set +CONFIG_FEATURE_VI_MAX_LEN=0 # CONFIG_FEATURE_VI_8BIT is not set -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_ASK_TERMINAL=y +# CONFIG_FEATURE_VI_COLON is not set +# CONFIG_FEATURE_VI_YANKMARK is not set +# CONFIG_FEATURE_VI_SEARCH is not set +# CONFIG_FEATURE_VI_USE_SIGNALS is not set +# CONFIG_FEATURE_VI_DOT_CMD is not set +# CONFIG_FEATURE_VI_READONLY is not set +# CONFIG_FEATURE_VI_SETOPTS is not set +# CONFIG_FEATURE_VI_SET is not set +# CONFIG_FEATURE_VI_WIN_RESIZE is not set +# CONFIG_FEATURE_VI_ASK_TERMINAL is not set # CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set -CONFIG_FEATURE_ALLOW_EXEC=y +# CONFIG_FEATURE_ALLOW_EXEC is not set # # Finding Utilities # -CONFIG_FIND=y -CONFIG_FEATURE_FIND_PRINT0=y +# CONFIG_FIND is not set +# CONFIG_FEATURE_FIND_PRINT0 is not set # CONFIG_FEATURE_FIND_MTIME is not set # CONFIG_FEATURE_FIND_MMIN is not set # CONFIG_FEATURE_FIND_PERM is not set @@ -383,10 +362,10 @@ CONFIG_FEATURE_FIND_PRINT0=y # CONFIG_FEATURE_FIND_MAXDEPTH is not set # CONFIG_FEATURE_FIND_NEWER is not set # CONFIG_FEATURE_FIND_INUM is not set -CONFIG_FEATURE_FIND_EXEC=y +# CONFIG_FEATURE_FIND_EXEC is not set # CONFIG_FEATURE_FIND_USER is not set # CONFIG_FEATURE_FIND_GROUP is not set -CONFIG_FEATURE_FIND_NOT=y +# CONFIG_FEATURE_FIND_NOT is not set # CONFIG_FEATURE_FIND_DEPTH is not set # CONFIG_FEATURE_FIND_PAREN is not set # CONFIG_FEATURE_FIND_SIZE is not set @@ -396,10 +375,10 @@ CONFIG_FEATURE_FIND_NOT=y # CONFIG_FEATURE_FIND_REGEX is not set # CONFIG_FEATURE_FIND_CONTEXT is not set # CONFIG_FEATURE_FIND_LINKS is not set -CONFIG_GREP=y -CONFIG_FEATURE_GREP_EGREP_ALIAS=y -CONFIG_FEATURE_GREP_FGREP_ALIAS=y -CONFIG_FEATURE_GREP_CONTEXT=y +# CONFIG_GREP is not set +# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_CONTEXT is not set # CONFIG_XARGS is not set # CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set # CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set @@ -409,12 +388,6 @@ CONFIG_FEATURE_GREP_CONTEXT=y # # Init Utilities # -# CONFIG_BOOTCHARTD is not set -# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set -# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set -# CONFIG_HALT is not set -# CONFIG_FEATURE_CALL_TELINIT is not set -CONFIG_TELINIT_PATH="" # CONFIG_INIT is not set # CONFIG_FEATURE_USE_INITTAB is not set # CONFIG_FEATURE_KILL_REMOVED is not set @@ -424,32 +397,33 @@ CONFIG_FEATURE_KILL_DELAY=0 # CONFIG_FEATURE_EXTRA_QUIET is not set # CONFIG_FEATURE_INIT_COREDUMPS is not set # CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" +# CONFIG_HALT is not set +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" # CONFIG_MESG is not set +# CONFIG_BOOTCHARTD is not set # # Login/Password Management Utilities # -# CONFIG_ADD_SHELL is not set -# CONFIG_REMOVE_SHELL is not set -CONFIG_FEATURE_SHADOWPASSWDS=y -CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set # CONFIG_USE_BB_CRYPT is not set # CONFIG_USE_BB_CRYPT_SHA is not set -# CONFIG_ADDUSER is not set -# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set -# CONFIG_FEATURE_CHECK_NAMES is not set -CONFIG_FIRST_SYSTEM_ID=0 -CONFIG_LAST_SYSTEM_ID=0 # CONFIG_ADDGROUP is not set # CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set # CONFIG_FEATURE_ADDUSER_TO_GROUP is not set -# CONFIG_DELUSER is not set # CONFIG_DELGROUP is not set # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_DELUSER is not set # CONFIG_GETTY is not set -CONFIG_LOGIN=y +# CONFIG_LOGIN is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -468,12 +442,9 @@ CONFIG_LOGIN=y # Linux Ext2 FS Progs # # CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set # CONFIG_FSCK is not set # CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set # CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set # # Linux Module Utilities @@ -482,40 +453,38 @@ CONFIG_LOGIN=y # CONFIG_MODPROBE_SMALL is not set # CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set # CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" # # Linux System Utilities # -# CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set -CONFIG_BLKID=y -CONFIG_DMESG=y -CONFIG_FEATURE_DMESG_PRETTY=y +# CONFIG_BLKID is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set # CONFIG_FBSET is not set # CONFIG_FEATURE_FBSET_FANCY is not set # CONFIG_FEATURE_FBSET_READMODE is not set @@ -528,7 +497,6 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set -# CONFIG_FEATURE_GPT_LABEL is not set # CONFIG_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set # CONFIG_FLOCK is not set @@ -559,71 +527,58 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_MDEV_EXEC is not set # CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set # CONFIG_MKSWAP is not set -CONFIG_FEATURE_MKSWAP_UUID=y -CONFIG_MORE=y -CONFIG_MOUNT=y -# CONFIG_FEATURE_MOUNT_FAKE is not set -# CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y -# CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y -# CONFIG_RDATE is not set -# CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set -# CONFIG_RTCWAKE is not set -# CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set -# CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y -# CONFIG_FEATURE_SWAPON_PRI is not set -# CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y -# CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y -# CONFIG_FEATURE_MTAB_SUPPORT is not set +# CONFIG_FEATURE_MKSWAP_UUID is not set +# CONFIG_MORE is not set +# CONFIG_FEATURE_USE_TERMIOS is not set CONFIG_VOLUMEID=y - -# -# Filesystem/Volume identification -# -CONFIG_FEATURE_VOLUMEID_EXT=y +# CONFIG_FEATURE_VOLUMEID_EXT is not set # CONFIG_FEATURE_VOLUMEID_BTRFS is not set # CONFIG_FEATURE_VOLUMEID_REISERFS is not set -CONFIG_FEATURE_VOLUMEID_FAT=y +# CONFIG_FEATURE_VOLUMEID_FAT is not set # CONFIG_FEATURE_VOLUMEID_HFS is not set # CONFIG_FEATURE_VOLUMEID_JFS is not set # CONFIG_FEATURE_VOLUMEID_XFS is not set -CONFIG_FEATURE_VOLUMEID_NTFS=y +# CONFIG_FEATURE_VOLUMEID_NTFS is not set # CONFIG_FEATURE_VOLUMEID_ISO9660 is not set # CONFIG_FEATURE_VOLUMEID_UDF is not set # CONFIG_FEATURE_VOLUMEID_LUKS is not set -CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set # CONFIG_FEATURE_VOLUMEID_CRAMFS is not set # CONFIG_FEATURE_VOLUMEID_ROMFS is not set # CONFIG_FEATURE_VOLUMEID_SYSV is not set # CONFIG_FEATURE_VOLUMEID_OCFS2 is not set # CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_RDEV is not set +# CONFIG_READPROFILE is not set +# CONFIG_RTCWAKE is not set +# CONFIG_SCRIPT is not set +# CONFIG_SCRIPTREPLAY is not set +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +# CONFIG_SWITCH_ROOT is not set +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set # # Miscellaneous Utilities # -# CONFIG_CONSPY is not set -# CONFIG_NANDWRITE is not set -# CONFIG_NANDDUMP is not set -# CONFIG_UBIATTACH is not set -# CONFIG_UBIDETACH is not set # CONFIG_ADJTIMEX is not set -# CONFIG_BBCONFIG is not set -# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BBCONFIG=y # CONFIG_BEEP is not set CONFIG_FEATURE_BEEP_FREQ=0 CONFIG_FEATURE_BEEP_LENGTH_MS=0 @@ -636,10 +591,10 @@ CONFIG_FEATURE_BEEP_LENGTH_MS=0 # CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set # CONFIG_FEATURE_CHAT_CLR_ABORT is not set # CONFIG_CHRT is not set -CONFIG_CROND=y +# CONFIG_CROND is not set # CONFIG_FEATURE_CROND_D is not set # CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set -CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_FEATURE_CROND_DIR="" # CONFIG_CRONTAB is not set # CONFIG_DC is not set # CONFIG_FEATURE_DC_LIBM is not set @@ -647,7 +602,7 @@ CONFIG_FEATURE_CROND_DIR="/var/spool/cron" # CONFIG_DEVFSD_MODLOAD is not set # CONFIG_DEVFSD_FG_NP is not set # CONFIG_DEVFSD_VERBOSE is not set -CONFIG_FEATURE_DEVFS=y +# CONFIG_FEATURE_DEVFS is not set # CONFIG_DEVMEM is not set # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set @@ -661,8 +616,8 @@ CONFIG_FEATURE_DEVFS=y # CONFIG_LAST is not set # CONFIG_FEATURE_LAST_SMALL is not set # CONFIG_FEATURE_LAST_FANCY is not set -CONFIG_LESS=y -CONFIG_FEATURE_LESS_MAXLINES=9999999 +# CONFIG_LESS is not set +CONFIG_FEATURE_LESS_MAXLINES=0 # CONFIG_FEATURE_LESS_BRACKETS is not set # CONFIG_FEATURE_LESS_FLAGS is not set # CONFIG_FEATURE_LESS_MARKS is not set @@ -690,7 +645,7 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 # CONFIG_RUNLEVEL is not set # CONFIG_RX is not set # CONFIG_SETSID is not set -CONFIG_STRINGS=y +# CONFIG_STRINGS is not set # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set # CONFIG_TIME is not set @@ -703,22 +658,17 @@ CONFIG_STRINGS=y # # Networking Utilities # -# CONFIG_NBDCLIENT is not set -CONFIG_NC=y -# CONFIG_NC_SERVER is not set -CONFIG_NC_EXTRA=y -# CONFIG_NC_110_COMPAT is not set # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set -CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set -CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARP is not set +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set # CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y +# CONFIG_ETHER_WAKE is not set # CONFIG_FAKEIDENTD is not set # CONFIG_FTPD is not set # CONFIG_FEATURE_FTP_WRITE is not set @@ -739,13 +689,12 @@ CONFIG_ETHER_WAKE=y # CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set # CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set # CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set -CONFIG_IFCONFIG=y -CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set # CONFIG_FEATURE_IFCONFIG_SLIP is not set # CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set -CONFIG_FEATURE_IFCONFIG_HW=y -CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set # CONFIG_IFUPDOWN is not set @@ -782,24 +731,27 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set # CONFIG_NAMEIF is not set # CONFIG_FEATURE_NAMEIF_EXTENDED is not set -CONFIG_NETSTAT=y -CONFIG_FEATURE_NETSTAT_WIDE=y +# CONFIG_NC is not set +# CONFIG_NC_SERVER is not set +# CONFIG_NC_EXTRA is not set +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set # CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y +# CONFIG_PING is not set # CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y -CONFIG_PSCAN=y -CONFIG_ROUTE=y +# CONFIG_FEATURE_FANCY_PING is not set +# CONFIG_PSCAN is not set +# CONFIG_ROUTE is not set # CONFIG_SLATTACH is not set # CONFIG_TCPSVD is not set -CONFIG_TELNET=y +# CONFIG_TELNET is not set # CONFIG_FEATURE_TELNET_TTYPE is not set # CONFIG_FEATURE_TELNET_AUTOLOGIN is not set -CONFIG_TELNETD=y -CONFIG_FEATURE_TELNETD_STANDALONE=y +# CONFIG_TELNETD is not set +# CONFIG_FEATURE_TELNETD_STANDALONE is not set # CONFIG_FEATURE_TELNETD_INETD_WAIT is not set # CONFIG_TFTP is not set # CONFIG_TFTPD is not set @@ -808,11 +760,11 @@ CONFIG_FEATURE_TELNETD_STANDALONE=y # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set # CONFIG_TFTP_DEBUG is not set -CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set -CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_UDHCPD is not set @@ -820,22 +772,20 @@ CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set CONFIG_DHCPD_LEASES_FILE="" -CONFIG_UDHCPC=y +# CONFIG_UDHCPC is not set # CONFIG_FEATURE_UDHCPC_ARPING is not set # CONFIG_FEATURE_UDHCP_PORT is not set CONFIG_UDHCP_DEBUG=0 # CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" # CONFIG_UDPSVD is not set -CONFIG_VCONFIG=y -CONFIG_WGET=y +# CONFIG_VCONFIG is not set +# CONFIG_WGET is not set # CONFIG_FEATURE_WGET_STATUSBAR is not set -CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_AUTHENTICATION is not set # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set -CONFIG_FEATURE_WGET_TIMEOUT=y # CONFIG_ZCIP is not set # @@ -859,39 +809,34 @@ CONFIG_FEATURE_MIME_CHARSET="" # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set -# CONFIG_PMAP is not set -# CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set -CONFIG_FREE=y +# CONFIG_FREE is not set # CONFIG_FUSER is not set -CONFIG_KILL=y -CONFIG_KILLALL=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set # CONFIG_KILLALL5 is not set # CONFIG_NMETER is not set # CONFIG_PGREP is not set -CONFIG_PIDOF=y +# CONFIG_PIDOF is not set # CONFIG_FEATURE_PIDOF_SINGLE is not set # CONFIG_FEATURE_PIDOF_OMIT is not set # CONFIG_PKILL is not set -CONFIG_PS=y -CONFIG_FEATURE_PS_WIDE=y +# CONFIG_PS is not set +# CONFIG_FEATURE_PS_WIDE is not set # CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set # CONFIG_RENICE is not set # CONFIG_BB_SYSCTL is not set -CONFIG_TOP=y -CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y -CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +# CONFIG_TOP is not set +# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set +# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set # CONFIG_FEATURE_TOP_SMP_CPU is not set # CONFIG_FEATURE_TOP_DECIMALS is not set # CONFIG_FEATURE_TOP_SMP_PROCESS is not set # CONFIG_FEATURE_TOPMEM is not set # CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y -CONFIG_WATCH=y +# CONFIG_UPTIME is not set +# CONFIG_WATCH is not set # # Runit Utilities @@ -926,26 +871,23 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # # Shells # -CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set # CONFIG_ASH_JOB_CONTROL is not set -CONFIG_ASH_ALIAS=y +# CONFIG_ASH_ALIAS is not set # CONFIG_ASH_GETOPTS is not set # CONFIG_ASH_BUILTIN_ECHO is not set # CONFIG_ASH_BUILTIN_PRINTF 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=y +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set # CONFIG_ASH_RANDOM_SUPPORT is not set # CONFIG_ASH_EXPAND_PRMT is not set -# CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_HUSH_BASH_COMPAT is not set -# CONFIG_HUSH_BRACE_EXPANSION is not set # CONFIG_HUSH_HELP is not set # CONFIG_HUSH_INTERACTIVE is not set -# CONFIG_HUSH_SAVEHISTORY is not set # CONFIG_HUSH_JOB is not set # CONFIG_HUSH_TICK is not set # CONFIG_HUSH_IF is not set @@ -953,34 +895,33 @@ CONFIG_ASH_OPTIMIZE_FOR_SIZE=y # CONFIG_HUSH_CASE is not set # CONFIG_HUSH_FUNCTIONS is not set # CONFIG_HUSH_LOCAL is not set -# CONFIG_HUSH_RANDOM_SUPPORT is not set # CONFIG_HUSH_EXPORT_N is not set -# CONFIG_HUSH_MODE_X is not set -# CONFIG_MSH is not set -CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_FEATURE_SH_IS_NONE=y # CONFIG_FEATURE_BASH_IS_ASH is not set # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y -CONFIG_SH_MATH_SUPPORT=y +# CONFIG_MSH is not set +# CONFIG_SH_MATH_SUPPORT is not set # CONFIG_SH_MATH_SUPPORT_64 is not set -CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_CTTYHACK is not set # # System Logging Utilities # -CONFIG_SYSLOGD=y -CONFIG_FEATURE_ROTATE_LOGFILE=y -CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set # CONFIG_FEATURE_SYSLOGD_DUP is not set -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 # CONFIG_LOGREAD is not set # CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -CONFIG_FEATURE_KLOGD_KLOGCTL=y -CONFIG_LOGGER=y +# CONFIG_KLOGD is not set +# CONFIG_LOGGER is not set diff --git a/release/src/router/busybox/configs/TEST_rh9_defconfig b/release/src/router/busybox/configs/TEST_rh9_defconfig new file mode 100644 index 0000000000..193d8f615e --- /dev/null +++ b/release/src/router/busybox/configs/TEST_rh9_defconfig @@ -0,0 +1,941 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.17.0.git +# Fri Apr 16 22:25:22 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +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=y +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +CONFIG_FEATURE_PIDFILE=y +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y +CONFIG_FEATURE_HAVE_RPC=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# 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_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=15 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_MONOTONIC_SYSCALL is not set +CONFIG_IOCTL_HEX2STR_ERROR=y +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set +CONFIG_GUNZIP=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=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_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAL=y +CONFIG_CAT=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=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_FSYNC=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_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_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_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, sha256sum, sha512sum +# +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_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y + +# +# Common options for loadfont and setfont +# +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# 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_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_FEATURE_VI_8BIT is not set +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 is not set +CONFIG_FEATURE_FIND_LINKS=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_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +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_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_MESG=y + +# +# Login/Password Management Utilities +# +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_DELUSER=y +CONFIG_GETTY=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_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +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 is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +# CONFIG_FLOCK is not set +CONFIG_FREERAMDISK=y +CONFIG_FSCK_MINIX=y +# CONFIG_MKFS_EXT2 is not set +CONFIG_MKFS_MINIX=y + +# +# Minix filesystem support +# +CONFIG_FEATURE_MINIX2=y +# CONFIG_MKFS_REISER is not set +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=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_LSPCI=y +CONFIG_LSUSB=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_UUID=y +CONFIG_MORE=y +CONFIG_FEATURE_USE_TERMIOS=y +CONFIG_VOLUMEID=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=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 is not set +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_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +CONFIG_SETARCH=y +CONFIG_SWAPONOFF=y +CONFIG_FEATURE_SWAPON_PRI=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_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Miscellaneous Utilities +# +CONFIG_ADJTIMEX=y +# CONFIG_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +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_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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_DEVMEM=y +CONFIG_EJECT=y +CONFIG_FEATURE_EJECT_SCSI=y +CONFIG_FBSPLASH=y +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +# CONFIG_INOTIFYD is not set +CONFIG_LAST=y +# CONFIG_FEATURE_LAST_SMALL is not set +CONFIG_FEATURE_LAST_FANCY=y +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=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 is not set +CONFIG_RUNLEVEL=y +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WALL=y +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +# CONFIG_FEATURE_UNIX_LOCAL is not set +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +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_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=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_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=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 is not set +CONFIG_IFPLUGD=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 is not set +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 is not set +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_FEATURE_NETSTAT_PRG=y +CONFIG_NSLOOKUP=y +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_PSCAN=y +CONFIG_ROUTE=y +CONFIG_SLATTACH=y +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_TIMEOUT=y +CONFIG_ZCIP=y + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=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 is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +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_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_UPTIME=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y +CONFIG_ASH_BASH_COMPAT=y +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_BUILTIN_ECHO=y +CONFIG_ASH_BUILTIN_PRINTF=y +CONFIG_ASH_BUILTIN_TEST=y +CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y +CONFIG_HUSH=y +CONFIG_HUSH_BASH_COMPAT=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_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_MSH=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +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_SYSLOGD_READ_BUFFER_SIZE=256 +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 diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/android2_defconfig similarity index 56% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/android2_defconfig index 373651d2fd..b5166e0fc5 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/android2_defconfig @@ -1,7 +1,7 @@ +# Run "make android2_defconfig", then "make". # -# Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Tested with the standalone toolchain from ndk r6: +# android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-8 # CONFIG_HAVE_DOT_CONFIG=y @@ -20,13 +20,13 @@ CONFIG_PLATFORM_LINUX=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_SHOW_USAGE is not set # CONFIG_FEATURE_VERBOSE_USAGE is not set # CONFIG_FEATURE_COMPRESS_USAGE is not set # CONFIG_FEATURE_INSTALLER is not set # CONFIG_INSTALL_NO_USR is not set # CONFIG_LOCALE_SUPPORT is not set -CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_SUPPORT is not set # CONFIG_UNICODE_USING_LOCALE is not set # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=0 @@ -36,13 +36,13 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 # CONFIG_UNICODE_BIDI_SUPPORT is not set # CONFIG_UNICODE_NEUTRAL_TABLE is not set # CONFIG_UNICODE_PRESERVE_BROKEN is not set -CONFIG_LONG_OPTS=y -CONFIG_FEATURE_DEVPTS=y +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set # CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_WTMP is not set # CONFIG_FEATURE_UTMP is not set -CONFIG_FEATURE_PIDFILE=y -CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set # CONFIG_FEATURE_SUID_CONFIG is not set # CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set @@ -60,8 +60,8 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_BUILD_LIBBUSYBOX is not set # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set -CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" CONFIG_EXTRA_CFLAGS="" # @@ -89,25 +89,28 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 -CONFIG_FEATURE_FAST_TOP=y +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_FEATURE_EDITING=y -CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 +CONFIG_FEATURE_EDITING_HISTORY=0 # CONFIG_FEATURE_EDITING_SAVEHISTORY is not set -CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_TAB_COMPLETION is not set # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set # CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set -CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_NON_POSIX_CP is not set # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set # CONFIG_MONOTONIC_SYSCALL is not set -CONFIG_IOCTL_HEX2STR_ERROR=y +# CONFIG_IOCTL_HEX2STR_ERROR is not set # CONFIG_FEATURE_HWIB is not set # @@ -117,105 +120,106 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y -# CONFIG_FEATURE_SEAMLESS_Z is not set -# CONFIG_AR is not set -# CONFIG_FEATURE_AR_LONG_FILENAMES is not set -# CONFIG_FEATURE_AR_CREATE is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_FEATURE_CPIO_O is not set -# CONFIG_FEATURE_CPIO_P is not set -# CONFIG_DPKG is not set -# CONFIG_DPKG_DEB is not set +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -# CONFIG_LZOP is not set -# CONFIG_LZOP_COMPR_HIGH is not set -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y CONFIG_TAR=y CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set +CONFIG_FEATURE_TAR_AUTODETECT=y CONFIG_FEATURE_TAR_FROM=y CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set # CONFIG_FEATURE_TAR_TO_COMMAND is not set -# CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set -# CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set -# CONFIG_BASE64 is not set -# CONFIG_CAL is not set -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y # CONFIG_FEATURE_CP_LONG_OPTIONS is not set CONFIG_CUT=y CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set +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_ENV is not set # CONFIG_FEATURE_ENV_LONG_OPTIONS is not set -# CONFIG_EXPAND is not set +CONFIG_EXPAND=y # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set -CONFIG_EXPR=y -CONFIG_EXPR_MATH_SUPPORT_64=y -# CONFIG_FALSE is not set -# CONFIG_FOLD is not set +# CONFIG_EXPR is not set +# CONFIG_EXPR_MATH_SUPPORT_64 is not set +CONFIG_FALSE=y +CONFIG_FOLD=y # CONFIG_FSYNC is not set CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y # CONFIG_HOSTID is not set -# CONFIG_ID is not set -# CONFIG_INSTALL is not set +CONFIG_INSTALL=y # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y @@ -230,58 +234,57 @@ CONFIG_FEATURE_LS_USERNAME=y CONFIG_MD5SUM=y CONFIG_MKDIR=y # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set -# CONFIG_MKNOD is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y CONFIG_MV=y # CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set +CONFIG_NICE=y CONFIG_NOHUP=y -# CONFIG_OD is not set -# CONFIG_PRINTENV is not set +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set -# CONFIG_SHA256SUM is not set -# CONFIG_SHA512SUM is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y # CONFIG_STAT is not set # CONFIG_FEATURE_STAT_FORMAT is not set -# CONFIG_STTY is not set -# CONFIG_SUM is not set +CONFIG_STTY=y +CONFIG_SUM=y CONFIG_SYNC=y -# CONFIG_TAC is not set +CONFIG_TAC=y CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TRUE=y # CONFIG_TTY is not set CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set +CONFIG_UNEXPAND=y # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -# CONFIG_UNIQ is not set -CONFIG_USLEEP=y -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UNIQ=y +# CONFIG_USLEEP is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y # CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -301,80 +304,81 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # -# CONFIG_CHVT is not set -# CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set -# CONFIG_DEALLOCVT is not set -# CONFIG_DUMPKMAP is not set +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y # CONFIG_KBD_MODE is not set # CONFIG_LOADFONT is not set -# CONFIG_LOADKMAP is not set -# CONFIG_OPENVT is not set -# CONFIG_RESET is not set -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set -# CONFIG_SETCONSOLE is not set +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 is not set # CONFIG_SETFONT is not set # CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set CONFIG_DEFAULT_SETFONT_DIR="" -# CONFIG_SETKEYCODES is not set -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y # CONFIG_FEATURE_LOADFONT_PSF2 is not set # CONFIG_FEATURE_LOADFONT_RAW is not set # # Debian Utilities # -# CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y # CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -# CONFIG_START_STOP_DAEMON is not set -# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +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 is not set CONFIG_WHICH=y # # Editors # -# CONFIG_PATCH is not set -CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y +CONFIG_PATCH=y +# CONFIG_VI is not set +CONFIG_FEATURE_VI_MAX_LEN=0 +# CONFIG_FEATURE_VI_8BIT is not set +# CONFIG_FEATURE_VI_COLON is not set +# CONFIG_FEATURE_VI_YANKMARK is not set +# CONFIG_FEATURE_VI_SEARCH is not set +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +# CONFIG_FEATURE_VI_USE_SIGNALS is not set +# CONFIG_FEATURE_VI_DOT_CMD is not set +# CONFIG_FEATURE_VI_READONLY is not set +# CONFIG_FEATURE_VI_SETOPTS is not set +# CONFIG_FEATURE_VI_SET is not set +# CONFIG_FEATURE_VI_WIN_RESIZE is not set +# CONFIG_FEATURE_VI_ASK_TERMINAL is not set +# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set +# CONFIG_AWK is not set +# CONFIG_FEATURE_AWK_LIBM is not set CONFIG_CMP=y -# CONFIG_DIFF is not set +CONFIG_DIFF=y # CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set +CONFIG_FEATURE_DIFF_DIR=y # CONFIG_ED is not set -CONFIG_SED=y -CONFIG_VI=y -CONFIG_FEATURE_VI_MAX_LEN=4096 -# CONFIG_FEATURE_VI_8BIT is not set -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_ASK_TERMINAL=y -# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set -CONFIG_FEATURE_ALLOW_EXEC=y +# CONFIG_SED is not set +# CONFIG_FEATURE_ALLOW_EXEC is not set # # Finding Utilities # -CONFIG_FIND=y -CONFIG_FEATURE_FIND_PRINT0=y +# CONFIG_FIND is not set +# CONFIG_FEATURE_FIND_PRINT0 is not set # CONFIG_FEATURE_FIND_MTIME is not set # CONFIG_FEATURE_FIND_MMIN is not set # CONFIG_FEATURE_FIND_PERM is not set @@ -383,10 +387,10 @@ CONFIG_FEATURE_FIND_PRINT0=y # CONFIG_FEATURE_FIND_MAXDEPTH is not set # CONFIG_FEATURE_FIND_NEWER is not set # CONFIG_FEATURE_FIND_INUM is not set -CONFIG_FEATURE_FIND_EXEC=y +# CONFIG_FEATURE_FIND_EXEC is not set # CONFIG_FEATURE_FIND_USER is not set # CONFIG_FEATURE_FIND_GROUP is not set -CONFIG_FEATURE_FIND_NOT=y +# CONFIG_FEATURE_FIND_NOT is not set # CONFIG_FEATURE_FIND_DEPTH is not set # CONFIG_FEATURE_FIND_PAREN is not set # CONFIG_FEATURE_FIND_SIZE is not set @@ -396,15 +400,15 @@ CONFIG_FEATURE_FIND_NOT=y # CONFIG_FEATURE_FIND_REGEX is not set # CONFIG_FEATURE_FIND_CONTEXT is not set # CONFIG_FEATURE_FIND_LINKS is not set -CONFIG_GREP=y -CONFIG_FEATURE_GREP_EGREP_ALIAS=y -CONFIG_FEATURE_GREP_FGREP_ALIAS=y -CONFIG_FEATURE_GREP_CONTEXT=y -# CONFIG_XARGS is not set -# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set -# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set -# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set -# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set +# CONFIG_GREP is not set +# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_CONTEXT is not set +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 @@ -412,29 +416,30 @@ CONFIG_FEATURE_GREP_CONTEXT=y # CONFIG_BOOTCHARTD is not set # CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set # CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set -# CONFIG_HALT is not set +CONFIG_HALT=y # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" -# CONFIG_INIT is not set -# CONFIG_FEATURE_USE_INITTAB is not set +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y # CONFIG_FEATURE_KILL_REMOVED is not set CONFIG_FEATURE_KILL_DELAY=0 -# CONFIG_FEATURE_INIT_SCTTY is not set -# CONFIG_FEATURE_INIT_SYSLOG is not set -# CONFIG_FEATURE_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_MESG is not set +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_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # # CONFIG_ADD_SHELL is not set # CONFIG_REMOVE_SHELL is not set -CONFIG_FEATURE_SHADOWPASSWDS=y -CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set # CONFIG_USE_BB_CRYPT is not set # CONFIG_USE_BB_CRYPT_SHA is not set # CONFIG_ADDUSER is not set @@ -449,7 +454,7 @@ CONFIG_LAST_SYSTEM_ID=0 # CONFIG_DELGROUP is not set # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set # CONFIG_GETTY is not set -CONFIG_LOGIN=y +# CONFIG_LOGIN is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -467,128 +472,122 @@ CONFIG_LOGIN=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set -# CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y # # Linux Module Utilities # -# CONFIG_MODINFO is not set -# CONFIG_MODPROBE_SMALL is not set -# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set -# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" # # Linux System Utilities # -# CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set +CONFIG_BLOCKDEV=y +CONFIG_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y -# CONFIG_FBSET is not set -# CONFIG_FEATURE_FBSET_FANCY is not set -# CONFIG_FEATURE_FBSET_READMODE is not set -# CONFIG_FDFLUSH is not set -# CONFIG_FDFORMAT is not set -# CONFIG_FDISK is not set +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 is not set +CONFIG_FEATURE_FDISK_WRITABLE=y # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set # CONFIG_FEATURE_GPT_LABEL is not set -# CONFIG_FEATURE_FDISK_ADVANCED is not set -# CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set -# CONFIG_FREERAMDISK is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set # CONFIG_MKFS_MINIX is not set # CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set # CONFIG_MKFS_VFAT is not set -# CONFIG_GETOPT is not set -# CONFIG_FEATURE_GETOPT_LONG is not set -# CONFIG_HEXDUMP is not set -# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y # CONFIG_HWCLOCK is not set # CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set # CONFIG_IPCRM is not set # CONFIG_IPCS is not set -# CONFIG_LOSETUP is not set -# CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y # CONFIG_MDEV is not set # CONFIG_FEATURE_MDEV_CONF is not set # CONFIG_FEATURE_MDEV_RENAME is not set # CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set # CONFIG_FEATURE_MDEV_EXEC is not set # CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -# CONFIG_MKSWAP is not set +CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set # CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set -# CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set -# CONFIG_RTCWAKE is not set -# CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set # CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y +# CONFIG_UMOUNT is not set # CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set # CONFIG_FEATURE_MTAB_SUPPORT is not set CONFIG_VOLUMEID=y @@ -596,73 +595,78 @@ CONFIG_VOLUMEID=y # Filesystem/Volume identification # CONFIG_FEATURE_VOLUMEID_EXT=y -# CONFIG_FEATURE_VOLUMEID_BTRFS is not set -# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set -# CONFIG_FEATURE_VOLUMEID_JFS is not set -# CONFIG_FEATURE_VOLUMEID_XFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y CONFIG_FEATURE_VOLUMEID_NTFS=y -# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set -# CONFIG_FEATURE_VOLUMEID_UDF is not set -# CONFIG_FEATURE_VOLUMEID_LUKS is not set +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y -# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set -# CONFIG_FEATURE_VOLUMEID_ROMFS is not set -# CONFIG_FEATURE_VOLUMEID_SYSV is not set -# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set -# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +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 # # Miscellaneous Utilities # # CONFIG_CONSPY is not set # CONFIG_NANDWRITE is not set -# CONFIG_NANDDUMP is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 -# CONFIG_CHAT is not set -# CONFIG_FEATURE_CHAT_NOFAIL is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y # CONFIG_FEATURE_CHAT_TTY_HIFI is not set -# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set -# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set -# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set -# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set -# CONFIG_FEATURE_CHAT_CLR_ABORT is not set -# CONFIG_CHRT is not set -CONFIG_CROND=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 is not set # CONFIG_FEATURE_CROND_D is not set # CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set -CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_FEATURE_CROND_DIR="" # CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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=y -# CONFIG_DEVMEM is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set -# CONFIG_FBSPLASH is not set -# CONFIG_FLASHCP is not set -# CONFIG_FLASH_LOCK is not set -# CONFIG_FLASH_UNLOCK is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y # CONFIG_FLASH_ERASEALL is not set # CONFIG_IONICE is not set -# CONFIG_INOTIFYD is not set +CONFIG_INOTIFYD=y # CONFIG_LAST is not set # CONFIG_FEATURE_LAST_SMALL is not set # CONFIG_FEATURE_LAST_FANCY is not set -CONFIG_LESS=y -CONFIG_FEATURE_LESS_MAXLINES=9999999 +# CONFIG_LESS is not set +CONFIG_FEATURE_LESS_MAXLINES=0 # CONFIG_FEATURE_LESS_BRACKETS is not set # CONFIG_FEATURE_LESS_FLAGS is not set # CONFIG_FEATURE_LESS_MARKS is not set @@ -670,92 +674,98 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 # CONFIG_FEATURE_LESS_WINCH is not set # CONFIG_FEATURE_LESS_DASHCMD is not set # CONFIG_FEATURE_LESS_LINENUMS is not set -# CONFIG_HDPARM is not set -# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set -# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set -# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set -# CONFIG_MAKEDEVS is not set +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 is not set -# CONFIG_MAN is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y # CONFIG_MICROCOM is not set # CONFIG_MOUNTPOINT is not set # CONFIG_MT is not set -# CONFIG_RAIDAUTORUN is not set +CONFIG_RAIDAUTORUN=y # CONFIG_READAHEAD is not set # CONFIG_RFKILL is not set # CONFIG_RUNLEVEL is not set -# CONFIG_RX is not set -# CONFIG_SETSID is not set +CONFIG_RX=y +CONFIG_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set -# CONFIG_TIME is not set -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set # CONFIG_WATCHDOG is not set # # Networking Utilities # -# CONFIG_NBDCLIENT is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y CONFIG_NC=y -# CONFIG_NC_SERVER is not set +CONFIG_NC_SERVER=y CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +CONFIG_WHOIS=y # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set -CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set -# CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set # CONFIG_HOSTNAME is not set -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set -# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set -# CONFIG_FEATURE_HTTPD_SETUID is not set -# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set -# CONFIG_FEATURE_HTTPD_CGI is not set -# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set -# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set -# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set -# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set -# CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set +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_FEATURE_HTTPD_GZIP=y CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y # CONFIG_FEATURE_IFCONFIG_SLIP is not set -# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y CONFIG_FEATURE_IFCONFIG_HW=y CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set -# CONFIG_IFUPDOWN is not set -CONFIG_IFUPDOWN_IFSTATE_PATH="" -# CONFIG_FEATURE_IFUPDOWN_IP is not set -# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set +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 is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set -# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y # CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set # CONFIG_INETD is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set @@ -764,42 +774,37 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set # CONFIG_FEATURE_INETD_RPC is not set -# CONFIG_IP is not set -# CONFIG_FEATURE_IP_ADDRESS is not set -# CONFIG_FEATURE_IP_LINK is not set -# CONFIG_FEATURE_IP_ROUTE is not set -# CONFIG_FEATURE_IP_TUNNEL is not set -# CONFIG_FEATURE_IP_RULE is not set -# CONFIG_FEATURE_IP_SHORT_FORMS is not set +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 is not set -# CONFIG_IPADDR is not set -# CONFIG_IPLINK is not set -# CONFIG_IPROUTE is not set -# CONFIG_IPTUNNEL is not set -# CONFIG_IPRULE is not set -# CONFIG_IPCALC is not set -# CONFIG_FEATURE_IPCALC_FANCY is not set +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 is not set -# CONFIG_NAMEIF is not set -# CONFIG_FEATURE_NAMEIF_EXTENDED is not set CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y -# CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -# CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y # CONFIG_SLATTACH is not set -# CONFIG_TCPSVD is not set -CONFIG_TELNET=y +CONFIG_TCPSVD=y +# CONFIG_TELNET is not set # CONFIG_FEATURE_TELNET_TTYPE is not set # CONFIG_FEATURE_TELNET_AUTOLOGIN is not set -CONFIG_TELNETD=y -CONFIG_FEATURE_TELNETD_STANDALONE=y +# CONFIG_TELNETD is not set +# CONFIG_FEATURE_TELNETD_STANDALONE is not set # CONFIG_FEATURE_TELNETD_INETD_WAIT is not set # CONFIG_TFTP is not set # CONFIG_TFTPD is not set @@ -808,31 +813,32 @@ CONFIG_FEATURE_TELNETD_STANDALONE=y # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set # CONFIG_TFTP_DEBUG is not set -CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set -CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y # CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y -# CONFIG_FEATURE_UDHCPC_ARPING is not set +CONFIG_FEATURE_UDHCPC_ARPING=y # CONFIG_FEATURE_UDHCP_PORT is not set -CONFIG_UDHCP_DEBUG=0 -# CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set -CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 -CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" # CONFIG_UDPSVD is not set -CONFIG_VCONFIG=y +# CONFIG_VCONFIG is not set CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set CONFIG_FEATURE_WGET_TIMEOUT=y @@ -841,72 +847,74 @@ CONFIG_FEATURE_WGET_TIMEOUT=y # # Print Utilities # -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set -CONFIG_FEATURE_MIME_CHARSET="" -# CONFIG_POPMAILDIR is not set -# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set -# CONFIG_REFORMIME is not set -# CONFIG_FEATURE_REFORMIME_COMPAT is not set -# CONFIG_SENDMAIL is not set +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set -# CONFIG_PMAP is not set -# CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set -CONFIG_FREE=y -# CONFIG_FUSER is not set -CONFIG_KILL=y -CONFIG_KILLALL=y +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set # CONFIG_KILLALL5 is not set -# CONFIG_NMETER is not set # CONFIG_PGREP is not set CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y # CONFIG_PKILL is not set -CONFIG_PS=y -CONFIG_FEATURE_PS_WIDE=y +# CONFIG_PS is not set +# CONFIG_FEATURE_PS_WIDE is not set # CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -# CONFIG_RENICE is not set -# CONFIG_BB_SYSCTL is not set +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_SMP_CPU is not set -# CONFIG_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -# CONFIG_FEATURE_TOPMEM is not set -# CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +# CONFIG_UPTIME is not set CONFIG_WATCH=y # # Runit Utilities # -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y # CONFIG_FEATURE_RUNSVDIR_LOG is not set -# CONFIG_SV is not set -CONFIG_SV_DEFAULT_SERVICE_DIR="" -# CONFIG_SVLOGD is not set -# CONFIG_CHPST is not set -# CONFIG_SETUIDGID is not set -# CONFIG_ENVUIDGID is not set -# CONFIG_ENVDIR is not set -# CONFIG_SOFTLIMIT is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y # CONFIG_CHCON is not set # CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set # CONFIG_GETENFORCE is not set @@ -926,20 +934,21 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # # Shells # -CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set # CONFIG_ASH_JOB_CONTROL is not set -CONFIG_ASH_ALIAS=y +# CONFIG_ASH_ALIAS is not set # CONFIG_ASH_GETOPTS is not set # CONFIG_ASH_BUILTIN_ECHO is not set # CONFIG_ASH_BUILTIN_PRINTF 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=y +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set # CONFIG_ASH_RANDOM_SUPPORT is not set # CONFIG_ASH_EXPAND_PRMT is not set -# CONFIG_CTTYHACK is not set +CONFIG_CTTYHACK=y # CONFIG_HUSH is not set # CONFIG_HUSH_BASH_COMPAT is not set # CONFIG_HUSH_BRACE_EXPANSION is not set @@ -957,30 +966,32 @@ CONFIG_ASH_OPTIMIZE_FOR_SIZE=y # CONFIG_HUSH_EXPORT_N is not set # CONFIG_HUSH_MODE_X is not set # CONFIG_MSH is not set -CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_FEATURE_SH_IS_NONE=y # CONFIG_FEATURE_BASH_IS_ASH is not set # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y -CONFIG_SH_MATH_SUPPORT=y +# CONFIG_SH_MATH_SUPPORT is not set # CONFIG_SH_MATH_SUPPORT_64 is not set -CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities # -CONFIG_SYSLOGD=y -CONFIG_FEATURE_ROTATE_LOGFILE=y -CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set # CONFIG_FEATURE_SYSLOGD_DUP is not set -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 # CONFIG_LOGREAD is not set # CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set CONFIG_KLOGD=y CONFIG_FEATURE_KLOGD_KLOGCTL=y -CONFIG_LOGGER=y +# CONFIG_LOGGER is not set diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/android_defconfig similarity index 52% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/android_defconfig index 373651d2fd..a9a8d5e1f1 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/android_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.20.0.git +# Sun Nov 6 07:51:38 2011 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,7 +12,7 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set +CONFIG_DESKTOP=y # CONFIG_EXTRA_COMPAT is not set # CONFIG_INCLUDE_SUSv2 is not set # CONFIG_USE_PORTABLE_CODE is not set @@ -20,13 +20,13 @@ CONFIG_PLATFORM_LINUX=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_SHOW_USAGE is not set # CONFIG_FEATURE_VERBOSE_USAGE is not set # CONFIG_FEATURE_COMPRESS_USAGE is not set # CONFIG_FEATURE_INSTALLER is not set # CONFIG_INSTALL_NO_USR is not set # CONFIG_LOCALE_SUPPORT is not set -CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_SUPPORT is not set # CONFIG_UNICODE_USING_LOCALE is not set # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=0 @@ -36,13 +36,13 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 # CONFIG_UNICODE_BIDI_SUPPORT is not set # CONFIG_UNICODE_NEUTRAL_TABLE is not set # CONFIG_UNICODE_PRESERVE_BROKEN is not set -CONFIG_LONG_OPTS=y -CONFIG_FEATURE_DEVPTS=y +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set # CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_WTMP is not set # CONFIG_FEATURE_UTMP is not set -CONFIG_FEATURE_PIDFILE=y -CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set # CONFIG_FEATURE_SUID_CONFIG is not set # CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set @@ -60,9 +60,27 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_BUILD_LIBBUSYBOX is not set # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set -CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" -CONFIG_EXTRA_CFLAGS="" +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" +# +# Removed: +# warning flags: +# -Wno-multichar -W -Wall -Wno-unused -Winit-self -Wpointer-arith +# -Werror=return-type -Werror=non-virtual-dtor -Werror=address +# -Werror=sequence-point -Wstrict-aliasing=2 -Wno-undef -Wno-shadow +# bbox already adds these: +# -ffunction-sections -fomit-frame-pointer +# enabled implicitly by -Os: +# -frerun-cse-after-loop +# should be not needed, or even increases code size: +# -finline-functions -fno-inline-functions-called-once -finline-limit=64 +# -fstack-protector -fno-strict-aliasing -fno-exceptions -funwind-tables +# -fmessage-length=0 (only affects error message format) +# todo: do we need these? - +# -fno-short-enums +# -fgcse-after-reload +# -frename-registers +CONFIG_EXTRA_CFLAGS="-I$A/system/core/include -I$A/bionic/libc/arch-arm/include -I$A/bionic/libc/include -I$A/bionic/libc/kernel/common -I$A/bionic/libc/kernel/arch-arm -I$A/bionic/libm/include -I$A/bionic/libm/include/arch/arm -include $A/system/core/include/arch/linux-arm/AndroidConfig.h -I$A/system/core/include/arch/linux-arm/ -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers" # # Debugging Options @@ -89,25 +107,30 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 -CONFIG_FEATURE_FAST_TOP=y +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_FEATURE_EDITING=y -CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 +CONFIG_FEATURE_EDITING_HISTORY=0 # CONFIG_FEATURE_EDITING_SAVEHISTORY is not set -CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set # CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set -CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_NON_POSIX_CP is not set # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set # CONFIG_MONOTONIC_SYSCALL is not set -CONFIG_IOCTL_HEX2STR_ERROR=y +# CONFIG_IOCTL_HEX2STR_ERROR is not set # CONFIG_FEATURE_HWIB is not set # @@ -117,105 +140,110 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y -# CONFIG_FEATURE_SEAMLESS_Z is not set -# CONFIG_AR is not set -# CONFIG_FEATURE_AR_LONG_FILENAMES is not set -# CONFIG_FEATURE_AR_CREATE is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_FEATURE_CPIO_O is not set -# CONFIG_FEATURE_CPIO_P is not set -# CONFIG_DPKG is not set -# CONFIG_DPKG_DEB is not set +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -# CONFIG_LZOP is not set -# CONFIG_LZOP_COMPR_HIGH is not set -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set +CONFIG_GZIP_FAST=0 +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y CONFIG_TAR=y CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set +CONFIG_FEATURE_TAR_AUTODETECT=y CONFIG_FEATURE_TAR_FROM=y CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set # CONFIG_FEATURE_TAR_TO_COMMAND is not set -# CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set -# CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set -# CONFIG_BASE64 is not set -# CONFIG_CAL is not set -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y # CONFIG_FEATURE_CP_LONG_OPTIONS is not set CONFIG_CUT=y CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set +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 is not set -# CONFIG_EXPAND is not set +CONFIG_EXPAND=y # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set CONFIG_EXPR=y CONFIG_EXPR_MATH_SUPPORT_64=y -# CONFIG_FALSE is not set -# CONFIG_FOLD is not set -# CONFIG_FSYNC is not set +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set -# CONFIG_INSTALL is not set +CONFIG_INSTALL=y # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y @@ -230,58 +258,56 @@ CONFIG_FEATURE_LS_USERNAME=y CONFIG_MD5SUM=y CONFIG_MKDIR=y # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set -# CONFIG_MKNOD is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y CONFIG_MV=y # CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set +CONFIG_NICE=y CONFIG_NOHUP=y -# CONFIG_OD is not set -# CONFIG_PRINTENV is not set +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set -# CONFIG_SHA256SUM is not set -# CONFIG_SHA512SUM is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y # CONFIG_STAT is not set # CONFIG_FEATURE_STAT_FORMAT is not set -# CONFIG_STTY is not set -# CONFIG_SUM is not set +CONFIG_STTY=y +CONFIG_SUM=y CONFIG_SYNC=y -# CONFIG_TAC is not set +CONFIG_TAC=y CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TRUE=y # CONFIG_TTY is not set CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set +CONFIG_UNEXPAND=y # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -# CONFIG_UNIQ is not set +CONFIG_UNIQ=y CONFIG_USLEEP=y -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y -# CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -301,65 +327,58 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # -# CONFIG_CHVT is not set -# CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set -# CONFIG_DEALLOCVT is not set -# CONFIG_DUMPKMAP is not set +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y # CONFIG_KBD_MODE is not set # CONFIG_LOADFONT is not set -# CONFIG_LOADKMAP is not set -# CONFIG_OPENVT is not set -# CONFIG_RESET is not set -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set -# CONFIG_SETCONSOLE is not set +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 is not set # CONFIG_SETFONT is not set # CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set CONFIG_DEFAULT_SETFONT_DIR="" -# CONFIG_SETKEYCODES is not set -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y # CONFIG_FEATURE_LOADFONT_PSF2 is not set # CONFIG_FEATURE_LOADFONT_RAW is not set # # Debian Utilities # -# CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y # CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -# CONFIG_START_STOP_DAEMON is not set -# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +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 is not set CONFIG_WHICH=y # # Editors # -# CONFIG_PATCH is not set -CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_ED is not set -CONFIG_SED=y +CONFIG_PATCH=y CONFIG_VI=y CONFIG_FEATURE_VI_MAX_LEN=4096 -# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_8BIT=y CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -367,7 +386,15 @@ CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y CONFIG_FEATURE_VI_ASK_TERMINAL=y -# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -375,66 +402,67 @@ CONFIG_FEATURE_ALLOW_EXEC=y # CONFIG_FIND=y CONFIG_FEATURE_FIND_PRINT0=y -# CONFIG_FEATURE_FIND_MTIME is not set -# CONFIG_FEATURE_FIND_MMIN is not set -# CONFIG_FEATURE_FIND_PERM is not set -# CONFIG_FEATURE_FIND_TYPE is not set -# CONFIG_FEATURE_FIND_XDEV is not set -# CONFIG_FEATURE_FIND_MAXDEPTH is not set -# CONFIG_FEATURE_FIND_NEWER is not set -# CONFIG_FEATURE_FIND_INUM is not set +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 is not set -# CONFIG_FEATURE_FIND_GROUP is not set +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y CONFIG_FEATURE_FIND_NOT=y -# CONFIG_FEATURE_FIND_DEPTH is not set -# CONFIG_FEATURE_FIND_PAREN is not set -# CONFIG_FEATURE_FIND_SIZE is not set -# CONFIG_FEATURE_FIND_PRUNE is not set -# CONFIG_FEATURE_FIND_DELETE is not set -# CONFIG_FEATURE_FIND_PATH is not set -# CONFIG_FEATURE_FIND_REGEX is not set +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 is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_FEATURE_GREP_EGREP_ALIAS=y CONFIG_FEATURE_GREP_FGREP_ALIAS=y CONFIG_FEATURE_GREP_CONTEXT=y -# CONFIG_XARGS is not set -# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set -# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set -# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set -# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set +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_BOOTCHARTD is not set -# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set -# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set -# CONFIG_HALT is not set +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" -# CONFIG_INIT is not set -# CONFIG_FEATURE_USE_INITTAB is not set +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y # CONFIG_FEATURE_KILL_REMOVED is not set CONFIG_FEATURE_KILL_DELAY=0 -# CONFIG_FEATURE_INIT_SCTTY is not set -# CONFIG_FEATURE_INIT_SYSLOG is not set -# CONFIG_FEATURE_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_MESG is not set +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_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # # CONFIG_ADD_SHELL is not set # CONFIG_REMOVE_SHELL is not set -CONFIG_FEATURE_SHADOWPASSWDS=y -CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set # CONFIG_USE_BB_CRYPT is not set # CONFIG_USE_BB_CRYPT_SHA is not set # CONFIG_ADDUSER is not set @@ -449,7 +477,8 @@ CONFIG_LAST_SYSTEM_ID=0 # CONFIG_DELGROUP is not set # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set # CONFIG_GETTY is not set -CONFIG_LOGIN=y +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -467,128 +496,122 @@ CONFIG_LOGIN=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set -# CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y # # Linux Module Utilities # -# CONFIG_MODINFO is not set -# CONFIG_MODPROBE_SMALL is not set -# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set -# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" # # Linux System Utilities # -# CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set +CONFIG_BLOCKDEV=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_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set CONFIG_BLKID=y +CONFIG_FEATURE_BLKID_TYPE=y CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y -# CONFIG_FBSET is not set -# CONFIG_FEATURE_FBSET_FANCY is not set -# CONFIG_FEATURE_FBSET_READMODE is not set -# CONFIG_FDFLUSH is not set -# CONFIG_FDFORMAT is not set -# CONFIG_FDISK is not set +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 is not set +CONFIG_FEATURE_FDISK_WRITABLE=y # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set # CONFIG_FEATURE_GPT_LABEL is not set -# CONFIG_FEATURE_FDISK_ADVANCED is not set -# CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set -# CONFIG_FREERAMDISK is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set # CONFIG_MKFS_MINIX is not set # CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set # CONFIG_MKFS_VFAT is not set -# CONFIG_GETOPT is not set -# CONFIG_FEATURE_GETOPT_LONG is not set -# CONFIG_HEXDUMP is not set -# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set -# CONFIG_HWCLOCK is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y # CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set # CONFIG_IPCRM is not set # CONFIG_IPCS is not set -# CONFIG_LOSETUP is not set -# CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set -# CONFIG_MDEV is not set -# CONFIG_FEATURE_MDEV_CONF is not set -# CONFIG_FEATURE_MDEV_RENAME is not set -# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set -# CONFIG_FEATURE_MDEV_EXEC is not set -# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -# CONFIG_MKSWAP is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set # CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set -# CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set -# CONFIG_RTCWAKE is not set -# CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set -# CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y +CONFIG_SWITCH_ROOT=y +# CONFIG_UMOUNT is not set # CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set # CONFIG_FEATURE_MTAB_SUPPORT is not set CONFIG_VOLUMEID=y @@ -596,167 +619,179 @@ CONFIG_VOLUMEID=y # Filesystem/Volume identification # CONFIG_FEATURE_VOLUMEID_EXT=y -# CONFIG_FEATURE_VOLUMEID_BTRFS is not set -# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set -# CONFIG_FEATURE_VOLUMEID_JFS is not set -# CONFIG_FEATURE_VOLUMEID_XFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y CONFIG_FEATURE_VOLUMEID_NTFS=y -# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set -# CONFIG_FEATURE_VOLUMEID_UDF is not set -# CONFIG_FEATURE_VOLUMEID_LUKS is not set +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y -# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set -# CONFIG_FEATURE_VOLUMEID_ROMFS is not set -# CONFIG_FEATURE_VOLUMEID_SYSV is not set -# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set -# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +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 # # Miscellaneous Utilities # # CONFIG_CONSPY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y # CONFIG_NANDWRITE is not set -# CONFIG_NANDDUMP is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 -# CONFIG_CHAT is not set -# CONFIG_FEATURE_CHAT_NOFAIL is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y # CONFIG_FEATURE_CHAT_TTY_HIFI is not set -# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set -# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set -# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set -# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set -# CONFIG_FEATURE_CHAT_CLR_ABORT is not set -# CONFIG_CHRT is not set +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_FEATURE_CROND_D is not set -# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y CONFIG_FEATURE_CROND_DIR="/var/spool/cron" -# CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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=y -# CONFIG_DEVMEM is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set -# CONFIG_FBSPLASH is not set -# CONFIG_FLASHCP is not set -# CONFIG_FLASH_LOCK is not set -# CONFIG_FLASH_UNLOCK is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y # CONFIG_FLASH_ERASEALL is not set # CONFIG_IONICE is not set -# CONFIG_INOTIFYD is not set +CONFIG_INOTIFYD=y # CONFIG_LAST is not set # CONFIG_FEATURE_LAST_SMALL is not set # CONFIG_FEATURE_LAST_FANCY is not set -CONFIG_LESS=y -CONFIG_FEATURE_LESS_MAXLINES=9999999 -# CONFIG_FEATURE_LESS_BRACKETS is not set -# CONFIG_FEATURE_LESS_FLAGS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP is not set -# CONFIG_FEATURE_LESS_WINCH is not set -# CONFIG_FEATURE_LESS_DASHCMD is not set -# CONFIG_FEATURE_LESS_LINENUMS is not set -# CONFIG_HDPARM is not set -# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set -# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set -# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set -# CONFIG_MAKEDEVS is not set +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 is not set -# CONFIG_MAN is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y # CONFIG_MICROCOM is not set # CONFIG_MOUNTPOINT is not set # CONFIG_MT is not set -# CONFIG_RAIDAUTORUN is not set +CONFIG_RAIDAUTORUN=y # CONFIG_READAHEAD is not set # CONFIG_RFKILL is not set # CONFIG_RUNLEVEL is not set -# CONFIG_RX is not set -# CONFIG_SETSID is not set +CONFIG_RX=y +CONFIG_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set -# CONFIG_TIME is not set -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set # CONFIG_WATCHDOG is not set # # Networking Utilities # -# CONFIG_NBDCLIENT is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y CONFIG_NC=y -# CONFIG_NC_SERVER is not set +CONFIG_NC_SERVER=y CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +# CONFIG_PING6 is not set +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set -CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set -# CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set # CONFIG_HOSTNAME is not set -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set -# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set -# CONFIG_FEATURE_HTTPD_SETUID is not set -# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set -# CONFIG_FEATURE_HTTPD_CGI is not set -# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set -# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set -# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set -# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set -# CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set +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_FEATURE_HTTPD_GZIP=y CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y # CONFIG_FEATURE_IFCONFIG_SLIP is not set -# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y CONFIG_FEATURE_IFCONFIG_HW=y CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set -# CONFIG_IFUPDOWN is not set -CONFIG_IFUPDOWN_IFSTATE_PATH="" -# CONFIG_FEATURE_IFUPDOWN_IP is not set -# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set +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 is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set -# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set -# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y # CONFIG_INETD is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set @@ -764,75 +799,76 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set # CONFIG_FEATURE_INETD_RPC is not set -# CONFIG_IP is not set -# CONFIG_FEATURE_IP_ADDRESS is not set -# CONFIG_FEATURE_IP_LINK is not set -# CONFIG_FEATURE_IP_ROUTE is not set -# CONFIG_FEATURE_IP_TUNNEL is not set -# CONFIG_FEATURE_IP_RULE is not set -# CONFIG_FEATURE_IP_SHORT_FORMS is not set +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 is not set -# CONFIG_IPADDR is not set -# CONFIG_IPLINK is not set -# CONFIG_IPROUTE is not set -# CONFIG_IPTUNNEL is not set -# CONFIG_IPRULE is not set -# CONFIG_IPCALC is not set -# CONFIG_FEATURE_IPCALC_FANCY is not set +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 is not set -# CONFIG_NAMEIF is not set -# CONFIG_FEATURE_NAMEIF_EXTENDED is not set CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y -# CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -# CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y # CONFIG_SLATTACH is not set -# CONFIG_TCPSVD is not set +CONFIG_TCPSVD=y CONFIG_TELNET=y -# CONFIG_FEATURE_TELNET_TTYPE is not set -# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y CONFIG_TELNETD=y CONFIG_FEATURE_TELNETD_STANDALONE=y -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set -# CONFIG_TFTP is not set -# CONFIG_TFTPD is not set -# CONFIG_FEATURE_TFTP_GET is not set -# CONFIG_FEATURE_TFTP_PUT is not set -# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set -# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y # CONFIG_TFTP_DEBUG is not set CONFIG_TRACEROUTE=y # CONFIG_TRACEROUTE6 is not set CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set # CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y -# CONFIG_FEATURE_UDHCPC_ARPING is not set -# CONFIG_FEATURE_UDHCP_PORT is not set -CONFIG_UDHCP_DEBUG=0 -# CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set -CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 -CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" -# CONFIG_UDPSVD is not set +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y CONFIG_VCONFIG=y CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set CONFIG_FEATURE_WGET_TIMEOUT=y @@ -841,72 +877,76 @@ CONFIG_FEATURE_WGET_TIMEOUT=y # # Print Utilities # -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set -CONFIG_FEATURE_MIME_CHARSET="" -# CONFIG_POPMAILDIR is not set -# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set -# CONFIG_REFORMIME is not set -# CONFIG_FEATURE_REFORMIME_COMPAT is not set -# CONFIG_SENDMAIL is not set +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set -# CONFIG_PMAP is not set -# CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set CONFIG_FREE=y -# CONFIG_FUSER is not set -CONFIG_KILL=y -CONFIG_KILLALL=y +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set # CONFIG_KILLALL5 is not set -# CONFIG_NMETER is not set # CONFIG_PGREP is not set CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y # CONFIG_PKILL is not set CONFIG_PS=y -CONFIG_FEATURE_PS_WIDE=y -# CONFIG_FEATURE_PS_TIME is not set -# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -# CONFIG_RENICE is not set -# CONFIG_BB_SYSCTL is not set +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_SMP_CPU is not set -# CONFIG_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -# CONFIG_FEATURE_TOPMEM is not set -# CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y CONFIG_WATCH=y # # Runit Utilities # -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y # CONFIG_FEATURE_RUNSVDIR_LOG is not set -# CONFIG_SV is not set -CONFIG_SV_DEFAULT_SERVICE_DIR="" -# CONFIG_SVLOGD is not set -# CONFIG_CHPST is not set -# CONFIG_SETUIDGID is not set -# CONFIG_ENVUIDGID is not set -# CONFIG_ENVDIR is not set -# CONFIG_SOFTLIMIT is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y # CONFIG_CHCON is not set # CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set # CONFIG_GETENFORCE is not set @@ -926,20 +966,21 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # # Shells # -CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set # CONFIG_ASH_JOB_CONTROL is not set -CONFIG_ASH_ALIAS=y +# CONFIG_ASH_ALIAS is not set # CONFIG_ASH_GETOPTS is not set # CONFIG_ASH_BUILTIN_ECHO is not set # CONFIG_ASH_BUILTIN_PRINTF 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=y +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set # CONFIG_ASH_RANDOM_SUPPORT is not set # CONFIG_ASH_EXPAND_PRMT is not set -# CONFIG_CTTYHACK is not set +CONFIG_CTTYHACK=y # CONFIG_HUSH is not set # CONFIG_HUSH_BASH_COMPAT is not set # CONFIG_HUSH_BRACE_EXPANSION is not set @@ -957,30 +998,32 @@ CONFIG_ASH_OPTIMIZE_FOR_SIZE=y # CONFIG_HUSH_EXPORT_N is not set # CONFIG_HUSH_MODE_X is not set # CONFIG_MSH is not set -CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_FEATURE_SH_IS_NONE=y # CONFIG_FEATURE_BASH_IS_ASH is not set # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y -CONFIG_SH_MATH_SUPPORT=y +# CONFIG_SH_MATH_SUPPORT is not set # CONFIG_SH_MATH_SUPPORT_64 is not set -CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities # -CONFIG_SYSLOGD=y -CONFIG_FEATURE_ROTATE_LOGFILE=y -CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set # CONFIG_FEATURE_SYSLOGD_DUP is not set -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 # CONFIG_LOGREAD is not set # CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set CONFIG_KLOGD=y CONFIG_FEATURE_KLOGD_KLOGCTL=y -CONFIG_LOGGER=y +# CONFIG_LOGGER is not set diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/android_ndk_defconfig similarity index 52% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/android_ndk_defconfig index 373651d2fd..bf8827a584 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/android_ndk_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.20.0.git +# Fri Mar 2 16:53:26 2012 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,7 +12,7 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set +CONFIG_DESKTOP=y # CONFIG_EXTRA_COMPAT is not set # CONFIG_INCLUDE_SUSv2 is not set # CONFIG_USE_PORTABLE_CODE is not set @@ -20,13 +20,13 @@ CONFIG_PLATFORM_LINUX=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_SHOW_USAGE is not set # CONFIG_FEATURE_VERBOSE_USAGE is not set # CONFIG_FEATURE_COMPRESS_USAGE is not set # CONFIG_FEATURE_INSTALLER is not set # CONFIG_INSTALL_NO_USR is not set # CONFIG_LOCALE_SUPPORT is not set -CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_SUPPORT is not set # CONFIG_UNICODE_USING_LOCALE is not set # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=0 @@ -36,13 +36,13 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 # CONFIG_UNICODE_BIDI_SUPPORT is not set # CONFIG_UNICODE_NEUTRAL_TABLE is not set # CONFIG_UNICODE_PRESERVE_BROKEN is not set -CONFIG_LONG_OPTS=y -CONFIG_FEATURE_DEVPTS=y +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set # CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_WTMP is not set # CONFIG_FEATURE_UTMP is not set -CONFIG_FEATURE_PIDFILE=y -CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set # CONFIG_FEATURE_SUID_CONFIG is not set # CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set @@ -60,9 +60,13 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_BUILD_LIBBUSYBOX is not set # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set -CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" -CONFIG_EXTRA_CFLAGS="" +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" +CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm" +CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers" +CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o" +CONFIG_EXTRA_LDLIBS="dl m c gcc" + # # Debugging Options @@ -89,25 +93,30 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 -CONFIG_FEATURE_FAST_TOP=y +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_FEATURE_EDITING=y -CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 +CONFIG_FEATURE_EDITING_HISTORY=0 # CONFIG_FEATURE_EDITING_SAVEHISTORY is not set -CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set # CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set -CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_NON_POSIX_CP is not set # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set # CONFIG_MONOTONIC_SYSCALL is not set -CONFIG_IOCTL_HEX2STR_ERROR=y +# CONFIG_IOCTL_HEX2STR_ERROR is not set # CONFIG_FEATURE_HWIB is not set # @@ -117,105 +126,110 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y -# CONFIG_FEATURE_SEAMLESS_Z is not set -# CONFIG_AR is not set -# CONFIG_FEATURE_AR_LONG_FILENAMES is not set -# CONFIG_FEATURE_AR_CREATE is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_FEATURE_CPIO_O is not set -# CONFIG_FEATURE_CPIO_P is not set -# CONFIG_DPKG is not set -# CONFIG_DPKG_DEB is not set +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -# CONFIG_LZOP is not set -# CONFIG_LZOP_COMPR_HIGH is not set -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set +CONFIG_GZIP_FAST=0 +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y CONFIG_TAR=y CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set +CONFIG_FEATURE_TAR_AUTODETECT=y CONFIG_FEATURE_TAR_FROM=y CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set # CONFIG_FEATURE_TAR_TO_COMMAND is not set -# CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set -# CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set -# CONFIG_BASE64 is not set -# CONFIG_CAL is not set -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y # CONFIG_FEATURE_CP_LONG_OPTIONS is not set CONFIG_CUT=y CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set +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 is not set -# CONFIG_EXPAND is not set +CONFIG_EXPAND=y # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set CONFIG_EXPR=y CONFIG_EXPR_MATH_SUPPORT_64=y -# CONFIG_FALSE is not set -# CONFIG_FOLD is not set -# CONFIG_FSYNC is not set +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set -# CONFIG_INSTALL is not set +CONFIG_INSTALL=y # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y @@ -230,58 +244,56 @@ CONFIG_FEATURE_LS_USERNAME=y CONFIG_MD5SUM=y CONFIG_MKDIR=y # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set -# CONFIG_MKNOD is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y CONFIG_MV=y # CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set +CONFIG_NICE=y CONFIG_NOHUP=y -# CONFIG_OD is not set -# CONFIG_PRINTENV is not set +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set -# CONFIG_SHA256SUM is not set -# CONFIG_SHA512SUM is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y # CONFIG_STAT is not set # CONFIG_FEATURE_STAT_FORMAT is not set -# CONFIG_STTY is not set -# CONFIG_SUM is not set +CONFIG_STTY=y +CONFIG_SUM=y CONFIG_SYNC=y -# CONFIG_TAC is not set +CONFIG_TAC=y CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TRUE=y # CONFIG_TTY is not set CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set +CONFIG_UNEXPAND=y # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -# CONFIG_UNIQ is not set +CONFIG_UNIQ=y CONFIG_USLEEP=y -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y -# CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -301,65 +313,58 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # -# CONFIG_CHVT is not set -# CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set -# CONFIG_DEALLOCVT is not set -# CONFIG_DUMPKMAP is not set +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y # CONFIG_KBD_MODE is not set # CONFIG_LOADFONT is not set -# CONFIG_LOADKMAP is not set -# CONFIG_OPENVT is not set -# CONFIG_RESET is not set -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set -# CONFIG_SETCONSOLE is not set +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 is not set # CONFIG_SETFONT is not set # CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set CONFIG_DEFAULT_SETFONT_DIR="" -# CONFIG_SETKEYCODES is not set -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y # CONFIG_FEATURE_LOADFONT_PSF2 is not set # CONFIG_FEATURE_LOADFONT_RAW is not set # # Debian Utilities # -# CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y # CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -# CONFIG_START_STOP_DAEMON is not set -# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +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 is not set CONFIG_WHICH=y # # Editors # -# CONFIG_PATCH is not set -CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_ED is not set -CONFIG_SED=y +CONFIG_PATCH=y CONFIG_VI=y CONFIG_FEATURE_VI_MAX_LEN=4096 -# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_8BIT=y CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -367,7 +372,15 @@ CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y CONFIG_FEATURE_VI_ASK_TERMINAL=y -# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -375,66 +388,67 @@ CONFIG_FEATURE_ALLOW_EXEC=y # CONFIG_FIND=y CONFIG_FEATURE_FIND_PRINT0=y -# CONFIG_FEATURE_FIND_MTIME is not set -# CONFIG_FEATURE_FIND_MMIN is not set -# CONFIG_FEATURE_FIND_PERM is not set -# CONFIG_FEATURE_FIND_TYPE is not set -# CONFIG_FEATURE_FIND_XDEV is not set -# CONFIG_FEATURE_FIND_MAXDEPTH is not set -# CONFIG_FEATURE_FIND_NEWER is not set -# CONFIG_FEATURE_FIND_INUM is not set +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 is not set -# CONFIG_FEATURE_FIND_GROUP is not set +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y CONFIG_FEATURE_FIND_NOT=y -# CONFIG_FEATURE_FIND_DEPTH is not set -# CONFIG_FEATURE_FIND_PAREN is not set -# CONFIG_FEATURE_FIND_SIZE is not set -# CONFIG_FEATURE_FIND_PRUNE is not set -# CONFIG_FEATURE_FIND_DELETE is not set -# CONFIG_FEATURE_FIND_PATH is not set -# CONFIG_FEATURE_FIND_REGEX is not set +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 is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_FEATURE_GREP_EGREP_ALIAS=y CONFIG_FEATURE_GREP_FGREP_ALIAS=y CONFIG_FEATURE_GREP_CONTEXT=y -# CONFIG_XARGS is not set -# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set -# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set -# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set -# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set +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_BOOTCHARTD is not set -# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set -# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set -# CONFIG_HALT is not set +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" -# CONFIG_INIT is not set -# CONFIG_FEATURE_USE_INITTAB is not set +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y # CONFIG_FEATURE_KILL_REMOVED is not set CONFIG_FEATURE_KILL_DELAY=0 -# CONFIG_FEATURE_INIT_SCTTY is not set -# CONFIG_FEATURE_INIT_SYSLOG is not set -# CONFIG_FEATURE_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_MESG is not set +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_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # # CONFIG_ADD_SHELL is not set # CONFIG_REMOVE_SHELL is not set -CONFIG_FEATURE_SHADOWPASSWDS=y -CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set # CONFIG_USE_BB_CRYPT is not set # CONFIG_USE_BB_CRYPT_SHA is not set # CONFIG_ADDUSER is not set @@ -449,7 +463,8 @@ CONFIG_LAST_SYSTEM_ID=0 # CONFIG_DELGROUP is not set # CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set # CONFIG_GETTY is not set -CONFIG_LOGIN=y +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -458,6 +473,7 @@ CONFIG_LOGIN=y # CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set # CONFIG_CRYPTPW is not set # CONFIG_CHPASSWD is not set +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="" # CONFIG_SU is not set # CONFIG_FEATURE_SU_SYSLOG is not set # CONFIG_FEATURE_SU_CHECKS_SHELLS is not set @@ -467,128 +483,122 @@ CONFIG_LOGIN=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set -# CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y # # Linux Module Utilities # -# CONFIG_MODINFO is not set -# CONFIG_MODPROBE_SMALL is not set -# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set -# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" # # Linux System Utilities # -# CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set +CONFIG_BLOCKDEV=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_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set CONFIG_BLKID=y +CONFIG_FEATURE_BLKID_TYPE=y CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y -# CONFIG_FBSET is not set -# CONFIG_FEATURE_FBSET_FANCY is not set -# CONFIG_FEATURE_FBSET_READMODE is not set -# CONFIG_FDFLUSH is not set -# CONFIG_FDFORMAT is not set -# CONFIG_FDISK is not set +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 is not set +CONFIG_FEATURE_FDISK_WRITABLE=y # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set # CONFIG_FEATURE_SUN_LABEL is not set # CONFIG_FEATURE_OSF_LABEL is not set # CONFIG_FEATURE_GPT_LABEL is not set -# CONFIG_FEATURE_FDISK_ADVANCED is not set -# CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set -# CONFIG_FREERAMDISK is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set # CONFIG_MKFS_MINIX is not set # CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set # CONFIG_MKFS_VFAT is not set -# CONFIG_GETOPT is not set -# CONFIG_FEATURE_GETOPT_LONG is not set -# CONFIG_HEXDUMP is not set -# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set -# CONFIG_HWCLOCK is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y # CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set # CONFIG_IPCRM is not set # CONFIG_IPCS is not set -# CONFIG_LOSETUP is not set -# CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set -# CONFIG_MDEV is not set -# CONFIG_FEATURE_MDEV_CONF is not set -# CONFIG_FEATURE_MDEV_RENAME is not set -# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set -# CONFIG_FEATURE_MDEV_EXEC is not set -# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -# CONFIG_MKSWAP is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set # CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set -# CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set -# CONFIG_RTCWAKE is not set -# CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set -# CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y +CONFIG_SWITCH_ROOT=y +# CONFIG_UMOUNT is not set # CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set # CONFIG_FEATURE_MTAB_SUPPORT is not set CONFIG_VOLUMEID=y @@ -596,167 +606,179 @@ CONFIG_VOLUMEID=y # Filesystem/Volume identification # CONFIG_FEATURE_VOLUMEID_EXT=y -# CONFIG_FEATURE_VOLUMEID_BTRFS is not set -# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set -# CONFIG_FEATURE_VOLUMEID_JFS is not set -# CONFIG_FEATURE_VOLUMEID_XFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y CONFIG_FEATURE_VOLUMEID_NTFS=y -# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set -# CONFIG_FEATURE_VOLUMEID_UDF is not set -# CONFIG_FEATURE_VOLUMEID_LUKS is not set +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y -# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set -# CONFIG_FEATURE_VOLUMEID_ROMFS is not set -# CONFIG_FEATURE_VOLUMEID_SYSV is not set -# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set -# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +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 # # Miscellaneous Utilities # # CONFIG_CONSPY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y # CONFIG_NANDWRITE is not set -# CONFIG_NANDDUMP is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 -# CONFIG_CHAT is not set -# CONFIG_FEATURE_CHAT_NOFAIL is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y # CONFIG_FEATURE_CHAT_TTY_HIFI is not set -# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set -# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set -# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set -# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set -# CONFIG_FEATURE_CHAT_CLR_ABORT is not set -# CONFIG_CHRT is not set +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_FEATURE_CROND_D is not set -# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y CONFIG_FEATURE_CROND_DIR="/var/spool/cron" -# CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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=y -# CONFIG_DEVMEM is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set -# CONFIG_FBSPLASH is not set -# CONFIG_FLASHCP is not set -# CONFIG_FLASH_LOCK is not set -# CONFIG_FLASH_UNLOCK is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y # CONFIG_FLASH_ERASEALL is not set # CONFIG_IONICE is not set -# CONFIG_INOTIFYD is not set +CONFIG_INOTIFYD=y # CONFIG_LAST is not set # CONFIG_FEATURE_LAST_SMALL is not set # CONFIG_FEATURE_LAST_FANCY is not set -CONFIG_LESS=y -CONFIG_FEATURE_LESS_MAXLINES=9999999 -# CONFIG_FEATURE_LESS_BRACKETS is not set -# CONFIG_FEATURE_LESS_FLAGS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP is not set -# CONFIG_FEATURE_LESS_WINCH is not set -# CONFIG_FEATURE_LESS_DASHCMD is not set -# CONFIG_FEATURE_LESS_LINENUMS is not set -# CONFIG_HDPARM is not set -# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set -# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set -# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set -# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set -# CONFIG_MAKEDEVS is not set +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 is not set -# CONFIG_MAN is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y # CONFIG_MICROCOM is not set # CONFIG_MOUNTPOINT is not set # CONFIG_MT is not set -# CONFIG_RAIDAUTORUN is not set +CONFIG_RAIDAUTORUN=y # CONFIG_READAHEAD is not set # CONFIG_RFKILL is not set # CONFIG_RUNLEVEL is not set -# CONFIG_RX is not set -# CONFIG_SETSID is not set +CONFIG_RX=y +CONFIG_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set -# CONFIG_TIME is not set -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set # CONFIG_WATCHDOG is not set # # Networking Utilities # -# CONFIG_NBDCLIENT is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y CONFIG_NC=y -# CONFIG_NC_SERVER is not set +CONFIG_NC_SERVER=y CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +# CONFIG_PING6 is not set +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set -CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set -# CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set # CONFIG_HOSTNAME is not set -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set -# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set -# CONFIG_FEATURE_HTTPD_SETUID is not set -# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set -# CONFIG_FEATURE_HTTPD_CGI is not set -# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set -# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set -# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set -# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set -# CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set +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_FEATURE_HTTPD_GZIP=y CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y # CONFIG_FEATURE_IFCONFIG_SLIP is not set -# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y CONFIG_FEATURE_IFCONFIG_HW=y CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set -# CONFIG_IFUPDOWN is not set -CONFIG_IFUPDOWN_IFSTATE_PATH="" -# CONFIG_FEATURE_IFUPDOWN_IP is not set -# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set +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 is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set -# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set -# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y # CONFIG_INETD is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set @@ -764,75 +786,76 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set # CONFIG_FEATURE_INETD_RPC is not set -# CONFIG_IP is not set -# CONFIG_FEATURE_IP_ADDRESS is not set -# CONFIG_FEATURE_IP_LINK is not set -# CONFIG_FEATURE_IP_ROUTE is not set -# CONFIG_FEATURE_IP_TUNNEL is not set -# CONFIG_FEATURE_IP_RULE is not set -# CONFIG_FEATURE_IP_SHORT_FORMS is not set +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 is not set -# CONFIG_IPADDR is not set -# CONFIG_IPLINK is not set -# CONFIG_IPROUTE is not set -# CONFIG_IPTUNNEL is not set -# CONFIG_IPRULE is not set -# CONFIG_IPCALC is not set -# CONFIG_FEATURE_IPCALC_FANCY is not set +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 is not set -# CONFIG_NAMEIF is not set -# CONFIG_FEATURE_NAMEIF_EXTENDED is not set CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y -# CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -# CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y # CONFIG_SLATTACH is not set -# CONFIG_TCPSVD is not set +CONFIG_TCPSVD=y CONFIG_TELNET=y -# CONFIG_FEATURE_TELNET_TTYPE is not set -# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y CONFIG_TELNETD=y CONFIG_FEATURE_TELNETD_STANDALONE=y -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set -# CONFIG_TFTP is not set -# CONFIG_TFTPD is not set -# CONFIG_FEATURE_TFTP_GET is not set -# CONFIG_FEATURE_TFTP_PUT is not set -# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set -# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y # CONFIG_TFTP_DEBUG is not set CONFIG_TRACEROUTE=y # CONFIG_TRACEROUTE6 is not set CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set # CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y -# CONFIG_FEATURE_UDHCPC_ARPING is not set -# CONFIG_FEATURE_UDHCP_PORT is not set -CONFIG_UDHCP_DEBUG=0 -# CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set -CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 -CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" -# CONFIG_UDPSVD is not set +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y CONFIG_VCONFIG=y CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set CONFIG_FEATURE_WGET_TIMEOUT=y @@ -841,72 +864,76 @@ CONFIG_FEATURE_WGET_TIMEOUT=y # # Print Utilities # -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set -CONFIG_FEATURE_MIME_CHARSET="" -# CONFIG_POPMAILDIR is not set -# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set -# CONFIG_REFORMIME is not set -# CONFIG_FEATURE_REFORMIME_COMPAT is not set -# CONFIG_SENDMAIL is not set +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set -# CONFIG_PMAP is not set -# CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set CONFIG_FREE=y -# CONFIG_FUSER is not set -CONFIG_KILL=y -CONFIG_KILLALL=y +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set # CONFIG_KILLALL5 is not set -# CONFIG_NMETER is not set # CONFIG_PGREP is not set CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y # CONFIG_PKILL is not set CONFIG_PS=y -CONFIG_FEATURE_PS_WIDE=y -# CONFIG_FEATURE_PS_TIME is not set -# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -# CONFIG_RENICE is not set -# CONFIG_BB_SYSCTL is not set +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_SMP_CPU is not set -# CONFIG_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -# CONFIG_FEATURE_TOPMEM is not set -# CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y CONFIG_WATCH=y # # Runit Utilities # -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y # CONFIG_FEATURE_RUNSVDIR_LOG is not set -# CONFIG_SV is not set -CONFIG_SV_DEFAULT_SERVICE_DIR="" -# CONFIG_SVLOGD is not set -# CONFIG_CHPST is not set -# CONFIG_SETUIDGID is not set -# CONFIG_ENVUIDGID is not set -# CONFIG_ENVDIR is not set -# CONFIG_SOFTLIMIT is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y # CONFIG_CHCON is not set # CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set # CONFIG_GETENFORCE is not set @@ -926,20 +953,21 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # # Shells # -CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set # CONFIG_ASH_JOB_CONTROL is not set -CONFIG_ASH_ALIAS=y +# CONFIG_ASH_ALIAS is not set # CONFIG_ASH_GETOPTS is not set # CONFIG_ASH_BUILTIN_ECHO is not set # CONFIG_ASH_BUILTIN_PRINTF 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=y +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set # CONFIG_ASH_RANDOM_SUPPORT is not set # CONFIG_ASH_EXPAND_PRMT is not set -# CONFIG_CTTYHACK is not set +CONFIG_CTTYHACK=y # CONFIG_HUSH is not set # CONFIG_HUSH_BASH_COMPAT is not set # CONFIG_HUSH_BRACE_EXPANSION is not set @@ -957,30 +985,32 @@ CONFIG_ASH_OPTIMIZE_FOR_SIZE=y # CONFIG_HUSH_EXPORT_N is not set # CONFIG_HUSH_MODE_X is not set # CONFIG_MSH is not set -CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_FEATURE_SH_IS_NONE=y # CONFIG_FEATURE_BASH_IS_ASH is not set # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y -CONFIG_SH_MATH_SUPPORT=y +# CONFIG_SH_MATH_SUPPORT is not set # CONFIG_SH_MATH_SUPPORT_64 is not set -CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities # -CONFIG_SYSLOGD=y -CONFIG_FEATURE_ROTATE_LOGFILE=y -CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set # CONFIG_FEATURE_SYSLOGD_DUP is not set -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 # CONFIG_FEATURE_IPC_SYSLOG is not set CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 # CONFIG_LOGREAD is not set # CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set CONFIG_KLOGD=y CONFIG_FEATURE_KLOGD_KLOGCTL=y -CONFIG_LOGGER=y +# CONFIG_LOGGER is not set diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/cygwin_defconfig similarity index 55% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/cygwin_defconfig index 373651d2fd..bdd0d66d0a 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/cygwin_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.19.0.git +# Sun Jul 10 12:48:50 2011 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,24 +12,24 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set +CONFIG_DESKTOP=y # CONFIG_EXTRA_COMPAT is not set -# CONFIG_INCLUDE_SUSv2 is not set +CONFIG_INCLUDE_SUSv2=y # CONFIG_USE_PORTABLE_CODE is not set CONFIG_PLATFORM_LINUX=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 is not set -# CONFIG_FEATURE_COMPRESS_USAGE is not set -# CONFIG_FEATURE_INSTALLER is not set +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y # CONFIG_INSTALL_NO_USR is not set # CONFIG_LOCALE_SUPPORT is not set CONFIG_UNICODE_SUPPORT=y # CONFIG_UNICODE_USING_LOCALE is not set # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set -CONFIG_SUBST_WCHAR=0 +CONFIG_SUBST_WCHAR=65533 CONFIG_LAST_SUPPORTED_WCHAR=0 # CONFIG_UNICODE_COMBINING_WCHARS is not set # CONFIG_UNICODE_WIDE_WCHARS is not set @@ -39,8 +39,8 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 CONFIG_LONG_OPTS=y CONFIG_FEATURE_DEVPTS=y # CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_WTMP is not set # CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set CONFIG_FEATURE_PIDFILE=y CONFIG_FEATURE_SUID=y # CONFIG_FEATURE_SUID_CONFIG is not set @@ -61,7 +61,7 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +CONFIG_CROSS_COMPILER_PREFIX="" CONFIG_EXTRA_CFLAGS="" # @@ -89,16 +89,18 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +CONFIG_FEATURE_RTMINMAX=y CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y CONFIG_FEATURE_EDITING=y CONFIG_FEATURE_EDITING_MAX_LEN=1024 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 -# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_EDITING_HISTORY=255 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set CONFIG_FEATURE_EDITING_FANCY_PROMPT=y @@ -106,9 +108,10 @@ CONFIG_FEATURE_EDITING_FANCY_PROMPT=y CONFIG_FEATURE_NON_POSIX_CP=y # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y # CONFIG_MONOTONIC_SYSCALL is not set CONFIG_IOCTL_HEX2STR_ERROR=y -# CONFIG_FEATURE_HWIB is not set +CONFIG_FEATURE_HWIB=y # # Applets @@ -117,48 +120,48 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y # CONFIG_FEATURE_SEAMLESS_Z is not set # CONFIG_AR is not set # CONFIG_FEATURE_AR_LONG_FILENAMES is not set # CONFIG_FEATURE_AR_CREATE is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_FEATURE_CPIO_O is not set -# CONFIG_FEATURE_CPIO_P is not set +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y # CONFIG_DPKG is not set # CONFIG_DPKG_DEB is not set # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y -# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -# CONFIG_LZOP is not set +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y # CONFIG_LZOP_COMPR_HIGH is not set -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y CONFIG_TAR=y CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set +CONFIG_FEATURE_TAR_AUTODETECT=y CONFIG_FEATURE_TAR_FROM=y CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y -# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set -# CONFIG_FEATURE_TAR_TO_COMMAND is not set -# CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set # CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils @@ -169,55 +172,56 @@ CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y # CONFIG_FEATURE_DATE_NANO is not set CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_ID=y +CONFIG_GROUPS=y CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set -# CONFIG_BASE64 is not set -# CONFIG_CAL is not set -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y -# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y -# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_FEATURE_CP_LONG_OPTIONS=y CONFIG_CUT=y CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y CONFIG_DF=y -# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_FEATURE_DF_FANCY=y CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y CONFIG_DU=y -CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set CONFIG_ECHO=y CONFIG_FEATURE_FANCY_ECHO=y CONFIG_ENV=y -# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set -# CONFIG_EXPAND is not set -# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +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 is not set -# CONFIG_FOLD is not set -# CONFIG_FSYNC is not set +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set -# CONFIG_INSTALL is not set -# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set +CONFIG_HOSTID=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y CONFIG_LN=y -# CONFIG_LOGNAME is not set +CONFIG_LOGNAME=y CONFIG_LS=y CONFIG_FEATURE_LS_FILETYPES=y CONFIG_FEATURE_LS_FOLLOWLINKS=y @@ -225,63 +229,62 @@ CONFIG_FEATURE_LS_RECURSIVE=y CONFIG_FEATURE_LS_SORTFILES=y CONFIG_FEATURE_LS_TIMESTAMPS=y CONFIG_FEATURE_LS_USERNAME=y -# CONFIG_FEATURE_LS_COLOR is not set -# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y CONFIG_MD5SUM=y CONFIG_MKDIR=y -# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set -# CONFIG_MKNOD is not set +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y CONFIG_MV=y -# CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y CONFIG_NOHUP=y -# CONFIG_OD is not set -# CONFIG_PRINTENV is not set +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y -# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set -# CONFIG_SHA256SUM is not set -# CONFIG_SHA512SUM is not set +CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y # CONFIG_STAT is not set # CONFIG_FEATURE_STAT_FORMAT is not set -# CONFIG_STTY is not set -# CONFIG_SUM is not set +CONFIG_STTY=y +CONFIG_SUM=y CONFIG_SYNC=y -# CONFIG_TAC is not set +CONFIG_TAC=y CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TRUE=y -# CONFIG_TTY is not set +CONFIG_TTY=y CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set -# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -# CONFIG_UNIQ is not set +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y CONFIG_USLEEP=y -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y # CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -301,23 +304,23 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # # CONFIG_CHVT is not set # CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set +CONFIG_CLEAR=y # CONFIG_DEALLOCVT is not set # CONFIG_DUMPKMAP is not set # CONFIG_KBD_MODE is not set # CONFIG_LOADFONT is not set # CONFIG_LOADKMAP is not set # CONFIG_OPENVT is not set -# CONFIG_RESET is not set -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y # CONFIG_SETCONSOLE is not set # CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set # CONFIG_SETFONT is not set @@ -332,34 +335,27 @@ CONFIG_DEFAULT_SETFONT_DIR="" # # Debian Utilities # -# CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set -# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -# CONFIG_START_STOP_DAEMON is not set -# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set -# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +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_PATCH is not set -CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_ED is not set -CONFIG_SED=y +CONFIG_PATCH=y CONFIG_VI=y CONFIG_FEATURE_VI_MAX_LEN=4096 # CONFIG_FEATURE_VI_8BIT is not set CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -367,7 +363,15 @@ CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y CONFIG_FEATURE_VI_ASK_TERMINAL=y -# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -375,36 +379,36 @@ CONFIG_FEATURE_ALLOW_EXEC=y # CONFIG_FIND=y CONFIG_FEATURE_FIND_PRINT0=y -# CONFIG_FEATURE_FIND_MTIME is not set -# CONFIG_FEATURE_FIND_MMIN is not set -# CONFIG_FEATURE_FIND_PERM is not set -# CONFIG_FEATURE_FIND_TYPE is not set -# CONFIG_FEATURE_FIND_XDEV is not set -# CONFIG_FEATURE_FIND_MAXDEPTH is not set -# CONFIG_FEATURE_FIND_NEWER is not set -# CONFIG_FEATURE_FIND_INUM is not set +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 is not set -# CONFIG_FEATURE_FIND_GROUP is not set +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y CONFIG_FEATURE_FIND_NOT=y -# CONFIG_FEATURE_FIND_DEPTH is not set -# CONFIG_FEATURE_FIND_PAREN is not set -# CONFIG_FEATURE_FIND_SIZE is not set -# CONFIG_FEATURE_FIND_PRUNE is not set -# CONFIG_FEATURE_FIND_DELETE is not set -# CONFIG_FEATURE_FIND_PATH is not set -# CONFIG_FEATURE_FIND_REGEX is not set +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 is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_FEATURE_GREP_EGREP_ALIAS=y CONFIG_FEATURE_GREP_FGREP_ALIAS=y CONFIG_FEATURE_GREP_CONTEXT=y -# CONFIG_XARGS is not set -# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set -# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set -# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set -# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set +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 @@ -425,55 +429,53 @@ CONFIG_FEATURE_KILL_DELAY=0 # CONFIG_FEATURE_INIT_COREDUMPS is not set # CONFIG_FEATURE_INITRD is not set CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_MESG is not set +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # -# CONFIG_ADD_SHELL is not set -# CONFIG_REMOVE_SHELL is not set +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y CONFIG_FEATURE_SHADOWPASSWDS=y CONFIG_USE_BB_PWD_GRP=y CONFIG_USE_BB_SHADOW=y -# CONFIG_USE_BB_CRYPT is not set -# CONFIG_USE_BB_CRYPT_SHA is not set -# CONFIG_ADDUSER is not set -# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y # CONFIG_FEATURE_CHECK_NAMES is not set -CONFIG_FIRST_SYSTEM_ID=0 -CONFIG_LAST_SYSTEM_ID=0 -# CONFIG_ADDGROUP is not set -# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set -# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set -# CONFIG_DELUSER is not set -# CONFIG_DELGROUP is not set -# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_DELUSER=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y # CONFIG_GETTY is not set CONFIG_LOGIN=y # CONFIG_PAM is not set -# CONFIG_LOGIN_SCRIPTS is not set -# CONFIG_FEATURE_NOLOGIN is not set -# CONFIG_FEATURE_SECURETTY is not set -# CONFIG_PASSWD is not set -# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set -# CONFIG_CRYPTPW is not set -# CONFIG_CHPASSWD is not set -# CONFIG_SU is not set -# CONFIG_FEATURE_SU_SYSLOG is not set -# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set -# CONFIG_SULOGIN is not set -# CONFIG_VLOCK 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 is not set -# CONFIG_E2FSCK is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set # CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set # CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set # # Linux Module Utilities @@ -482,47 +484,48 @@ CONFIG_LOGIN=y # CONFIG_MODPROBE_SMALL is not set # CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set # CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set # # Options common to multiple modutils # -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" # # Linux System Utilities # # CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set +CONFIG_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set -CONFIG_BLKID=y -CONFIG_DMESG=y -CONFIG_FEATURE_DMESG_PRETTY=y +# CONFIG_BLKID is not set +# CONFIG_FEATURE_BLKID_TYPE is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set # CONFIG_FBSET is not set # CONFIG_FEATURE_FBSET_FANCY is not set # CONFIG_FEATURE_FBSET_READMODE is not set # CONFIG_FDFLUSH is not set # CONFIG_FDFORMAT is not set # CONFIG_FDISK is not set -CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set # CONFIG_FEATURE_FDISK_WRITABLE is not set # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set @@ -531,23 +534,23 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_GPT_LABEL is not set # CONFIG_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set +CONFIG_FLOCK=y # CONFIG_FREERAMDISK is not set -# CONFIG_FSCK_MINIX is not set +CONFIG_FSCK_MINIX=y # CONFIG_MKFS_EXT2 is not set # CONFIG_MKFS_MINIX is not set -# CONFIG_FEATURE_MINIX2 is not set +CONFIG_FEATURE_MINIX2=y # CONFIG_MKFS_REISER is not set # CONFIG_MKFS_VFAT is not set -# CONFIG_GETOPT is not set -# CONFIG_FEATURE_GETOPT_LONG is not set -# CONFIG_HEXDUMP is not set -# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y # CONFIG_HWCLOCK is not set # CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set -# CONFIG_IPCRM is not set +CONFIG_IPCRM=y # CONFIG_IPCS is not set # CONFIG_LOSETUP is not set # CONFIG_LSPCI is not set @@ -558,55 +561,47 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set # CONFIG_FEATURE_MDEV_EXEC is not set # CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -# CONFIG_MKSWAP is not set +CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set # CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set -# CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y # CONFIG_RTCWAKE is not set -# CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set # CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y +# CONFIG_UMOUNT is not set # CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set # CONFIG_FEATURE_MTAB_SUPPORT is not set -CONFIG_VOLUMEID=y - -# -# Filesystem/Volume identification -# -CONFIG_FEATURE_VOLUMEID_EXT=y +# CONFIG_VOLUMEID is not set +# CONFIG_FEATURE_VOLUMEID_EXT is not set # CONFIG_FEATURE_VOLUMEID_BTRFS is not set # CONFIG_FEATURE_VOLUMEID_REISERFS is not set -CONFIG_FEATURE_VOLUMEID_FAT=y +# CONFIG_FEATURE_VOLUMEID_FAT is not set # CONFIG_FEATURE_VOLUMEID_HFS is not set # CONFIG_FEATURE_VOLUMEID_JFS is not set # CONFIG_FEATURE_VOLUMEID_XFS is not set -CONFIG_FEATURE_VOLUMEID_NTFS=y +# CONFIG_FEATURE_VOLUMEID_NTFS is not set # CONFIG_FEATURE_VOLUMEID_ISO9660 is not set # CONFIG_FEATURE_VOLUMEID_UDF is not set # CONFIG_FEATURE_VOLUMEID_LUKS is not set -CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set # CONFIG_FEATURE_VOLUMEID_CRAMFS is not set # CONFIG_FEATURE_VOLUMEID_ROMFS is not set # CONFIG_FEATURE_VOLUMEID_SYSV is not set @@ -619,36 +614,41 @@ CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y # CONFIG_CONSPY is not set # CONFIG_NANDWRITE is not set # CONFIG_NANDDUMP is not set +# CONFIG_SETSERIAL is not set # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set # CONFIG_ADJTIMEX is not set # CONFIG_BBCONFIG is not set # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set # CONFIG_BEEP is not set CONFIG_FEATURE_BEEP_FREQ=0 CONFIG_FEATURE_BEEP_LENGTH_MS=0 -# CONFIG_CHAT is not set -# CONFIG_FEATURE_CHAT_NOFAIL is not set +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y # CONFIG_FEATURE_CHAT_TTY_HIFI is not set -# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set -# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set -# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set -# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set -# CONFIG_FEATURE_CHAT_CLR_ABORT is not set -# CONFIG_CHRT is not set +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_FEATURE_CROND_D is not set -# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y CONFIG_FEATURE_CROND_DIR="/var/spool/cron" -# CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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=y -# CONFIG_DEVMEM is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set # CONFIG_FBSPLASH is not set @@ -663,13 +663,13 @@ CONFIG_FEATURE_DEVFS=y # CONFIG_FEATURE_LAST_FANCY is not set CONFIG_LESS=y CONFIG_FEATURE_LESS_MAXLINES=9999999 -# CONFIG_FEATURE_LESS_BRACKETS is not set -# CONFIG_FEATURE_LESS_FLAGS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP is not set -# CONFIG_FEATURE_LESS_WINCH is not set -# CONFIG_FEATURE_LESS_DASHCMD is not set -# CONFIG_FEATURE_LESS_LINENUMS is not set +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y # CONFIG_HDPARM is not set # CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set # CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set @@ -680,72 +680,78 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 # CONFIG_MAKEDEVS is not set # CONFIG_FEATURE_MAKEDEVS_LEAF is not set # CONFIG_FEATURE_MAKEDEVS_TABLE is not set -# CONFIG_MAN is not set +CONFIG_MAN=y # CONFIG_MICROCOM is not set # CONFIG_MOUNTPOINT is not set -# CONFIG_MT is not set +CONFIG_MT=y # CONFIG_RAIDAUTORUN is not set # CONFIG_READAHEAD is not set # CONFIG_RFKILL is not set # CONFIG_RUNLEVEL is not set # CONFIG_RX is not set -# CONFIG_SETSID is not set +CONFIG_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set -# CONFIG_TIME is not set -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set # CONFIG_WATCHDOG is not set # # Networking Utilities # +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set # CONFIG_NBDCLIENT is not set CONFIG_NC=y -# CONFIG_NC_SERVER is not set +CONFIG_NC_SERVER=y CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set -# CONFIG_FEATURE_IPV6 is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +CONFIG_WHOIS=y +CONFIG_FEATURE_IPV6=y # CONFIG_FEATURE_UNIX_LOCAL is not set CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set -CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARP is not set +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set -# CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set -# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set -# CONFIG_HOSTNAME is not set -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=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 is not set -# CONFIG_FEATURE_HTTPD_SETUID is not set -# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set -# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set -# CONFIG_FEATURE_HTTPD_CGI is not set -# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set -# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set -# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set -# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set -# CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set -CONFIG_IFCONFIG=y -CONFIG_FEATURE_IFCONFIG_STATUS=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=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_FEATURE_HTTPD_GZIP=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set # CONFIG_FEATURE_IFCONFIG_SLIP is not set # CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set -CONFIG_FEATURE_IFCONFIG_HW=y -CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set # CONFIG_IFUPDOWN is not set @@ -757,12 +763,12 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set # CONFIG_FEATURE_IFUPDOWN_MAPPING is not set # CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set -# CONFIG_INETD is not set -# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set -# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set -# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set -# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set -# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +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 is not set # CONFIG_IP is not set # CONFIG_FEATURE_IP_ADDRESS is not set @@ -777,136 +783,138 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_IPROUTE is not set # CONFIG_IPTUNNEL is not set # CONFIG_IPRULE is not set -# CONFIG_IPCALC is not set -# CONFIG_FEATURE_IPCALC_FANCY is not set -# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set -# CONFIG_NAMEIF is not set -# CONFIG_FEATURE_NAMEIF_EXTENDED is not set -CONFIG_NETSTAT=y -CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set # CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -# CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y -CONFIG_ROUTE=y +# CONFIG_ROUTE is not set # CONFIG_SLATTACH is not set -# CONFIG_TCPSVD is not set +CONFIG_TCPSVD=y CONFIG_TELNET=y -# CONFIG_FEATURE_TELNET_TTYPE is not set -# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y CONFIG_TELNETD=y CONFIG_FEATURE_TELNETD_STANDALONE=y -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set -# CONFIG_TFTP is not set -# CONFIG_TFTPD is not set -# CONFIG_FEATURE_TFTP_GET is not set -# CONFIG_FEATURE_TFTP_PUT is not set -# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set -# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y # CONFIG_TFTP_DEBUG is not set -CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set -CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set CONFIG_DHCPD_LEASES_FILE="" -CONFIG_UDHCPC=y +# CONFIG_UDHCPC is not set # CONFIG_FEATURE_UDHCPC_ARPING is not set # CONFIG_FEATURE_UDHCP_PORT is not set CONFIG_UDHCP_DEBUG=0 # CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set +# CONFIG_FEATURE_UDHCP_8021Q is not set CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" -# CONFIG_UDPSVD is not set -CONFIG_VCONFIG=y +CONFIG_UDPSVD=y +# CONFIG_VCONFIG is not set CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y -# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_LONG_OPTIONS=y CONFIG_FEATURE_WGET_TIMEOUT=y # CONFIG_ZCIP is not set # # Print Utilities # -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set -CONFIG_FEATURE_MIME_CHARSET="" -# CONFIG_POPMAILDIR is not set -# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set -# CONFIG_REFORMIME is not set -# CONFIG_FEATURE_REFORMIME_COMPAT is not set -# CONFIG_SENDMAIL is not set +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y # CONFIG_PMAP is not set # CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set -CONFIG_FREE=y -# CONFIG_FUSER is not set +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set +CONFIG_FUSER=y CONFIG_KILL=y CONFIG_KILLALL=y -# CONFIG_KILLALL5 is not set -# CONFIG_NMETER is not set -# CONFIG_PGREP is not set +CONFIG_KILLALL5=y +CONFIG_PGREP=y CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set -# CONFIG_PKILL is not set +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 is not set -# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -# CONFIG_RENICE is not set -# CONFIG_BB_SYSCTL is not set +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_SMP_CPU is not set -# CONFIG_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -# CONFIG_FEATURE_TOPMEM is not set +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y # CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y +# CONFIG_UPTIME is not set CONFIG_WATCH=y # # Runit Utilities # -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y # CONFIG_FEATURE_RUNSVDIR_LOG is not set -# CONFIG_SV is not set -CONFIG_SV_DEFAULT_SERVICE_DIR="" -# CONFIG_SVLOGD is not set -# CONFIG_CHPST is not set -# CONFIG_SETUIDGID is not set -# CONFIG_ENVUIDGID is not set -# CONFIG_ENVDIR is not set -# CONFIG_SOFTLIMIT is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y # CONFIG_CHCON is not set # CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set # CONFIG_GETENFORCE is not set @@ -928,34 +936,35 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # CONFIG_ASH=y CONFIG_ASH_BASH_COMPAT=y -# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +CONFIG_ASH_JOB_CONTROL=y CONFIG_ASH_ALIAS=y -# CONFIG_ASH_GETOPTS is not set -# CONFIG_ASH_BUILTIN_ECHO is not set -# CONFIG_ASH_BUILTIN_PRINTF is not set -# CONFIG_ASH_BUILTIN_TEST is not set -# CONFIG_ASH_CMDCMD is not set +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_BUILTIN_ECHO=y +CONFIG_ASH_BUILTIN_PRINTF=y +CONFIG_ASH_BUILTIN_TEST=y +CONFIG_ASH_CMDCMD=y # CONFIG_ASH_MAIL is not set CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -# CONFIG_ASH_RANDOM_SUPPORT is not set -# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y # CONFIG_CTTYHACK is not set -# CONFIG_HUSH is not set -# CONFIG_HUSH_BASH_COMPAT is not set -# CONFIG_HUSH_BRACE_EXPANSION is not set -# CONFIG_HUSH_HELP is not set -# CONFIG_HUSH_INTERACTIVE is not set -# CONFIG_HUSH_SAVEHISTORY is not set -# CONFIG_HUSH_JOB is not set -# CONFIG_HUSH_TICK is not set -# CONFIG_HUSH_IF is not set -# CONFIG_HUSH_LOOPS is not set -# CONFIG_HUSH_CASE is not set -# CONFIG_HUSH_FUNCTIONS is not set -# CONFIG_HUSH_LOCAL is not set -# CONFIG_HUSH_RANDOM_SUPPORT is not set -# CONFIG_HUSH_EXPORT_N is not set -# CONFIG_HUSH_MODE_X is not set +CONFIG_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_BRACE_EXPANSION=y +CONFIG_HUSH_HELP=y +CONFIG_HUSH_INTERACTIVE=y +CONFIG_HUSH_SAVEHISTORY=y +CONFIG_HUSH_JOB=y +CONFIG_HUSH_TICK=y +CONFIG_HUSH_IF=y +CONFIG_HUSH_LOOPS=y +CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_MODE_X=y # CONFIG_MSH is not set CONFIG_FEATURE_SH_IS_ASH=y # CONFIG_FEATURE_SH_IS_HUSH is not set @@ -964,10 +973,11 @@ CONFIG_FEATURE_SH_IS_ASH=y # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y CONFIG_SH_MATH_SUPPORT=y -# CONFIG_SH_MATH_SUPPORT_64 is not set +CONFIG_SH_MATH_SUPPORT_64=y CONFIG_FEATURE_SH_EXTRA_QUIET=y # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_FEATURE_SH_HISTFILESIZE=y # # System Logging Utilities @@ -975,12 +985,13 @@ CONFIG_FEATURE_SH_EXTRA_QUIET=y CONFIG_SYSLOGD=y CONFIG_FEATURE_ROTATE_LOGFILE=y CONFIG_FEATURE_REMOTE_LOG=y -# CONFIG_FEATURE_SYSLOGD_DUP is not set +CONFIG_FEATURE_SYSLOGD_DUP=y +CONFIG_FEATURE_SYSLOGD_CFG=y CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 -# CONFIG_FEATURE_IPC_SYSLOG is not set -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 -# CONFIG_LOGREAD is not set -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -CONFIG_FEATURE_KLOGD_KLOGCTL=y +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set CONFIG_LOGGER=y diff --git a/release/src/router/busybox/config_base b/release/src/router/busybox/configs/freebsd_defconfig similarity index 66% copy from release/src/router/busybox/config_base copy to release/src/router/busybox/configs/freebsd_defconfig index 373651d2fd..dcb5d953c2 100644 --- a/release/src/router/busybox/config_base +++ b/release/src/router/busybox/configs/freebsd_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.18.0 -# Wed Nov 24 20:35:47 2010 +# Busybox version: 1.18.1 +# Tue Dec 21 19:47:40 2010 # CONFIG_HAVE_DOT_CONFIG=y @@ -14,23 +14,23 @@ CONFIG_HAVE_DOT_CONFIG=y # # CONFIG_DESKTOP is not set # CONFIG_EXTRA_COMPAT is not set -# CONFIG_INCLUDE_SUSv2 is not set -# CONFIG_USE_PORTABLE_CODE is not set -CONFIG_PLATFORM_LINUX=y +CONFIG_INCLUDE_SUSv2=y +CONFIG_USE_PORTABLE_CODE=y +# CONFIG_PLATFORM_LINUX is not set 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 is not set -# CONFIG_FEATURE_COMPRESS_USAGE is not set -# CONFIG_FEATURE_INSTALLER is not set +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y # CONFIG_INSTALL_NO_USR is not set -# CONFIG_LOCALE_SUPPORT is not set +CONFIG_LOCALE_SUPPORT=y CONFIG_UNICODE_SUPPORT=y # CONFIG_UNICODE_USING_LOCALE is not set # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set -CONFIG_SUBST_WCHAR=0 -CONFIG_LAST_SUPPORTED_WCHAR=0 +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 # CONFIG_UNICODE_COMBINING_WCHARS is not set # CONFIG_UNICODE_WIDE_WCHARS is not set # CONFIG_UNICODE_BIDI_SUPPORT is not set @@ -43,8 +43,8 @@ CONFIG_FEATURE_DEVPTS=y # CONFIG_FEATURE_UTMP is not set CONFIG_FEATURE_PIDFILE=y CONFIG_FEATURE_SUID=y -# CONFIG_FEATURE_SUID_CONFIG is not set -# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y # CONFIG_SELINUX is not set # CONFIG_FEATURE_PREFER_APPLETS is not set CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" @@ -61,7 +61,7 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y -CONFIG_CROSS_COMPILER_PREFIX="mipsel-uclibc-" +CONFIG_CROSS_COMPILER_PREFIX="" CONFIG_EXTRA_CFLAGS="" # @@ -90,25 +90,25 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_USE_TERMIOS=y CONFIG_FEATURE_EDITING=y CONFIG_FEATURE_EDITING_MAX_LEN=1024 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=50 +CONFIG_FEATURE_EDITING_HISTORY=30 # CONFIG_FEATURE_EDITING_SAVEHISTORY is not set CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set # CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set CONFIG_FEATURE_NON_POSIX_CP=y # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 # CONFIG_MONOTONIC_SYSCALL is not set CONFIG_IOCTL_HEX2STR_ERROR=y -# CONFIG_FEATURE_HWIB is not set +CONFIG_FEATURE_HWIB=y # # Applets @@ -117,17 +117,17 @@ CONFIG_IOCTL_HEX2STR_ERROR=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y CONFIG_FEATURE_SEAMLESS_BZ2=y CONFIG_FEATURE_SEAMLESS_GZ=y -# CONFIG_FEATURE_SEAMLESS_Z is not set -# CONFIG_AR is not set -# CONFIG_FEATURE_AR_LONG_FILENAMES is not set -# CONFIG_FEATURE_AR_CREATE is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y # CONFIG_FEATURE_CPIO_O is not set # CONFIG_FEATURE_CPIO_P is not set # CONFIG_DPKG is not set @@ -135,89 +135,89 @@ CONFIG_FEATURE_SEAMLESS_GZ=y # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y -# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -# CONFIG_LZOP is not set +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y # CONFIG_LZOP_COMPR_HIGH is not set -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y CONFIG_TAR=y CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set +CONFIG_FEATURE_TAR_AUTODETECT=y CONFIG_FEATURE_TAR_FROM=y CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y -# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set -# CONFIG_FEATURE_TAR_TO_COMMAND is not set +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y # CONFIG_FEATURE_TAR_UNAME_GNAME is not set -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set -# CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set -# CONFIG_UNZIP is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_FEATURE_DATE_COMPAT is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y # CONFIG_BASE64 is not set -# CONFIG_CAL is not set -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y -# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y -# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_FEATURE_CP_LONG_OPTIONS=y CONFIG_CUT=y CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set +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 is not set -# CONFIG_EXPAND is not set -# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +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 is not set -# CONFIG_FOLD is not set -# CONFIG_FSYNC is not set +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -# CONFIG_HOSTID is not set -# CONFIG_ID is not set -# CONFIG_INSTALL is not set -# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LENGTH=y CONFIG_LN=y -# CONFIG_LOGNAME is not set +CONFIG_LOGNAME=y CONFIG_LS=y CONFIG_FEATURE_LS_FILETYPES=y CONFIG_FEATURE_LS_FOLLOWLINKS=y @@ -225,63 +225,63 @@ CONFIG_FEATURE_LS_RECURSIVE=y CONFIG_FEATURE_LS_SORTFILES=y CONFIG_FEATURE_LS_TIMESTAMPS=y CONFIG_FEATURE_LS_USERNAME=y -# CONFIG_FEATURE_LS_COLOR is not set -# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y CONFIG_MD5SUM=y CONFIG_MKDIR=y -# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y # CONFIG_MKNOD is not set CONFIG_MV=y -# CONFIG_FEATURE_MV_LONG_OPTIONS is not set -# CONFIG_NICE is not set +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y CONFIG_NOHUP=y -# CONFIG_OD is not set -# CONFIG_PRINTENV is not set +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set -# CONFIG_SHA256SUM is not set -# CONFIG_SHA512SUM is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y CONFIG_SLEEP=y CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y -# CONFIG_FEATURE_SORT_BIG is not set -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y # CONFIG_STAT is not set # CONFIG_FEATURE_STAT_FORMAT is not set # CONFIG_STTY is not set -# CONFIG_SUM is not set +CONFIG_SUM=y CONFIG_SYNC=y # CONFIG_TAC is not set CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TOUCH=y CONFIG_TRUE=y -# CONFIG_TTY is not set +CONFIG_TTY=y CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set -# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -# CONFIG_UNIQ is not set +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y CONFIG_USLEEP=y -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y CONFIG_FEATURE_WC_LARGE=y # CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -301,23 +301,23 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # # CONFIG_CHVT is not set # CONFIG_FGCONSOLE is not set -# CONFIG_CLEAR is not set +CONFIG_CLEAR=y # CONFIG_DEALLOCVT is not set # CONFIG_DUMPKMAP is not set # CONFIG_KBD_MODE is not set # CONFIG_LOADFONT is not set # CONFIG_LOADKMAP is not set # CONFIG_OPENVT is not set -# CONFIG_RESET is not set -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y # CONFIG_SETCONSOLE is not set # CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set # CONFIG_SETFONT is not set @@ -332,11 +332,11 @@ CONFIG_DEFAULT_SETFONT_DIR="" # # Debian Utilities # -# CONFIG_MKTEMP is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set -# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set +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 is not set # CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set # CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set @@ -345,18 +345,18 @@ CONFIG_WHICH=y # # Editors # -# CONFIG_PATCH is not set +CONFIG_PATCH=y CONFIG_AWK=y CONFIG_FEATURE_AWK_LIBM=y CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_ED is not set +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y CONFIG_SED=y CONFIG_VI=y -CONFIG_FEATURE_VI_MAX_LEN=4096 -# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_MAX_LEN=1024 +CONFIG_FEATURE_VI_8BIT=y CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y CONFIG_FEATURE_VI_SEARCH=y @@ -367,7 +367,7 @@ CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y CONFIG_FEATURE_VI_ASK_TERMINAL=y -# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -375,36 +375,36 @@ CONFIG_FEATURE_ALLOW_EXEC=y # CONFIG_FIND=y CONFIG_FEATURE_FIND_PRINT0=y -# CONFIG_FEATURE_FIND_MTIME is not set -# CONFIG_FEATURE_FIND_MMIN is not set -# CONFIG_FEATURE_FIND_PERM is not set -# CONFIG_FEATURE_FIND_TYPE is not set -# CONFIG_FEATURE_FIND_XDEV is not set -# CONFIG_FEATURE_FIND_MAXDEPTH is not set -# CONFIG_FEATURE_FIND_NEWER is not set -# CONFIG_FEATURE_FIND_INUM is not set +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 is not set -# CONFIG_FEATURE_FIND_GROUP is not set +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y CONFIG_FEATURE_FIND_NOT=y -# CONFIG_FEATURE_FIND_DEPTH is not set -# CONFIG_FEATURE_FIND_PAREN is not set -# CONFIG_FEATURE_FIND_SIZE is not set -# CONFIG_FEATURE_FIND_PRUNE is not set -# CONFIG_FEATURE_FIND_DELETE is not set -# CONFIG_FEATURE_FIND_PATH is not set -# CONFIG_FEATURE_FIND_REGEX is not set +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 is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_FEATURE_GREP_EGREP_ALIAS=y CONFIG_FEATURE_GREP_FGREP_ALIAS=y CONFIG_FEATURE_GREP_CONTEXT=y -# CONFIG_XARGS is not set -# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set -# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set -# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set -# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set +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 @@ -432,24 +432,24 @@ CONFIG_INIT_TERMINAL_TYPE="" # # CONFIG_ADD_SHELL is not set # CONFIG_REMOVE_SHELL is not set -CONFIG_FEATURE_SHADOWPASSWDS=y +# CONFIG_FEATURE_SHADOWPASSWDS is not set CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y +# CONFIG_USE_BB_SHADOW is not set # CONFIG_USE_BB_CRYPT is not set # CONFIG_USE_BB_CRYPT_SHA is not set # CONFIG_ADDUSER is not set # CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set # CONFIG_FEATURE_CHECK_NAMES is not set -CONFIG_FIRST_SYSTEM_ID=0 -CONFIG_LAST_SYSTEM_ID=0 -# CONFIG_ADDGROUP is not set -# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set -# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y # CONFIG_DELUSER is not set -# CONFIG_DELGROUP is not set -# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y # CONFIG_GETTY is not set -CONFIG_LOGIN=y +# CONFIG_LOGIN is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set @@ -467,55 +467,44 @@ CONFIG_LOGIN=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set -# CONFIG_E2FSCK is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set # CONFIG_LSATTR is not set -# CONFIG_MKE2FS is not set # CONFIG_TUNE2FS is not set -# CONFIG_E2LABEL is not set - -# -# Linux Module Utilities -# # CONFIG_MODINFO is not set # CONFIG_MODPROBE_SMALL is not set # CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set # CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -CONFIG_INSMOD=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y +# CONFIG_MODPROBE is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set - -# -# Options common to multiple modutils -# -CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_4_MODULES is not set # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set # CONFIG_FEATURE_MODUTILS_ALIAS is not set # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="/lib/modules/modules.dep" +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" # # Linux System Utilities # # CONFIG_BLOCKDEV is not set -# CONFIG_REV is not set +CONFIG_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set -CONFIG_BLKID=y -CONFIG_DMESG=y -CONFIG_FEATURE_DMESG_PRETTY=y +# CONFIG_BLKID is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set # CONFIG_FBSET is not set # CONFIG_FEATURE_FBSET_FANCY is not set # CONFIG_FEATURE_FBSET_READMODE is not set @@ -531,7 +520,7 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_GPT_LABEL is not set # CONFIG_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set -# CONFIG_FLOCK is not set +CONFIG_FLOCK=y # CONFIG_FREERAMDISK is not set # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set @@ -539,19 +528,19 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set # CONFIG_MKFS_VFAT is not set -# CONFIG_GETOPT is not set -# CONFIG_FEATURE_GETOPT_LONG is not set -# CONFIG_HEXDUMP is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y # CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set +CONFIG_HD=y # CONFIG_HWCLOCK is not set # CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set # CONFIG_IPCRM is not set # CONFIG_IPCS is not set # CONFIG_LOSETUP is not set -# CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set +CONFIG_LSPCI=y +CONFIG_LSUSB=y # CONFIG_MDEV is not set # CONFIG_FEATURE_MDEV_CONF is not set # CONFIG_FEATURE_MDEV_RENAME is not set @@ -559,54 +548,46 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # CONFIG_FEATURE_MDEV_EXEC is not set # CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set # CONFIG_MKSWAP is not set -CONFIG_FEATURE_MKSWAP_UUID=y +# CONFIG_FEATURE_MKSWAP_UUID is not set CONFIG_MORE=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set # CONFIG_FEATURE_MOUNT_NFS is not set -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set # CONFIG_RDATE is not set # CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set +CONFIG_READPROFILE=y # CONFIG_RTCWAKE is not set # CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set # CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y +# CONFIG_UMOUNT is not set # CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set # CONFIG_FEATURE_MTAB_SUPPORT is not set -CONFIG_VOLUMEID=y - -# -# Filesystem/Volume identification -# -CONFIG_FEATURE_VOLUMEID_EXT=y +# CONFIG_VOLUMEID is not set +# CONFIG_FEATURE_VOLUMEID_EXT is not set # CONFIG_FEATURE_VOLUMEID_BTRFS is not set # CONFIG_FEATURE_VOLUMEID_REISERFS is not set -CONFIG_FEATURE_VOLUMEID_FAT=y +# CONFIG_FEATURE_VOLUMEID_FAT is not set # CONFIG_FEATURE_VOLUMEID_HFS is not set # CONFIG_FEATURE_VOLUMEID_JFS is not set # CONFIG_FEATURE_VOLUMEID_XFS is not set -CONFIG_FEATURE_VOLUMEID_NTFS=y +# CONFIG_FEATURE_VOLUMEID_NTFS is not set # CONFIG_FEATURE_VOLUMEID_ISO9660 is not set # CONFIG_FEATURE_VOLUMEID_UDF is not set # CONFIG_FEATURE_VOLUMEID_LUKS is not set -CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set # CONFIG_FEATURE_VOLUMEID_CRAMFS is not set # CONFIG_FEATURE_VOLUMEID_ROMFS is not set # CONFIG_FEATURE_VOLUMEID_SYSV is not set @@ -635,19 +616,19 @@ CONFIG_FEATURE_BEEP_LENGTH_MS=0 # CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set # CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set # CONFIG_FEATURE_CHAT_CLR_ABORT is not set -# CONFIG_CHRT is not set -CONFIG_CROND=y +CONFIG_CHRT=y +# CONFIG_CROND is not set # CONFIG_FEATURE_CROND_D is not set # CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set CONFIG_FEATURE_CROND_DIR="/var/spool/cron" -# CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=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=y +# CONFIG_FEATURE_DEVFS is not set # CONFIG_DEVMEM is not set # CONFIG_EJECT is not set # CONFIG_FEATURE_EJECT_SCSI is not set @@ -663,10 +644,10 @@ CONFIG_FEATURE_DEVFS=y # CONFIG_FEATURE_LAST_FANCY is not set CONFIG_LESS=y CONFIG_FEATURE_LESS_MAXLINES=9999999 -# CONFIG_FEATURE_LESS_BRACKETS is not set -# CONFIG_FEATURE_LESS_FLAGS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP is not set +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y # CONFIG_FEATURE_LESS_WINCH is not set # CONFIG_FEATURE_LESS_DASHCMD is not set # CONFIG_FEATURE_LESS_LINENUMS is not set @@ -681,7 +662,7 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 # CONFIG_FEATURE_MAKEDEVS_LEAF is not set # CONFIG_FEATURE_MAKEDEVS_TABLE is not set # CONFIG_MAN is not set -# CONFIG_MICROCOM is not set +CONFIG_MICROCOM=y # CONFIG_MOUNTPOINT is not set # CONFIG_MT is not set # CONFIG_RAIDAUTORUN is not set @@ -689,14 +670,14 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 # CONFIG_RFKILL is not set # CONFIG_RUNLEVEL is not set # CONFIG_RX is not set -# CONFIG_SETSID is not set +CONFIG_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set # CONFIG_TIME is not set -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set # CONFIG_WATCHDOG is not set @@ -706,46 +687,46 @@ CONFIG_STRINGS=y # CONFIG_NBDCLIENT is not set CONFIG_NC=y # CONFIG_NC_SERVER is not set -CONFIG_NC_EXTRA=y +# CONFIG_NC_EXTRA is not set # CONFIG_NC_110_COMPAT is not set # CONFIG_FEATURE_IPV6 is not set # CONFIG_FEATURE_UNIX_LOCAL is not set -CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set -CONFIG_ARP=y -CONFIG_ARPING=y +# CONFIG_ARP is not set +# CONFIG_ARPING is not set # CONFIG_BRCTL is not set # CONFIG_FEATURE_BRCTL_FANCY is not set # CONFIG_FEATURE_BRCTL_SHOW is not set -# CONFIG_DNSD is not set -CONFIG_ETHER_WAKE=y -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set -# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set -# CONFIG_HOSTNAME is not set -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=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 is not set # CONFIG_FEATURE_HTTPD_SETUID is not set -# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set -# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set -# CONFIG_FEATURE_HTTPD_CGI is not set -# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set -# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set -# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set -# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set -# CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set -CONFIG_IFCONFIG=y -CONFIG_FEATURE_IFCONFIG_STATUS=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=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_FEATURE_HTTPD_GZIP=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set # CONFIG_FEATURE_IFCONFIG_SLIP is not set # CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set -CONFIG_FEATURE_IFCONFIG_HW=y -CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set # CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set # CONFIG_IFUPDOWN is not set @@ -777,42 +758,46 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # CONFIG_IPROUTE is not set # CONFIG_IPTUNNEL is not set # CONFIG_IPRULE is not set -# CONFIG_IPCALC is not set -# CONFIG_FEATURE_IPCALC_FANCY is not set -# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y # CONFIG_NAMEIF is not set # CONFIG_FEATURE_NAMEIF_EXTENDED is not set -CONFIG_NETSTAT=y -CONFIG_FEATURE_NETSTAT_WIDE=y +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set # CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y +# CONFIG_PING is not set # CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y +# CONFIG_FEATURE_FANCY_PING is not set CONFIG_PSCAN=y -CONFIG_ROUTE=y +# CONFIG_ROUTE is not set # CONFIG_SLATTACH is not set # CONFIG_TCPSVD is not set CONFIG_TELNET=y -# CONFIG_FEATURE_TELNET_TTYPE is not set -# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y CONFIG_TELNETD=y CONFIG_FEATURE_TELNETD_STANDALONE=y -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set -# CONFIG_TFTP is not set -# CONFIG_TFTPD is not set -# CONFIG_FEATURE_TFTP_GET is not set -# CONFIG_FEATURE_TFTP_PUT is not set -# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set -# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y # CONFIG_TFTP_DEBUG is not set -CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set -CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_UDHCPD is not set @@ -820,21 +805,20 @@ CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y # CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set CONFIG_DHCPD_LEASES_FILE="" -CONFIG_UDHCPC=y +# CONFIG_UDHCPC is not set # CONFIG_FEATURE_UDHCPC_ARPING is not set # CONFIG_FEATURE_UDHCP_PORT is not set CONFIG_UDHCP_DEBUG=0 # CONFIG_FEATURE_UDHCP_RFC3397 is not set -# CONFIG_FEATURE_UDHCP_RFC5969 is not set CONFIG_UDHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=924 +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" # CONFIG_UDPSVD is not set -CONFIG_VCONFIG=y +# CONFIG_VCONFIG is not set CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y -# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_LONG_OPTIONS=y CONFIG_FEATURE_WGET_TIMEOUT=y # CONFIG_ZCIP is not set @@ -842,8 +826,8 @@ CONFIG_FEATURE_WGET_TIMEOUT=y # Print Utilities # # CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities @@ -859,38 +843,38 @@ CONFIG_FEATURE_MIME_CHARSET="" # # Process Utilities # -# CONFIG_IOSTAT is not set -# CONFIG_MPSTAT is not set -# CONFIG_PMAP is not set -# CONFIG_POWERTOP is not set -# CONFIG_SMEMCAP is not set -CONFIG_FREE=y +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set # CONFIG_FUSER is not set CONFIG_KILL=y CONFIG_KILLALL=y -# CONFIG_KILLALL5 is not set +CONFIG_KILLALL5=y # CONFIG_NMETER is not set -# CONFIG_PGREP is not set -CONFIG_PIDOF=y +CONFIG_PGREP=y +# CONFIG_PIDOF is not set # CONFIG_FEATURE_PIDOF_SINGLE is not set # CONFIG_FEATURE_PIDOF_OMIT is not set -# CONFIG_PKILL is not set +CONFIG_PKILL=y CONFIG_PS=y CONFIG_FEATURE_PS_WIDE=y # CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -# CONFIG_RENICE is not set -# CONFIG_BB_SYSCTL is not set -CONFIG_TOP=y -CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y -CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +# CONFIG_TOP is not set +# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set +# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set # CONFIG_FEATURE_TOP_SMP_CPU is not set # CONFIG_FEATURE_TOP_DECIMALS is not set # CONFIG_FEATURE_TOP_SMP_PROCESS is not set # CONFIG_FEATURE_TOPMEM is not set -# CONFIG_FEATURE_SHOW_THREADS is not set -CONFIG_UPTIME=y +CONFIG_FEATURE_SHOW_THREADS=y +# CONFIG_UPTIME is not set CONFIG_WATCH=y # @@ -927,16 +911,16 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # Shells # CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_BASH_COMPAT is not set # CONFIG_ASH_JOB_CONTROL is not set -CONFIG_ASH_ALIAS=y +# CONFIG_ASH_ALIAS is not set # CONFIG_ASH_GETOPTS is not set # CONFIG_ASH_BUILTIN_ECHO is not set # CONFIG_ASH_BUILTIN_PRINTF 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=y +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set # CONFIG_ASH_RANDOM_SUPPORT is not set # CONFIG_ASH_EXPAND_PRMT is not set # CONFIG_CTTYHACK is not set @@ -964,8 +948,8 @@ CONFIG_FEATURE_SH_IS_ASH=y # CONFIG_FEATURE_BASH_IS_HUSH is not set CONFIG_FEATURE_BASH_IS_NONE=y CONFIG_SH_MATH_SUPPORT=y -# CONFIG_SH_MATH_SUPPORT_64 is not set -CONFIG_FEATURE_SH_EXTRA_QUIET=y +CONFIG_SH_MATH_SUPPORT_64=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set # CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set @@ -977,10 +961,10 @@ CONFIG_FEATURE_ROTATE_LOGFILE=y CONFIG_FEATURE_REMOTE_LOG=y # CONFIG_FEATURE_SYSLOGD_DUP is not set CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 -# CONFIG_FEATURE_IPC_SYSLOG is not set -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 -# CONFIG_LOGREAD is not set -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -CONFIG_FEATURE_KLOGD_KLOGCTL=y +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set CONFIG_LOGGER=y diff --git a/release/src/router/busybox/console-tools/Config.src b/release/src/router/busybox/console-tools/Config.src index cdb26800e2..c657044784 100644 --- a/release/src/router/busybox/console-tools/Config.src +++ b/release/src/router/busybox/console-tools/Config.src @@ -10,7 +10,7 @@ INSERT config CHVT bool "chvt" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program is used to change to another terminal. Example: chvt 4 (change to terminal /dev/tty4) @@ -18,7 +18,7 @@ config CHVT config FGCONSOLE bool "fgconsole" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program prints active (foreground) console number. @@ -31,14 +31,14 @@ config CLEAR config DEALLOCVT bool "deallocvt" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program deallocates unused virtual consoles. config DUMPKMAP bool "dumpkmap" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program dumps the kernel's keyboard translation table to stdout, in binary format. You can then use loadkmap to load it. @@ -46,21 +46,21 @@ config DUMPKMAP config KBD_MODE bool "kbd_mode" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program reports and sets keyboard mode. config LOADFONT bool "loadfont" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program loads a console font from standard input. config LOADKMAP bool "loadkmap" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program loads a keyboard translation table from standard input. @@ -68,7 +68,7 @@ config LOADKMAP config OPENVT bool "openvt" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program is used to start a command on an unused virtual terminal. @@ -100,7 +100,7 @@ config FEATURE_RESIZE_PRINT config SETCONSOLE bool "setconsole" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program redirects the system console to another device, like the current tty while logged in via telnet. @@ -115,7 +115,7 @@ config FEATURE_SETCONSOLE_LONG_OPTIONS config SETFONT bool "setfont" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Allows to load console screen map. Useful for i18n. @@ -137,7 +137,7 @@ config DEFAULT_SETFONT_DIR config SETKEYCODES bool "setkeycodes" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program loads entries into the kernel's scancode-to-keycode map, allowing unusual keyboards to generate usable keycodes. @@ -145,14 +145,14 @@ config SETKEYCODES config SETLOGCONS bool "setlogcons" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This program redirects the output console of kernel messages. config SHOWKEY bool "showkey" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Shows keys pressed. diff --git a/release/src/router/busybox/console-tools/chvt.c b/release/src/router/busybox/console-tools/chvt.c index 07e58c3b8a..b9c974f4a4 100644 --- a/release/src/router/busybox/console-tools/chvt.c +++ b/release/src/router/busybox/console-tools/chvt.c @@ -6,6 +6,12 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define chvt_trivial_usage +//usage: "N" +//usage:#define chvt_full_usage "\n\n" +//usage: "Change the foreground virtual terminal to /dev/ttyN" + #include "libbb.h" int chvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/console-tools/clear.c b/release/src/router/busybox/console-tools/clear.c index dcb9bfb02a..ac22b787e8 100644 --- a/release/src/router/busybox/console-tools/clear.c +++ b/release/src/router/busybox/console-tools/clear.c @@ -6,6 +6,12 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define clear_trivial_usage +//usage: "" +//usage:#define clear_full_usage "\n\n" +//usage: "Clear screen" + #include "libbb.h" int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/console-tools/deallocvt.c b/release/src/router/busybox/console-tools/deallocvt.c index 6a1d13d149..b131c0a649 100644 --- a/release/src/router/busybox/console-tools/deallocvt.c +++ b/release/src/router/busybox/console-tools/deallocvt.c @@ -10,6 +10,11 @@ /* no options, no getopt */ +//usage:#define deallocvt_trivial_usage +//usage: "[N]" +//usage:#define deallocvt_full_usage "\n\n" +//usage: "Deallocate unused virtual terminal /dev/ttyN" + #include "libbb.h" /* From */ diff --git a/release/src/router/busybox/console-tools/dumpkmap.c b/release/src/router/busybox/console-tools/dumpkmap.c index 301a90674a..6b923d2d47 100644 --- a/release/src/router/busybox/console-tools/dumpkmap.c +++ b/release/src/router/busybox/console-tools/dumpkmap.c @@ -9,6 +9,14 @@ */ /* no options, no getopt */ +//usage:#define dumpkmap_trivial_usage +//usage: "> keymap" +//usage:#define dumpkmap_full_usage "\n\n" +//usage: "Print a binary keyboard translation table to stdout" +//usage: +//usage:#define dumpkmap_example_usage +//usage: "$ dumpkmap > keymap\n" + #include "libbb.h" /* From */ diff --git a/release/src/router/busybox/console-tools/fgconsole.c b/release/src/router/busybox/console-tools/fgconsole.c index e2dba4860a..54355bee61 100644 --- a/release/src/router/busybox/console-tools/fgconsole.c +++ b/release/src/router/busybox/console-tools/fgconsole.c @@ -7,6 +7,11 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define fgconsole_trivial_usage +//usage: "" +//usage:#define fgconsole_full_usage "\n\n" +//usage: "Get active console" + #include "libbb.h" /* From */ diff --git a/release/src/router/busybox/console-tools/kbd_mode.c b/release/src/router/busybox/console-tools/kbd_mode.c index 1481d0dbb1..1385367212 100644 --- a/release/src/router/busybox/console-tools/kbd_mode.c +++ b/release/src/router/busybox/console-tools/kbd_mode.c @@ -8,6 +8,17 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define kbd_mode_trivial_usage +//usage: "[-a|k|s|u] [-C TTY]" +//usage:#define kbd_mode_full_usage "\n\n" +//usage: "Report or set the keyboard mode\n" +//usage: "\n -a Default (ASCII)" +//usage: "\n -k Medium-raw (keyboard)" +//usage: "\n -s Raw (scancode)" +//usage: "\n -u Unicode (utf-8)" +//usage: "\n -C TTY Affect TTY instead of /dev/tty" + #include "libbb.h" #include diff --git a/release/src/router/busybox/console-tools/loadfont.c b/release/src/router/busybox/console-tools/loadfont.c index 079626c20b..9e887f2566 100644 --- a/release/src/router/busybox/console-tools/loadfont.c +++ b/release/src/router/busybox/console-tools/loadfont.c @@ -9,6 +9,26 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define loadfont_trivial_usage +//usage: "< font" +//usage:#define loadfont_full_usage "\n\n" +//usage: "Load a console font from stdin" +/* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ +//usage: +//usage:#define loadfont_example_usage +//usage: "$ loadfont < /etc/i18n/fontname\n" +//usage: +//usage:#define setfont_trivial_usage +//usage: "FONT [-m MAPFILE] [-C TTY]" +//usage:#define setfont_full_usage "\n\n" +//usage: "Load a console font\n" +//usage: "\n -m MAPFILE Load console screen map" +//usage: "\n -C TTY Affect TTY instead of /dev/tty" +//usage: +//usage:#define setfont_example_usage +//usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" + #include "libbb.h" #include diff --git a/release/src/router/busybox/console-tools/loadkmap.c b/release/src/router/busybox/console-tools/loadkmap.c index 2d1c9e2848..bcffe16b12 100644 --- a/release/src/router/busybox/console-tools/loadkmap.c +++ b/release/src/router/busybox/console-tools/loadkmap.c @@ -6,6 +6,16 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define loadkmap_trivial_usage +//usage: "< keymap" +//usage:#define loadkmap_full_usage "\n\n" +//usage: "Load a binary keyboard translation table from stdin\n" +/* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ +//usage: +//usage:#define loadkmap_example_usage +//usage: "$ loadkmap < /etc/i18n/lang-keymap\n" + #include "libbb.h" #define BINARY_KEYMAP_MAGIC "bkeymap" diff --git a/release/src/router/busybox/console-tools/openvt.c b/release/src/router/busybox/console-tools/openvt.c index 6e0b589a0c..e523566926 100644 --- a/release/src/router/busybox/console-tools/openvt.c +++ b/release/src/router/busybox/console-tools/openvt.c @@ -8,6 +8,18 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define openvt_trivial_usage +//usage: "[-c N] [-sw] [PROG ARGS]" +//usage:#define openvt_full_usage "\n\n" +//usage: "Start PROG on a new virtual terminal\n" +//usage: "\n -c N Use specified VT" +//usage: "\n -s Switch to the VT" +/* //usage: "\n -l Run PROG as login shell (by prepending '-')" */ +//usage: "\n -w Wait for PROG to exit" +//usage: +//usage:#define openvt_example_usage +//usage: "openvt 2 /bin/ash\n" + #include #include "libbb.h" @@ -144,9 +156,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) { argv--; - argv[0] = getenv("SHELL"); - if (!argv[0]) - argv[0] = (char *) DEFAULT_SHELL; + argv[0] = (char *) get_shell_name(); /*argv[1] = NULL; - already is */ } diff --git a/release/src/router/busybox/console-tools/reset.c b/release/src/router/busybox/console-tools/reset.c index 1806ce742b..65940bdec5 100644 --- a/release/src/router/busybox/console-tools/reset.c +++ b/release/src/router/busybox/console-tools/reset.c @@ -11,6 +11,11 @@ /* BTW, which "standard" package has this utility? It doesn't seem * to be ncurses, coreutils, console-tools... then what? */ +//usage:#define reset_trivial_usage +//usage: "" +//usage:#define reset_full_usage "\n\n" +//usage: "Reset the screen" + #include "libbb.h" #define ESC "\033" @@ -31,12 +36,12 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) { /* See 'man 4 console_codes' for details: * "ESC c" -- Reset - * "ESC ( K" -- Select user mapping + * "ESC ( B" -- Select G0 Character Set (B = US) * "ESC [ 0 m" -- Reset all display attributes * "ESC [ J" -- Erase to the end of screen * "ESC [ ? 25 h" -- Make cursor visible */ - printf(ESC"c" ESC"(K" ESC"[0m" ESC"[J" ESC"[?25h"); + printf(ESC"c" ESC"(B" ESC"[0m" ESC"[J" ESC"[?25h"); /* http://bugs.busybox.net/view.php?id=1414: * people want it to reset echo etc: */ #if ENABLE_STTY diff --git a/release/src/router/busybox/console-tools/resize.c b/release/src/router/busybox/console-tools/resize.c index fdfe2a6a0c..4b0d63a03c 100644 --- a/release/src/router/busybox/console-tools/resize.c +++ b/release/src/router/busybox/console-tools/resize.c @@ -7,6 +7,12 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* no options, no getopt */ + +//usage:#define resize_trivial_usage +//usage: "" +//usage:#define resize_full_usage "\n\n" +//usage: "Resize the screen" + #include "libbb.h" #define ESC "\033" @@ -53,6 +59,7 @@ int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) */ fprintf(stderr, ESC"7" ESC"[r" ESC"[999;999H" ESC"[6n"); alarm(3); /* Just in case terminal won't answer */ +//BUG: death by signal won't restore termios scanf(ESC"[%hu;%huR", &w.ws_row, &w.ws_col); fprintf(stderr, ESC"8"); diff --git a/release/src/router/busybox/console-tools/setconsole.c b/release/src/router/busybox/console-tools/setconsole.c index 87265baf8e..c0051dcc8c 100644 --- a/release/src/router/busybox/console-tools/setconsole.c +++ b/release/src/router/busybox/console-tools/setconsole.c @@ -8,6 +8,12 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define setconsole_trivial_usage +//usage: "[-r" IF_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]" +//usage:#define setconsole_full_usage "\n\n" +//usage: "Redirect system console output to DEVICE (default: /dev/tty)\n" +//usage: "\n -r Reset output to /dev/console" + #include "libbb.h" int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -34,6 +40,6 @@ int setconsole_main(int argc UNUSED_PARAM, char **argv) device = DEV_CONSOLE; } - xioctl(xopen(device, O_RDONLY), TIOCCONS, NULL); + xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/console-tools/setkeycodes.c b/release/src/router/busybox/console-tools/setkeycodes.c index ca8cd21c2a..a6a7c23743 100644 --- a/release/src/router/busybox/console-tools/setkeycodes.c +++ b/release/src/router/busybox/console-tools/setkeycodes.c @@ -8,6 +8,18 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define setkeycodes_trivial_usage +//usage: "SCANCODE KEYCODE..." +//usage:#define setkeycodes_full_usage "\n\n" +//usage: "Set entries into the kernel's scancode-to-keycode map,\n" +//usage: "allowing unusual keyboards to generate usable keycodes.\n\n" +//usage: "SCANCODE may be either xx or e0xx (hexadecimal),\n" +//usage: "and KEYCODE is given in decimal." +//usage: +//usage:#define setkeycodes_example_usage +//usage: "$ setkeycodes e030 127\n" + #include "libbb.h" /* From */ diff --git a/release/src/router/busybox/console-tools/setlogcons.c b/release/src/router/busybox/console-tools/setlogcons.c index 52d2608aa7..83a895407b 100644 --- a/release/src/router/busybox/console-tools/setlogcons.c +++ b/release/src/router/busybox/console-tools/setlogcons.c @@ -9,6 +9,11 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define setlogcons_trivial_usage +//usage: "N" +//usage:#define setlogcons_full_usage "\n\n" +//usage: "Redirect the kernel output to console N (0 for current)" + #include "libbb.h" int setlogcons_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/console-tools/showkey.c b/release/src/router/busybox/console-tools/showkey.c index e7834f702f..69b785ec62 100644 --- a/release/src/router/busybox/console-tools/showkey.c +++ b/release/src/router/busybox/console-tools/showkey.c @@ -7,6 +7,14 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define showkey_trivial_usage +//usage: "[-a | -k | -s]" +//usage:#define showkey_full_usage "\n\n" +//usage: "Show keys pressed\n" +//usage: "\n -a Display decimal/octal/hex values of the keys" +//usage: "\n -k Display interpreted keycodes (default)" +//usage: "\n -s Display raw scan-codes" + #include "libbb.h" #include @@ -56,37 +64,45 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) // FIXME: aks are all mutually exclusive getopt32(argv, "aks"); - // get keyboard settings - xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); - printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n", - kbmode == K_RAW ? "RAW" : - (kbmode == K_XLATE ? "XLATE" : - (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : - (kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN"))) - , (option_mask32 & OPT_a) ? "on EOF (ctrl-D)" : "10s after last keypress" - ); - // prepare for raw mode xget1(&tio, &tio0); // put stdin in raw mode xset1(&tio); +#define press_keys "Press any keys, program terminates %s:\r\n\n" + if (option_mask32 & OPT_a) { + // just read stdin char by char unsigned char c; - // just read stdin char by char + printf(press_keys, "on EOF (ctrl-D)"); + + // read and show byte values while (1 == read(STDIN_FILENO, &c, 1)) { printf("%3u 0%03o 0x%02x\r\n", c, c, c); if (04 /*CTRL-D*/ == c) break; } + } else { + // we assume a PC keyboard + xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); + printf("Keyboard mode was %s.\r\n\n", + kbmode == K_RAW ? "RAW" : + (kbmode == K_XLATE ? "XLATE" : + (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : + (kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN"))) + ); + // set raw keyboard mode xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); // we should exit on any signal; signals should interrupt read bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); + // inform user that program ends after time of inactivity + printf(press_keys, "10s after last keypress"); + // read and show scancodes while (!bb_got_signal) { char buf[18]; @@ -94,6 +110,7 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) // setup 10s watchdog alarm(10); + // read scancodes n = read(STDIN_FILENO, buf, sizeof(buf)); i = 0; @@ -121,11 +138,13 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) } puts("\r"); } + + // restore keyboard mode + xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); } - // restore keyboard and console settings + // restore console settings xset1(&tio0); - xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/coreutils/Config.src b/release/src/router/busybox/coreutils/Config.src index 0eb70af557..a28449b11d 100644 --- a/release/src/router/busybox/coreutils/Config.src +++ b/release/src/router/busybox/coreutils/Config.src @@ -269,19 +269,6 @@ config FEATURE_FANCY_HEAD help This enables the head options (-c, -q, and -v). -config HOSTID - bool "hostid" - default y - help - hostid prints the numeric identifier (in hexadecimal) for - the current host. - -config ID - bool "id" - default y - help - id displays the current user and group ID names. - config INSTALL bool "install" default y @@ -295,11 +282,11 @@ config FEATURE_INSTALL_LONG_OPTIONS help Support long options for the install applet. -config LENGTH - bool "length" - default y - help - length is used to print out the length of a specified string. +####config LENGTH +#### bool "length" +#### default y +#### help +#### length is used to print out the length of a specified string. config LN bool "ln" @@ -591,7 +578,7 @@ config FEATURE_SPLIT_FANCY config STAT bool "stat" default y - depends on PLATFORM_LINUX # statfs() + select PLATFORM_LINUX # statfs() help display file or filesystem status. @@ -661,13 +648,6 @@ config FEATURE_TEE_USE_BLOCK_IO help Enable this option for a faster tee, at expense of size. -config TOUCH - bool "touch" - default y - help - touch is used to create or change the access and/or - modification timestamp of specified files. - config TRUE bool "true" default y @@ -738,13 +718,6 @@ config FEATURE_WC_LARGE help Use "unsigned long long" in wc for counter variables. -config WHO - bool "who" - default y - depends on FEATURE_UTMP - help - who is used to show who is logged on. - config WHOAMI bool "whoami" default y diff --git a/release/src/router/busybox/coreutils/Kbuild.src b/release/src/router/busybox/coreutils/Kbuild.src index 630b048dfc..d6453f0145 100644 --- a/release/src/router/busybox/coreutils/Kbuild.src +++ b/release/src/router/busybox/coreutils/Kbuild.src @@ -36,10 +36,8 @@ lib-$(CONFIG_FALSE) += false.o lib-$(CONFIG_FOLD) += fold.o lib-$(CONFIG_FSYNC) += fsync.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_LENGTH) += length.o lib-$(CONFIG_LN) += ln.o lib-$(CONFIG_LOGNAME) += logname.o lib-$(CONFIG_LS) += ls.o @@ -74,7 +72,6 @@ lib-$(CONFIG_SYNC) += sync.o lib-$(CONFIG_TAC) += tac.o lib-$(CONFIG_TAIL) += tail.o lib-$(CONFIG_TEE) += tee.o -lib-$(CONFIG_TOUCH) += touch.o lib-$(CONFIG_TRUE) += true.o lib-$(CONFIG_TTY) += tty.o lib-$(CONFIG_UNAME) += uname.o @@ -84,6 +81,5 @@ 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/release/src/router/busybox/coreutils/basename.c b/release/src/router/busybox/coreutils/basename.c index d441247416..1f7a13713c 100644 --- a/release/src/router/busybox/coreutils/basename.c +++ b/release/src/router/busybox/coreutils/basename.c @@ -28,6 +28,19 @@ //config: leaving just the filename itself. Enable this option if you wish //config: to enable the 'basename' utility. +//usage:#define basename_trivial_usage +//usage: "FILE [SUFFIX]" +//usage:#define basename_full_usage "\n\n" +//usage: "Strip directory path and .SUFFIX from FILE\n" +//usage: +//usage:#define basename_example_usage +//usage: "$ basename /usr/local/bin/foo\n" +//usage: "foo\n" +//usage: "$ basename /usr/local/bin/\n" +//usage: "bin\n" +//usage: "$ basename /foo/bar.txt .txt\n" +//usage: "bar" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ @@ -38,6 +51,11 @@ int basename_main(int argc, char **argv) size_t m, n; char *s; + if (argv[1] && strcmp(argv[1], "--") == 0) { + argv++; + argc--; + } + if ((unsigned)(argc-2) >= 2) { bb_show_usage(); } diff --git a/release/src/router/busybox/coreutils/cal.c b/release/src/router/busybox/coreutils/cal.c index f18c161206..b470ad968a 100644 --- a/release/src/router/busybox/coreutils/cal.c +++ b/release/src/router/busybox/coreutils/cal.c @@ -16,6 +16,14 @@ * * Major size reduction... over 50% (>1.5k) on i386. */ + +//usage:#define cal_trivial_usage +//usage: "[-jy] [[MONTH] YEAR]" +//usage:#define cal_full_usage "\n\n" +//usage: "Display a calendar\n" +//usage: "\n -j Use julian dates" +//usage: "\n -y Display the entire year" + #include "libbb.h" #include "unicode.h" diff --git a/release/src/router/busybox/coreutils/cat.c b/release/src/router/busybox/coreutils/cat.c index 9225498283..00c38d486a 100644 --- a/release/src/router/busybox/coreutils/cat.c +++ b/release/src/router/busybox/coreutils/cat.c @@ -22,6 +22,15 @@ //config: cat is used to concatenate files and print them to the standard //config: output. Enable this option if you wish to enable the 'cat' utility. +//usage:#define cat_trivial_usage +//usage: "[FILE]..." +//usage:#define cat_full_usage "\n\n" +//usage: "Concatenate FILEs and print them to stdout" +//usage: +//usage:#define cat_example_usage +//usage: "$ cat /proc/uptime\n" +//usage: "110716.72 17.67" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/catv.c b/release/src/router/busybox/coreutils/catv.c index f92d93d241..214b4311a6 100644 --- a/release/src/router/busybox/coreutils/catv.c +++ b/release/src/router/busybox/coreutils/catv.c @@ -10,6 +10,14 @@ /* See "Cat -v considered harmful" at * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */ +//usage:#define catv_trivial_usage +//usage: "[-etv] [FILE]..." +//usage:#define catv_full_usage "\n\n" +//usage: "Display nonprinting characters as ^x or M-x\n" +//usage: "\n -e End each line with $" +//usage: "\n -t Show tabs as ^I" +//usage: "\n -v Don't use ^x or M-x escapes" + #include "libbb.h" int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/coreutils/chgrp.c b/release/src/router/busybox/coreutils/chgrp.c index 58f78e7362..7076db62f9 100644 --- a/release/src/router/busybox/coreutils/chgrp.c +++ b/release/src/router/busybox/coreutils/chgrp.c @@ -11,6 +11,28 @@ /* BB_AUDIT GNU defects - unsupported long options. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */ +//usage:#define chgrp_trivial_usage +//usage: "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..." +//usage:#define chgrp_full_usage "\n\n" +//usage: "Change the group membership of each FILE to GROUP\n" +//usage: "\n -R Recurse" +//usage: "\n -h Affect symlinks instead of symlink targets" +//usage: "\n -L Traverse all symlinks to directories" +//usage: "\n -H Traverse symlinks on command line only" +//usage: "\n -P Don't traverse symlinks (default)" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v Verbose" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chgrp_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chgrp root /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/chmod.c b/release/src/router/busybox/coreutils/chmod.c index f07a49bd3b..5ee45b9420 100644 --- a/release/src/router/busybox/coreutils/chmod.c +++ b/release/src/router/busybox/coreutils/chmod.c @@ -14,6 +14,28 @@ /* BB_AUDIT GNU defects - unsupported long options. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ +//usage:#define chmod_trivial_usage +//usage: "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..." +//usage:#define chmod_full_usage "\n\n" +//usage: "Each MODE is one or more of the letters ugoa, one of the\n" +//usage: "symbols +-= and one or more of the letters rwxst\n" +//usage: "\n -R Recurse" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v List all files" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chmod_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chmod u+x /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" +//usage: "$ chmod 444 /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/chown.c b/release/src/router/busybox/coreutils/chown.c index 282deccfb0..bb166d8fe4 100644 --- a/release/src/router/busybox/coreutils/chown.c +++ b/release/src/router/busybox/coreutils/chown.c @@ -10,6 +10,31 @@ /* BB_AUDIT SUSv3 defects - none? */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */ +//usage:#define chown_trivial_usage +//usage: "[-RhLHP"IF_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..." +//usage:#define chown_full_usage "\n\n" +//usage: "Change the owner and/or group of each FILE to OWNER and/or GROUP\n" +//usage: "\n -R Recurse" +//usage: "\n -h Affect symlinks instead of symlink targets" +//usage: "\n -L Traverse all symlinks to directories" +//usage: "\n -H Traverse symlinks on command line only" +//usage: "\n -P Don't traverse symlinks (default)" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v List all files" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chown_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chown root /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chown root.root /tmp/foo\n" +//usage: "ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/chroot.c b/release/src/router/busybox/coreutils/chroot.c index b80a12ee01..633e66b383 100644 --- a/release/src/router/busybox/coreutils/chroot.c +++ b/release/src/router/busybox/coreutils/chroot.c @@ -9,6 +9,19 @@ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//usage:#define chroot_trivial_usage +//usage: "NEWROOT [PROG ARGS]" +//usage:#define chroot_full_usage "\n\n" +//usage: "Run PROG with root directory set to NEWROOT" +//usage: +//usage:#define chroot_example_usage +//usage: "$ ls -l /bin/ls\n" +//usage: "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" +//usage: "# mount /dev/hdc1 /mnt -t minix\n" +//usage: "# chroot /mnt\n" +//usage: "# ls -l /bin/ls\n" +//usage: "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" + #include "libbb.h" int chroot_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -18,16 +31,13 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) if (!*argv) bb_show_usage(); xchroot(*argv); - xchdir("/"); ++argv; if (!*argv) { /* no 2nd param (PROG), use shell */ argv -= 2; - argv[0] = getenv("SHELL"); - if (!argv[0]) { - argv[0] = (char *) DEFAULT_SHELL; - } - argv[1] = (char *) "-i"; + argv[0] = (char *) get_shell_name(); + argv[1] = (char *) "-i"; /* GNU coreutils 8.4 compat */ + /*argv[2] = NULL; - already is */ } BB_EXECVP_or_die(argv); diff --git a/release/src/router/busybox/coreutils/cksum.c b/release/src/router/busybox/coreutils/cksum.c index 53fb87a78c..ac0b0c319e 100644 --- a/release/src/router/busybox/coreutils/cksum.c +++ b/release/src/router/busybox/coreutils/cksum.c @@ -6,6 +6,12 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define cksum_trivial_usage +//usage: "FILES..." +//usage:#define cksum_full_usage "\n\n" +//usage: "Calculate the CRC32 checksums of FILES" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/comm.c b/release/src/router/busybox/coreutils/comm.c index c04da1896e..cd450950b5 100644 --- a/release/src/router/busybox/coreutils/comm.c +++ b/release/src/router/busybox/coreutils/comm.c @@ -7,6 +7,14 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define comm_trivial_usage +//usage: "[-123] FILE1 FILE2" +//usage:#define comm_full_usage "\n\n" +//usage: "Compare FILE1 with FILE2\n" +//usage: "\n -1 Suppress lines unique to FILE1" +//usage: "\n -2 Suppress lines unique to FILE2" +//usage: "\n -3 Suppress lines common to both files" + #include "libbb.h" #define COMM_OPT_1 (1 << 0) diff --git a/release/src/router/busybox/coreutils/cp.c b/release/src/router/busybox/coreutils/cp.c index ab17b39a69..de2e512be3 100644 --- a/release/src/router/busybox/coreutils/cp.c +++ b/release/src/router/busybox/coreutils/cp.c @@ -15,6 +15,23 @@ * Size reduction. */ +//usage:#define cp_trivial_usage +//usage: "[OPTIONS] SOURCE... DEST" +//usage:#define cp_full_usage "\n\n" +//usage: "Copy SOURCE(s) to DEST\n" +//usage: "\n -a Same as -dpR" +//usage: IF_SELINUX( +//usage: "\n -c Preserve security context" +//usage: ) +//usage: "\n -R,-r Recurse" +//usage: "\n -d,-P Preserve symlinks (default if -R)" +//usage: "\n -L Follow all symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: "\n -p Preserve file attributes if possible" +//usage: "\n -f Overwrite" +//usage: "\n -i Prompt before overwrite" +//usage: "\n -l,-s Create (sym)links" + #include "libbb.h" #include "libcoreutils/coreutils.h" diff --git a/release/src/router/busybox/coreutils/cut.c b/release/src/router/busybox/coreutils/cut.c index 38cd32c773..2c27b704f5 100644 --- a/release/src/router/busybox/coreutils/cut.c +++ b/release/src/router/busybox/coreutils/cut.c @@ -9,6 +9,23 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define cut_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define cut_full_usage "\n\n" +//usage: "Print selected fields from each input FILE to stdout\n" +//usage: "\n -b LIST Output only bytes from LIST" +//usage: "\n -c LIST Output only characters from LIST" +//usage: "\n -d CHAR Use CHAR instead of tab as the field delimiter" +//usage: "\n -s Output only the lines containing delimiter" +//usage: "\n -f N Print only these fields" +//usage: "\n -n Ignored" +//usage: +//usage:#define cut_example_usage +//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" +//usage: "Hello\n" +//usage: "$ echo \"Hello world\" | cut -f 2 -d ' '\n" +//usage: "world\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/date.c b/release/src/router/busybox/coreutils/date.c index d70957cf6a..767e0d4a29 100644 --- a/release/src/router/busybox/coreutils/date.c +++ b/release/src/router/busybox/coreutils/date.c @@ -19,7 +19,7 @@ /* Input parsing code is always bulky - used heavy duty libc stuff as much as possible, missed out a lot of bounds checking */ -//applet:IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_DATE(APPLET(date, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_DATE) += date.o @@ -42,7 +42,8 @@ //config:config FEATURE_DATE_NANO //config: bool "Support %[num]N nanosecond format specifier" //config: default n -//config: depends on DATE && PLATFORM_LINUX # syscall(__NR_clock_gettime) +//config: depends on DATE # syscall(__NR_clock_gettime) +//config: select PLATFORM_LINUX //config: help //config: Support %[num]N format specifier. Adds ~250 bytes of code. //config: @@ -97,7 +98,6 @@ //usage: "[OPTIONS] [+FMT] [TIME]" //usage:#define date_full_usage "\n\n" //usage: "Display time (using +FMT), or set time\n" -//usage: "\nOptions:" //usage: IF_NOT_LONG_OPTS( //usage: "\n [-s] TIME Set time to TIME" //usage: "\n -u Work in UTC (don't convert to local time)" @@ -129,6 +129,9 @@ //usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" //usage: "\n YYYY-MM-DD hh:mm[:ss]" //usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" +//usage: IF_FEATURE_DATE_COMPAT( +//usage: "\n 'date TIME' form accepts MMDDhhmm[[YY]YY][.ss] instead" +//usage: ) //usage: //usage:#define date_example_usage //usage: "$ date\n" @@ -250,7 +253,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) ts.tv_sec = statbuf.st_mtime; #if ENABLE_FEATURE_DATE_NANO ts.tv_nsec = statbuf.st_mtim.tv_nsec; - /* some toolchains use .st_mtimensec instead of st_mtim.tv_nsec */ + /* Some toolchains use .st_mtimensec instead of st_mtim.tv_nsec. + * If you need #define _SVID_SOURCE 1 to enable st_mtim.tv_nsec, + * drop a mail to project mailing list please + */ #endif } else { #if ENABLE_FEATURE_DATE_NANO @@ -279,7 +285,9 @@ int date_main(int argc UNUSED_PARAM, char **argv) } /* Correct any day of week and day of year etc. fields */ - tm_time.tm_isdst = -1; /* Be sure to recheck dst */ + /* Be sure to recheck dst (but not if date is time_t format) */ + if (date_str[0] != '@') + tm_time.tm_isdst = -1; ts.tv_sec = validate_tm_time(date_str, &tm_time); maybe_set_utc(opt); diff --git a/release/src/router/busybox/coreutils/dd.c b/release/src/router/busybox/coreutils/dd.c index 347a19454e..96602ebdd5 100644 --- a/release/src/router/busybox/coreutils/dd.c +++ b/release/src/router/busybox/coreutils/dd.c @@ -8,6 +8,38 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define dd_trivial_usage +//usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" +//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") +//usage:#define dd_full_usage "\n\n" +//usage: "Copy a file with converting and formatting\n" +//usage: "\n if=FILE Read from FILE instead of stdin" +//usage: "\n of=FILE Write to FILE instead of stdout" +//usage: "\n bs=N Read and write N bytes at a time" +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n ibs=N Read N bytes at a time" +//usage: ) +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n obs=N Write N bytes at a time" +//usage: ) +//usage: "\n count=N Copy only N input blocks" +//usage: "\n skip=N Skip N input blocks" +//usage: "\n seek=N Skip N output blocks" +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n conv=notrunc Don't truncate output file" +//usage: "\n conv=noerror Continue after read errors" +//usage: "\n conv=sync Pad blocks with zeros" +//usage: "\n conv=fsync Physically write data out before finishing" +//usage: ) +//usage: "\n" +//usage: "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024)," +//usage: "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)" +//usage: +//usage:#define dd_example_usage +//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" +//usage: "4+0 records in\n" +//usage: "4+0 records out\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -397,5 +429,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv) out_status: dd_output_status(0); + if (ENABLE_FEATURE_CLEAN_UP) { + free(obuf); + if (flags & FLAG_TWOBUFS) + free(ibuf); + } + return exitcode; } diff --git a/release/src/router/busybox/coreutils/df.c b/release/src/router/busybox/coreutils/df.c index 4031a48366..25dbd3eec1 100644 --- a/release/src/router/busybox/coreutils/df.c +++ b/release/src/router/busybox/coreutils/df.c @@ -22,6 +22,40 @@ * Implement -P and -B; better coreutils compat; cleanup */ +//usage:#define df_trivial_usage +//usage: "[-Pk" +//usage: IF_FEATURE_HUMAN_READABLE("mh") +//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") +//usage: "] [FILESYSTEM]..." +//usage:#define df_full_usage "\n\n" +//usage: "Print filesystem usage statistics\n" +//usage: "\n -P POSIX output format" +//usage: "\n -k 1024-byte blocks (default)" +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -m 1M-byte blocks" +//usage: "\n -h Human readable (e.g. 1K 243M 2G)" +//usage: ) +//usage: IF_FEATURE_DF_FANCY( +//usage: "\n -a Show all filesystems" +//usage: "\n -i Inodes" +//usage: "\n -B SIZE Blocksize" +//usage: ) +//usage: +//usage:#define df_example_usage +//usage: "$ df\n" +//usage: "Filesystem 1K-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 8690864 8553540 137324 98% /\n" +//usage: "/dev/sda1 64216 36364 27852 57% /boot\n" +//usage: "$ df /dev/sda3\n" +//usage: "Filesystem 1K-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 8690864 8553540 137324 98% /\n" +//usage: "$ POSIXLY_CORRECT=sure df /dev/sda3\n" +//usage: "Filesystem 512B-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 17381728 17107080 274648 98% /\n" +//usage: "$ POSIXLY_CORRECT=yep df -P /dev/sda3\n" +//usage: "Filesystem 512-blocks Used Available Capacity Mounted on\n" +//usage: "/dev/sda3 17381728 17107080 274648 98% /\n" + #include #include #include "libbb.h" @@ -162,7 +196,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) } /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */ - if (strcmp(device, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) continue; #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY @@ -180,7 +214,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) { uni_stat_t uni_stat; char *uni_dev = unicode_conv_to_printable(&uni_stat, device); - if (uni_stat.unicode_width > 20) { + if (uni_stat.unicode_width > 20 && !(opt & OPT_POSIX)) { printf("%s\n%20s", uni_dev, ""); } else { printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, ""); @@ -188,7 +222,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) free(uni_dev); } #else - if (printf("\n%-20s" + 1, device) > 20) + if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX)) printf("\n%-20s", ""); #endif diff --git a/release/src/router/busybox/coreutils/dirname.c b/release/src/router/busybox/coreutils/dirname.c index 246946ed03..101067c906 100644 --- a/release/src/router/busybox/coreutils/dirname.c +++ b/release/src/router/busybox/coreutils/dirname.c @@ -10,6 +10,17 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/dirname.html */ +//usage:#define dirname_trivial_usage +//usage: "FILENAME" +//usage:#define dirname_full_usage "\n\n" +//usage: "Strip non-directory suffix from FILENAME" +//usage: +//usage:#define dirname_example_usage +//usage: "$ dirname /tmp/foo\n" +//usage: "/tmp\n" +//usage: "$ dirname /tmp/foo/\n" +//usage: "/tmp\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/dos2unix.c b/release/src/router/busybox/coreutils/dos2unix.c index eab8110dc8..07398bdfa7 100644 --- a/release/src/router/busybox/coreutils/dos2unix.c +++ b/release/src/router/busybox/coreutils/dos2unix.c @@ -12,6 +12,22 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define dos2unix_trivial_usage +//usage: "[-ud] [FILE]" +//usage:#define dos2unix_full_usage "\n\n" +//usage: "Convert FILE in-place from DOS to Unix format.\n" +//usage: "When no file is given, use stdin/stdout.\n" +//usage: "\n -u dos2unix" +//usage: "\n -d unix2dos" +//usage: +//usage:#define unix2dos_trivial_usage +//usage: "[-ud] [FILE]" +//usage:#define unix2dos_full_usage "\n\n" +//usage: "Convert FILE in-place from Unix to DOS format.\n" +//usage: "When no file is given, use stdin/stdout.\n" +//usage: "\n -u dos2unix" +//usage: "\n -d unix2dos" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/du.c b/release/src/router/busybox/coreutils/du.c index cc3c784339..19a0319f13 100644 --- a/release/src/router/busybox/coreutils/du.c +++ b/release/src/router/busybox/coreutils/du.c @@ -23,6 +23,40 @@ * 4) Fixed busybox bug #1284 involving long overflow with human_readable. */ +//usage:#define du_trivial_usage +//usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." +//usage:#define du_full_usage "\n\n" +//usage: "Summarize disk space used for each FILE and/or directory\n" +//usage: "\n -a Show file sizes too" +//usage: "\n -L Follow all symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: "\n -d N Limit output to directories (and files with -a) of depth < N" +//usage: "\n -c Show grand total" +//usage: "\n -l Count sizes many times if hard linked" +//usage: "\n -s Display only a total for each argument" +//usage: "\n -x Skip directories on different filesystems" +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G)" +//usage: "\n -m Sizes in megabytes" +//usage: ) +//usage: "\n -k Sizes in kilobytes" IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") +//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K( +//usage: "\n Default unit is 512 bytes" +//usage: ) +//usage: +//usage:#define du_example_usage +//usage: "$ du\n" +//usage: "16 ./CVS\n" +//usage: "12 ./kernel-patches/CVS\n" +//usage: "80 ./kernel-patches\n" +//usage: "12 ./tests/CVS\n" +//usage: "36 ./tests\n" +//usage: "12 ./scripts/CVS\n" +//usage: "16 ./scripts\n" +//usage: "12 ./docs/CVS\n" +//usage: "104 ./docs\n" +//usage: "2417 .\n" + #include "libbb.h" enum { @@ -52,9 +86,10 @@ struct globals { dev_t dir_dev; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) -static void print(unsigned long size, const char *filename) +static void print(unsigned long long size, const char *filename) { /* TODO - May not want to defer error checking here. */ #if ENABLE_FEATURE_HUMAN_READABLE @@ -68,15 +103,15 @@ static void print(unsigned long size, const char *filename) size++; size >>= 1; } - printf("%lu\t%s\n", size, filename); + printf("%llu\t%s\n", size, filename); #endif } /* tiny recursive du */ -static unsigned long du(const char *filename) +static unsigned long long du(const char *filename) { struct stat statbuf; - unsigned long sum; + unsigned long long sum; if (lstat(filename, &statbuf) != 0) { bb_simple_perror_msg(filename); @@ -153,10 +188,12 @@ static unsigned long du(const char *filename) int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int du_main(int argc UNUSED_PARAM, char **argv) { - unsigned long total; + unsigned long long total; int slink_depth_save; unsigned opt; + INIT_G(); + #if ENABLE_FEATURE_HUMAN_READABLE IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;) IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;) diff --git a/release/src/router/busybox/coreutils/echo.c b/release/src/router/busybox/coreutils/echo.c index 3821e594e3..9663894ec8 100644 --- a/release/src/router/busybox/coreutils/echo.c +++ b/release/src/router/busybox/coreutils/echo.c @@ -23,128 +23,161 @@ * The previous version did not allow 4-digit octals. */ +//usage:#define echo_trivial_usage +//usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." +//usage:#define echo_full_usage "\n\n" +//usage: "Print the specified ARGs to stdout" +//usage: IF_FEATURE_FANCY_ECHO( "\n" +//usage: "\n -n Suppress trailing newline" +//usage: "\n -e Interpret backslash escapes (i.e., \\t=tab)" +//usage: "\n -E Don't interpret backslash escapes (default)" +//usage: ) +//usage: +//usage:#define echo_example_usage +//usage: "$ echo \"Erik is cool\"\n" +//usage: "Erik is cool\n" +//usage: IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" +//usage: "Erik\n" +//usage: "is\n" +//usage: "cool\n" +//usage: "$ echo \"Erik\\nis\\ncool\"\n" +//usage: "Erik\\nis\\ncool\n") + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ /* NB: can be used by shell even if not enabled as applet */ +/* + * NB2: we don't use stdio, we need better error handing. + * Examples include writing into non-opened stdout and error on write. + * + * 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. + * If echo is called by shell, it will try writing again later, and possibly + * will clobber future output. Not good. + * + * Solaris has fpurge which discards buffered input. glibc has __fpurge. + * But this function is not standard. + */ + int echo_main(int argc UNUSED_PARAM, char **argv) { + char **pp; const char *arg; + char *out; + char *buffer; + unsigned buflen; #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. */ -// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? - if (fcntl(1, F_GETFL) == -1) - return 1; /* match coreutils 6.10 (sans error msg to stderr) */ - //if (dup2(1, 1) != 1) - old way - // return 1; - - arg = *++argv; - if (!arg) - goto newline_ret; + argv++; #else - const char *p; char nflag = 1; char eflag = 0; - /* We must check that stdout is not closed. */ - if (fcntl(1, F_GETFL) == -1) - return 1; + while ((arg = *++argv) != NULL) { + char n, e; - while (1) { - arg = *++argv; - if (!arg) - goto newline_ret; - if (*arg != '-') - break; + if (arg[0] != '-') + break; /* not an option arg, echo it */ /* 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; - + arg++; + n = nflag; + e = eflag; do { - if (!strrchr("neE", *p)) + if (*arg == 'n') + n = 0; + else if (*arg == 'e') + e = '\\'; + else if (*arg != 'E') { + /* "-ccc" arg with one of c's invalid, echo it */ + /* arg consisting from just "-" also handled here */ 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); + } + } while (*++arg); + nflag = n; + eflag = e; } just_echo: #endif - while (1) { - /* arg is already == *argv and isn't NULL */ + + buflen = 0; + pp = argv; + while ((arg = *pp) != NULL) { + buflen += strlen(arg) + 1; + pp++; + } + out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */ + + while ((arg = *argv) != NULL) { int c; if (!eflag) { /* optimization for very common case */ - fputs(arg, stdout); - } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + out = stpcpy(out, arg); + } else + while ((c = *arg++) != '\0') { + if (c == eflag) { + /* This is an "\x" sequence */ + if (*arg == 'c') { - /* '\c' means cancel newline and + /* "\c" means cancel newline and * ignore all subsequent chars. */ - goto ret; + goto do_write; } -#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++; - } + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0') { + if ((unsigned char)(arg[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + arg++; } - /* bb_process_escape_sequence handles NUL correctly - * ("...\" case). */ - c = bb_process_escape_sequence(&arg); + } + /* bb_process_escape_sequence handles NUL correctly + * ("...\" case). */ + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. ~30 bytes win */ + const char *z = arg; + c = bb_process_escape_sequence(&z); + arg = z; } } - bb_putchar(c); + *out++ = c; } - arg = *++argv; - if (!arg) + if (!*++argv) break; - bb_putchar(' '); + *out++ = ' '; } - newline_ret: if (nflag) { - bb_putchar('\n'); + *out++ = '\n'; } - ret: - return fflush_all(); + + do_write: + /* Careful to error out on partial writes too (think ENOSPC!) */ + errno = 0; + /*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer); + free(buffer); + if (/*WRONG:r < 0*/ errno) { + bb_perror_msg(bb_msg_write_error); + return 1; + } + return 0; } -/*- +/* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -230,7 +263,7 @@ int echo_main(int argc, char **argv) goto just_echo; do { - if (!strrchr("neE", *p)) + if (!strchr("neE", *p)) goto just_echo; } while (*++p); @@ -256,27 +289,23 @@ int echo_main(int argc, char **argv) /* optimization for very common case */ p += strlen(arg); } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + if (c == eflag) { + /* This is an "\x" sequence */ + if (*arg == 'c') { - /* '\c' means cancel newline and + /* "\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); + /* 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; } diff --git a/release/src/router/busybox/coreutils/env.c b/release/src/router/busybox/coreutils/env.c index d64a714396..807ef13e9b 100644 --- a/release/src/router/busybox/coreutils/env.c +++ b/release/src/router/busybox/coreutils/env.c @@ -31,6 +31,14 @@ /* This is a NOEXEC applet. Be very careful! */ +//usage:#define env_trivial_usage +//usage: "[-iu] [-] [name=value]... [PROG ARGS]" +//usage:#define env_full_usage "\n\n" +//usage: "Print the current environment or run PROG after setting up\n" +//usage: "the specified environment\n" +//usage: "\n -, -i Start with an empty environment" +//usage: "\n -u Remove variable from the environment" + #include "libbb.h" #if ENABLE_FEATURE_ENV_LONG_OPTIONS diff --git a/release/src/router/busybox/coreutils/expand.c b/release/src/router/busybox/coreutils/expand.c index 7491b717ac..25bbffc66f 100644 --- a/release/src/router/busybox/coreutils/expand.c +++ b/release/src/router/busybox/coreutils/expand.c @@ -20,6 +20,35 @@ * * Caveat: this versions of expand and unexpand don't accept tab lists. */ + +//usage:#define expand_trivial_usage +//usage: "[-i] [-t N] [FILE]..." +//usage:#define expand_full_usage "\n\n" +//usage: "Convert tabs to spaces, writing to stdout\n" +//usage: IF_FEATURE_EXPAND_LONG_OPTIONS( +//usage: "\n -i,--initial Don't convert tabs after non blanks" +//usage: "\n -t,--tabs=N Tabstops every N chars" +//usage: ) +//usage: IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( +//usage: "\n -i Don't convert tabs after non blanks" +//usage: "\n -t Tabstops every N chars" +//usage: ) + +//usage:#define unexpand_trivial_usage +//usage: "[-fa][-t N] [FILE]..." +//usage:#define unexpand_full_usage "\n\n" +//usage: "Convert spaces to tabs, writing to stdout\n" +//usage: IF_FEATURE_UNEXPAND_LONG_OPTIONS( +//usage: "\n -a,--all Convert all blanks" +//usage: "\n -f,--first-only Convert only leading blanks" +//usage: "\n -t,--tabs=N Tabstops every N chars" +//usage: ) +//usage: IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( +//usage: "\n -a Convert all blanks" +//usage: "\n -f Convert only leading blanks" +//usage: "\n -t N Tabstops every N chars" +//usage: ) + #include "libbb.h" #include "unicode.h" diff --git a/release/src/router/busybox/coreutils/expr.c b/release/src/router/busybox/coreutils/expr.c index 04d783f2b5..c986f93274 100644 --- a/release/src/router/busybox/coreutils/expr.c +++ b/release/src/router/busybox/coreutils/expr.c @@ -25,6 +25,41 @@ /* no getopt needed */ +//usage:#define expr_trivial_usage +//usage: "EXPRESSION" +//usage:#define expr_full_usage "\n\n" +//usage: "Print the value of EXPRESSION to stdout\n" +//usage: "\n" +//usage: "EXPRESSION may be:\n" +//usage: " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" +//usage: " ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" +//usage: " ARG1 < ARG2 1 if ARG1 is less than ARG2, else 0. Similarly:\n" +//usage: " ARG1 <= ARG2\n" +//usage: " ARG1 = ARG2\n" +//usage: " ARG1 != ARG2\n" +//usage: " ARG1 >= ARG2\n" +//usage: " ARG1 > ARG2\n" +//usage: " ARG1 + ARG2 Sum of ARG1 and ARG2. Similarly:\n" +//usage: " ARG1 - ARG2\n" +//usage: " ARG1 * ARG2\n" +//usage: " ARG1 / ARG2\n" +//usage: " ARG1 % ARG2\n" +//usage: " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" +//usage: " match STRING REGEXP Same as STRING : REGEXP\n" +//usage: " substr STRING POS LENGTH Substring of STRING, POS counted from 1\n" +//usage: " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" +//usage: " length STRING Length of STRING\n" +//usage: " quote TOKEN Interpret TOKEN as a string, even if\n" +//usage: " it is a keyword like 'match' or an\n" +//usage: " operator like '/'\n" +//usage: " (EXPRESSION) Value of EXPRESSION\n" +//usage: "\n" +//usage: "Beware that many operators need to be escaped or quoted for shells.\n" +//usage: "Comparisons are arithmetic if both ARGs are numbers, else\n" +//usage: "lexicographical. Pattern matches return the string matched between\n" +//usage: "\\( and \\) or null; if \\( and \\) are not used, they return the number\n" +//usage: "of characters matched or 0." + #include "libbb.h" #include "xregex.h" @@ -65,6 +100,7 @@ struct globals { char **args; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) /* forward declarations */ static VALUE *eval(void); @@ -484,6 +520,8 @@ int expr_main(int argc UNUSED_PARAM, char **argv) { VALUE *v; + INIT_G(); + xfunc_error_retval = 2; /* coreutils compat */ G.args = argv + 1; if (*G.args == NULL) { diff --git a/release/src/router/busybox/coreutils/false.c b/release/src/router/busybox/coreutils/false.c index 033d2bff4c..59c2f321ae 100644 --- a/release/src/router/busybox/coreutils/false.c +++ b/release/src/router/busybox/coreutils/false.c @@ -10,6 +10,16 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */ +//usage:#define false_trivial_usage +//usage: "" +//usage:#define false_full_usage "\n\n" +//usage: "Return an exit code of FALSE (1)" +//usage: +//usage:#define false_example_usage +//usage: "$ false\n" +//usage: "$ echo $?\n" +//usage: "1\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/fold.c b/release/src/router/busybox/coreutils/fold.c index 4a6429ad7b..0e7306377d 100644 --- a/release/src/router/busybox/coreutils/fold.c +++ b/release/src/router/busybox/coreutils/fold.c @@ -9,6 +9,15 @@ Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define fold_trivial_usage +//usage: "[-bs] [-w WIDTH] [FILE]..." +//usage:#define fold_full_usage "\n\n" +//usage: "Wrap input lines in each FILE (or stdin), writing to stdout\n" +//usage: "\n -b Count bytes rather than columns" +//usage: "\n -s Break at spaces" +//usage: "\n -w Use WIDTH columns instead of 80" + #include "libbb.h" #include "unicode.h" diff --git a/release/src/router/busybox/coreutils/fsync.c b/release/src/router/busybox/coreutils/fsync.c index b8b463cd16..652a41c33f 100644 --- a/release/src/router/busybox/coreutils/fsync.c +++ b/release/src/router/busybox/coreutils/fsync.c @@ -6,6 +6,13 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define fsync_trivial_usage +//usage: "[-d] FILE..." +//usage:#define fsync_full_usage "\n\n" +//usage: "Write files' buffered blocks to disk\n" +//usage: "\n -d Avoid syncing metadata" + #include "libbb.h" #ifndef O_NOATIME # define O_NOATIME 0 diff --git a/release/src/router/busybox/coreutils/head.c b/release/src/router/busybox/coreutils/head.c index 669aae8193..ec4512765a 100644 --- a/release/src/router/busybox/coreutils/head.c +++ b/release/src/router/busybox/coreutils/head.c @@ -11,6 +11,25 @@ /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ +//usage:#define head_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define head_full_usage "\n\n" +//usage: "Print first 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -n N[kbm] Print first N lines" +//usage: IF_FEATURE_FANCY_HEAD( +//usage: "\n -c N[kbm] Print first N bytes" +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: ) +//usage: "\n" +//usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." +//usage: +//usage:#define head_example_usage +//usage: "$ head -n 2 /etc/passwd\n" +//usage: "root:x:0:0:root:/root:/bin/bash\n" +//usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/hostid.c b/release/src/router/busybox/coreutils/hostid.c index 635e48e124..5c1a4e0861 100644 --- a/release/src/router/busybox/coreutils/hostid.c +++ b/release/src/router/busybox/coreutils/hostid.c @@ -9,6 +9,22 @@ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//config:config HOSTID +//config: bool "hostid" +//config: default y +//config: help +//config: hostid prints the numeric identifier (in hexadecimal) for +//config: the current host. + +//applet:IF_HOSTID(APPLET_NOFORK(hostid, hostid, BB_DIR_USR_BIN, BB_SUID_DROP, hostid)) + +//kbuild:lib-$(CONFIG_HOSTID) += hostid.o + +//usage:#define hostid_trivial_usage +//usage: "" +//usage:#define hostid_full_usage "\n\n" +//usage: "Print out a unique 32-bit identifier for the machine" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ @@ -20,7 +36,7 @@ int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) bb_show_usage(); } - printf("%lx\n", gethostid()); + printf("%08lx\n", gethostid()); return fflush_all(); } diff --git a/release/src/router/busybox/coreutils/id.c b/release/src/router/busybox/coreutils/id.c index ed1dc862e8..399d25e342 100644 --- a/release/src/router/busybox/coreutils/id.c +++ b/release/src/router/busybox/coreutils/id.c @@ -15,6 +15,50 @@ * Added -G option Tito Ragusa (C) 2008 for SUSv3. */ +//config:config ID +//config: bool "id" +//config: default y +//config: help +//config: id displays the current user and group ID names. + +//config:config GROUPS +//config: bool "groups" +//config: default y +//config: help +//config: Print the group names associated with current user id. + +//kbuild:lib-$(CONFIG_GROUPS) += id.o +//kbuild:lib-$(CONFIG_ID) += id.o + +//applet:IF_GROUPS(APPLET_NOEXEC(groups, id, BB_DIR_USR_BIN, BB_SUID_DROP, groups)) +//applet:IF_ID( APPLET_NOEXEC(id, id, BB_DIR_USR_BIN, BB_SUID_DROP, id )) + +//usage:#define id_trivial_usage +//usage: "[OPTIONS] [USER]" +//usage:#define id_full_usage "\n\n" +//usage: "Print information about USER or the current user\n" +//usage: IF_SELINUX( +//usage: "\n -Z Security context" +//usage: ) +//usage: "\n -u User ID" +//usage: "\n -g Group ID" +//usage: "\n -G Supplementary group IDs" +//usage: "\n -n Print names instead of numbers" +//usage: "\n -r Print real ID instead of effective ID" +//usage: +//usage:#define id_example_usage +//usage: "$ id\n" +//usage: "uid=1000(andersen) gid=1000(andersen)\n" + +//usage:#define groups_trivial_usage +//usage: "[USER]" +//usage:#define groups_full_usage "\n\n" +//usage: "Print the group memberships of USER or for the current process" +//usage: +//usage:#define groups_example_usage +//usage: "$ groups\n" +//usage: "andersen lp dialout cdrom floppy\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -73,7 +117,7 @@ static int print_user(uid_t id, const char *prefix) /* On error set *n < 0 and return >= 0 * If *n is too small, update it and return < 0 - * (ok to trash groups[] in both cases) + * (ok to trash groups[] in both cases) * Otherwise fill in groups[] and return >= 0 */ static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n) @@ -87,20 +131,19 @@ static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n) m = getgrouplist(username, rgid, groups, n); /* I guess *n < 0 might indicate error. Anyway, * malloc'ing -1 bytes won't be good, so: */ - //if (*n < 0) - // return 0; - //return m; - //commented out here, happens below anyway - } else { - /* On error -1 is returned, which ends up in *n */ - int nn = getgroups(*n, groups); - /* 0: nn <= *n, groups[] was big enough; -1 otherwise */ - m = - (nn > *n); - *n = nn; + if (*n < 0) + return 0; + return m; } - if (*n < 0) - return 0; /* error, don't return < 0! */ - return m; + + *n = getgroups(*n, groups); + if (*n >= 0) + return *n; + /* Error */ + if (errno == EINVAL) /* *n is too small? */ + *n = getgroups(0, groups); /* get needed *n */ + /* if *n >= 0, return -1 (got new *n), else return 0 (error): */ + return -(*n >= 0); } int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -118,11 +161,22 @@ int id_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_SELINUX security_context_t scontext = NULL; #endif - /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ - /* Don't allow more than one username */ - opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" + + if (ENABLE_GROUPS && (!ENABLE_ID || applet_name[0] == 'g')) { + /* TODO: coreutils groups prepend "USER : " prefix, + * and accept many usernames. Example: + * # groups root root + * root : root + * root : root + */ + opt = option_mask32 = getopt32(argv, "") | JUST_ALL_GROUPS | NAME_NOT_NUMBER; + } else { + /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ + /* Don't allow more than one username */ + opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); - opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); + opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); + } username = argv[optind]; if (username) { @@ -159,11 +213,11 @@ int id_main(int argc UNUSED_PARAM, char **argv) /* We are supplying largish buffer, trying * to not run get_groups() twice. That might be slow * ("user database in remote SQL server" case) */ - groups = xmalloc(64 * sizeof(gid_t)); + groups = xmalloc(64 * sizeof(groups[0])); n = 64; if (get_groups(username, rgid, groups, &n) < 0) { /* Need bigger buffer after all */ - groups = xrealloc(groups, n * sizeof(gid_t)); + groups = xrealloc(groups, n * sizeof(groups[0])); get_groups(username, rgid, groups, &n); } if (n > 0) { @@ -176,10 +230,9 @@ int id_main(int argc UNUSED_PARAM, char **argv) prefix = ","; } } else if (n < 0) { /* error in get_groups() */ - if (!ENABLE_DESKTOP) + if (ENABLE_DESKTOP) bb_error_msg_and_die("can't get groups"); - else - return EXIT_FAILURE; + return EXIT_FAILURE; } if (ENABLE_FEATURE_CLEAN_UP) free(groups); diff --git a/release/src/router/busybox/coreutils/install.c b/release/src/router/busybox/coreutils/install.c index 9dc90d6413..445497f9a8 100644 --- a/release/src/router/busybox/coreutils/install.c +++ b/release/src/router/busybox/coreutils/install.c @@ -6,6 +6,23 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +/* -v, -b, -c are ignored */ +//usage:#define install_trivial_usage +//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [SOURCE]... DEST" +//usage:#define install_full_usage "\n\n" +//usage: "Copy files and set attributes\n" +//usage: "\n -c Just copy (default)" +//usage: "\n -d Create directories" +//usage: "\n -D Create leading target directories" +//usage: "\n -s Strip symbol table" +//usage: "\n -p Preserve date" +//usage: "\n -o USER Set ownership" +//usage: "\n -g GRP Set group ownership" +//usage: "\n -m MODE Set permissions" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) + #include "libbb.h" #include "libcoreutils/coreutils.h" diff --git a/release/src/router/busybox/coreutils/length.c.disabled b/release/src/router/busybox/coreutils/length.c.disabled new file mode 100644 index 0000000000..aee898d22d --- /dev/null +++ b/release/src/router/busybox/coreutils/length.c.disabled @@ -0,0 +1,31 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +/* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */ + +//usage:#define length_trivial_usage +//usage: "STRING" +//usage:#define length_full_usage "\n\n" +//usage: "Print STRING's length" +//usage: +//usage:#define length_example_usage +//usage: "$ length Hello\n" +//usage: "5\n" + +#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_all(); +} diff --git a/release/src/router/busybox/coreutils/ln.c b/release/src/router/busybox/coreutils/ln.c index ddad120d11..0eb3e6579e 100644 --- a/release/src/router/busybox/coreutils/ln.c +++ b/release/src/router/busybox/coreutils/ln.c @@ -11,6 +11,21 @@ /* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */ +//usage:#define ln_trivial_usage +//usage: "[OPTIONS] TARGET... LINK|DIR" +//usage:#define ln_full_usage "\n\n" +//usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" +//usage: "\n -s Make symlinks instead of hardlinks" +//usage: "\n -f Remove existing destinations" +//usage: "\n -n Don't dereference symlinks - treat like normal file" +//usage: "\n -b Make a backup of the target (if exists) before link operation" +//usage: "\n -S suf Use suffix instead of ~ when making backup files" +//usage: +//usage:#define ln_example_usage +//usage: "$ ln -s BusyBox /tmp/ls\n" +//usage: "$ ls -l /tmp/ls\n" +//usage: "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -40,8 +55,12 @@ int ln_main(int argc, char **argv) last = argv[argc - 1]; argv += optind; - if (argc == optind + 1) { + if (!argv[1]) { + /* "ln PATH/TO/FILE" -> "ln PATH/TO/FILE FILE" */ *--argv = last; + /* xstrdup is needed: "ln -s PATH/TO/FILE/" is equivalent to + * "ln -s PATH/TO/FILE/ FILE", not "ln -s PATH/TO/FILE FILE" + */ last = bb_get_last_path_component_strip(xstrdup(last)); } @@ -50,8 +69,8 @@ int ln_main(int argc, char **argv) src = last; if (is_directory(src, - (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE, - NULL) + (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE + ) ) { src_name = xstrdup(*argv); src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); diff --git a/release/src/router/busybox/coreutils/logname.c b/release/src/router/busybox/coreutils/logname.c index 62f453f2f0..10b9615a1e 100644 --- a/release/src/router/busybox/coreutils/logname.c +++ b/release/src/router/busybox/coreutils/logname.c @@ -20,6 +20,15 @@ * a diagnostic message and an error return. */ +//usage:#define logname_trivial_usage +//usage: "" +//usage:#define logname_full_usage "\n\n" +//usage: "Print the name of the current user" +//usage: +//usage:#define logname_example_usage +//usage: "$ logname\n" +//usage: "root\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/ls.c b/release/src/router/busybox/coreutils/ls.c index 72f58c253a..d5b25ee70b 100644 --- a/release/src/router/busybox/coreutils/ls.c +++ b/release/src/router/busybox/coreutils/ls.c @@ -1,6 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * tiny-ls.c version 0.1.0: A minimalist 'ls' * Copyright (C) 1996 Brian Candler * * Licensed under GPLv2 or later, see file LICENSE in this source tree. @@ -29,6 +28,70 @@ * [2009-03] * ls sorts listing now, and supports almost all options. */ + +//usage:#define ls_trivial_usage +//usage: "[-1AaCxd" +//usage: IF_FEATURE_LS_FOLLOWLINKS("LH") +//usage: IF_FEATURE_LS_RECURSIVE("R") +//usage: IF_FEATURE_LS_FILETYPES("Fp") "lins" +//usage: IF_FEATURE_LS_TIMESTAMPS("e") +//usage: IF_FEATURE_HUMAN_READABLE("h") +//usage: IF_FEATURE_LS_SORTFILES("rSXv") +//usage: IF_FEATURE_LS_TIMESTAMPS("ctu") +//usage: IF_SELINUX("kKZ") "]" +//usage: IF_FEATURE_AUTOWIDTH(" [-w WIDTH]") " [FILE]..." +//usage:#define ls_full_usage "\n\n" +//usage: "List directory contents\n" +//usage: "\n -1 One column output" +//usage: "\n -a Include entries which start with ." +//usage: "\n -A Like -a, but exclude . and .." +//usage: "\n -C List by columns" +//usage: "\n -x List by lines" +//usage: "\n -d List directory entries instead of contents" +//usage: IF_FEATURE_LS_FOLLOWLINKS( +//usage: "\n -L Follow symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: ) +//usage: IF_FEATURE_LS_RECURSIVE( +//usage: "\n -R Recurse" +//usage: ) +//usage: IF_FEATURE_LS_FILETYPES( +//usage: "\n -p Append / to dir entries" +//usage: "\n -F Append indicator (one of */=@|) to entries" +//usage: ) +//usage: "\n -l Long listing format" +//usage: "\n -i List inode numbers" +//usage: "\n -n List numeric UIDs and GIDs instead of names" +//usage: "\n -s List allocated blocks" +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -e List full date and time" +//usage: ) +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h List sizes in human readable format (1K 243M 2G)" +//usage: ) +//usage: IF_FEATURE_LS_SORTFILES( +//usage: "\n -r Sort in reverse order" +//usage: "\n -S Sort by size" +//usage: "\n -X Sort by extension" +//usage: "\n -v Sort by version" +//usage: ) +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -c With -l: sort by ctime" +//usage: "\n -t With -l: sort by mtime" +//usage: "\n -u With -l: sort by atime" +//usage: ) +//usage: IF_SELINUX( +//usage: "\n -k List security context" +//usage: "\n -K List security context in long format" +//usage: "\n -Z List security context and permission" +//usage: ) +//usage: IF_FEATURE_AUTOWIDTH( +//usage: "\n -w N Assume the terminal is N columns wide" +//usage: ) +//usage: IF_FEATURE_LS_COLOR( +//usage: "\n --color[={always,never,auto}] Control coloring" +//usage: ) + #include "libbb.h" #include "unicode.h" @@ -53,13 +116,12 @@ 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, +SPLIT_FILE = 0, +SPLIT_DIR = 1, +SPLIT_SUBDIR = 2, + +/* Bits in G.all_fmt: */ /* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ /* what file information will be listed */ @@ -71,76 +133,75 @@ LIST_ID_NAME = 1 << 4, LIST_ID_NUMERIC = 1 << 5, LIST_CONTEXT = 1 << 6, LIST_SIZE = 1 << 7, -//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE -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, +LIST_DATE_TIME = 1 << 8, +LIST_FULLTIME = 1 << 9, +LIST_SYMLINK = 1 << 10, +LIST_FILETYPE = 1 << 11, /* show / suffix for dirs */ +LIST_CLASSIFY = 1 << 12, /* requires LIST_FILETYPE, also show *,|,@,= suffixes */ +LIST_MASK = (LIST_CLASSIFY << 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_DIRNAME = 1 << 13, /* 2 or more items? label directories */ +DISP_HIDDEN = 1 << 14, /* show filenames starting with . */ +DISP_DOT = 1 << 15, /* show . and .. */ +DISP_NOLIST = 1 << 16, /* show directory as itself, not contents */ +DISP_RECURSIVE = 1 << 17, /* show directory and everything below it */ +DISP_ROWS = 1 << 18, /* 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, +/* what is the overall style of the listing */ +STYLE_COLUMNAR = 1 << 19, /* many records per line */ +STYLE_LONG = 2 << 19, /* one record per line, extended info */ +STYLE_SINGLE = 3 << 19, /* one record per line */ +STYLE_MASK = STYLE_SINGLE, /* 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, +TIME_CHANGE = (1 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_ACCESS = (2 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_MASK = (3 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, -FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS, +/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ +SORT_REVERSE = 1 << 23, -LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE, +SORT_NAME = 0, /* sort by file name */ +SORT_SIZE = 1 << 24, /* sort by file size */ +SORT_ATIME = 2 << 24, /* sort by last access time */ +SORT_CTIME = 3 << 24, /* sort by last change time */ +SORT_MTIME = 4 << 24, /* sort by last modification time */ +SORT_VERSION = 5 << 24, /* sort by version */ +SORT_EXT = 6 << 24, /* sort by file name extension */ +SORT_DIR = 7 << 24, /* sort by file or directory */ +SORT_MASK = (7 << 24) * ENABLE_FEATURE_LS_SORTFILES, -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, + LIST_DATE_TIME | LIST_SYMLINK, }; -/* "[-]Cadil1", POSIX mandated options, busybox always supports */ -/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ -/* "[-]Q" GNU option? 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 */ +/* -Cadil1 Std options, busybox always supports */ +/* -gnsxA Std options, busybox always supports */ +/* -Q GNU option, busybox always supports */ +/* -k SELinux option, busybox always supports (ignores if !SELinux) */ +/* Std has -k which means "show sizes in kbytes" */ +/* -LHRctur Std options, busybox optionally supports */ +/* -Fp Std options, busybox optionally supports */ +/* -SXvhTw GNU options, busybox optionally supports */ +/* -T WIDTH Ignored (we don't use tabs on output) */ +/* -KZ SELinux mandated options, busybox optionally supports */ +/* (coreutils 8.4 has no -K, remove it?) */ +/* -e I think we made this one up (looks similar to GNU --full-time) */ +/* We already used up all 32 bits, if we need to add more, candidates for removal: */ +/* -K, -T, -e (add --full-time instead) */ static const char ls_options[] ALIGN1 = - "Cadil1gnsxQAk" /* 13 opts, total 13 */ + "Cadil1gnsxQAk" /* 13 opts, total 13 */ IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ - IF_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ - ; + IF_FEATURE_LS_RECURSIVE("R") /* 1, 24 */ + IF_SELINUX("KZ") /* 2, 26 */ + IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 28 */ + IF_FEATURE_HUMAN_READABLE("h") /* 1, 29 */ + IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 31 */ + /* with --color, we use all 32 bits */; enum { //OPT_C = (1 << 0), //OPT_a = (1 << 1), @@ -155,99 +216,149 @@ enum { OPT_Q = (1 << 10), //OPT_A = (1 << 11), //OPT_k = (1 << 12), - OPTBIT_color = 13 - + 4 * ENABLE_FEATURE_LS_TIMESTAMPS - + 4 * ENABLE_FEATURE_LS_SORTFILES - + 2 * ENABLE_FEATURE_LS_FILETYPES - + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_color = 1 << OPTBIT_color, -}; -enum { - LIST_MASK_TRIGGER = 0, - STYLE_MASK_TRIGGER = STYLE_MASK, - DISP_MASK_TRIGGER = DISP_ROWS, - SORT_MASK_TRIGGER = SORT_MASK, + OPTBIT_c = 13, + OPTBIT_e, + OPTBIT_t, + OPTBIT_u, + OPTBIT_S = OPTBIT_c + 4 * ENABLE_FEATURE_LS_TIMESTAMPS, + OPTBIT_X, /* 18 */ + OPTBIT_r, + OPTBIT_v, + OPTBIT_F = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_p, /* 22 */ + OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, + OPTBIT_K = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, + OPTBIT_Z, /* 25 */ + OPTBIT_L = OPTBIT_K + 2 * ENABLE_SELINUX, + OPTBIT_H, /* 27 */ + OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, + OPTBIT_w, /* 30 */ + OPTBIT_color = OPTBIT_T + 2 * ENABLE_FEATURE_AUTOWIDTH, + + OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_e = (1 << OPTBIT_e) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_t = (1 << OPTBIT_t) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_u = (1 << OPTBIT_u) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_S = (1 << OPTBIT_S) * ENABLE_FEATURE_LS_SORTFILES, + OPT_X = (1 << OPTBIT_X) * ENABLE_FEATURE_LS_SORTFILES, + OPT_r = (1 << OPTBIT_r) * ENABLE_FEATURE_LS_SORTFILES, + OPT_v = (1 << OPTBIT_v) * ENABLE_FEATURE_LS_SORTFILES, + OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, + OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, + OPT_R = (1 << OPTBIT_R) * ENABLE_FEATURE_LS_RECURSIVE, + OPT_K = (1 << OPTBIT_K) * ENABLE_SELINUX, + OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX, + OPT_L = (1 << OPTBIT_L) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_H = (1 << OPTBIT_H) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_h = (1 << OPTBIT_h) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_T = (1 << OPTBIT_T) * ENABLE_FEATURE_AUTOWIDTH, + OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_AUTOWIDTH, + OPT_color = (1 << OPTBIT_color) * ENABLE_FEATURE_LS_COLOR, }; /* TODO: simple toggles may be stored as OPT_xxx bits instead */ -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 (don't show owner) - handled via OPT_g */ - LIST_ID_NUMERIC, /* n */ - LIST_BLOCKS, /* s */ - DISP_ROWS, /* x */ - 0, /* Q (quote filename) - handled via OPT_Q */ - DISP_HIDDEN, /* A */ - ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ +static const uint32_t opt_flags[] = { + STYLE_COLUMNAR, /* C */ + DISP_HIDDEN | DISP_DOT, /* a */ + DISP_NOLIST, /* d */ + LIST_INO, /* i */ + LIST_LONG | STYLE_LONG, /* l */ + STYLE_SINGLE, /* 1 */ + LIST_LONG | STYLE_LONG, /* g (don't show owner) - handled via OPT_g. assumes l */ + LIST_ID_NUMERIC | LIST_LONG | STYLE_LONG, /* n (assumes l) */ + LIST_BLOCKS, /* s */ + DISP_ROWS | STYLE_COLUMNAR, /* x */ + 0, /* Q (quote filename) - handled via OPT_Q */ + DISP_HIDDEN, /* A */ + ENABLE_SELINUX * (LIST_CONTEXT|STYLE_SINGLE), /* 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 */ + 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 */ + 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 */ + LIST_FILETYPE | LIST_CLASSIFY, /* F */ + LIST_FILETYPE, /* p */ #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 */ + DISP_RECURSIVE, /* R */ #endif #if ENABLE_SELINUX - LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ + LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME|STYLE_SINGLE, /* K */ + LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT|STYLE_SINGLE, /* Z */ #endif - (1U<<31) - /* options after Z are not processed through opt_flags: - * T, w - ignored - */ + (1U << 31) + /* options after Z are not processed through opt_flags */ }; /* - * a directory entry and its stat info are stored here + * a directory entry and its stat info */ struct dnode { - const char *name; /* the dir entry name */ - const char *fullname; /* the dir entry name */ - struct dnode *next; /* point at the next node */ - smallint fname_allocated; - struct stat dstat; /* the file stat info */ + const char *name; /* usually basename, but think "ls -l dir/file" */ + const char *fullname; /* full name (usable for stat etc) */ + struct dnode *dn_next; /* for linked list */ IF_SELINUX(security_context_t sid;) + smallint fname_allocated; + + /* Used to avoid re-doing [l]stat at printout stage + * if we already collected needed data in scan stage: + */ + mode_t dn_mode_lstat; /* obtained with lstat, or 0 */ + mode_t dn_mode_stat; /* obtained with stat, or 0 */ + +// struct stat dstat; +// struct stat is huge. We don't need it in full. +// At least we don't need st_dev and st_blksize, +// but there are invisible fields as well +// (such as nanosecond-resolution timespamps) +// and padding, which we also don't want to store. +// We also can pre-parse dev_t dn_rdev (in glibc, it's huge). +// On 32-bit uclibc: dnode size went from 112 to 84 bytes. +// + /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ + mode_t dn_mode; /* obtained with lstat OR stat, depending on -L etc */ + off_t dn_size; +#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES + time_t dn_atime; + time_t dn_mtime; + time_t dn_ctime; +#endif + ino_t dn_ino; + blkcnt_t dn_blocks; + nlink_t dn_nlink; + uid_t dn_uid; + gid_t dn_gid; + int dn_rdev_maj; + int dn_rdev_min; +// dev_t dn_dev; +// blksize_t dn_blksize; }; struct globals { #if ENABLE_FEATURE_LS_COLOR smallint show_color; +# define G_show_color (G.show_color) +#else +# define G_show_color 0 #endif smallint exit_code; unsigned all_fmt; #if ENABLE_FEATURE_AUTOWIDTH - unsigned tabstops; // = COLUMN_GAP; - unsigned terminal_width; // = TERMINAL_WIDTH; + unsigned terminal_width; +# define G_terminal_width (G.terminal_width) +#else +# define G_terminal_width TERMINAL_WIDTH #endif #if ENABLE_FEATURE_LS_TIMESTAMPS /* Do time() just once. Saves one syscall per file for "ls -l" */ @@ -255,77 +366,24 @@ struct globals { #endif } FIX_ALIASING; #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) #define INIT_G() do { \ /* we have to zero it out because of NOEXEC */ \ memset(&G, 0, sizeof(G)); \ - IF_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \ - IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \ - IF_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \ + IF_FEATURE_AUTOWIDTH(G_terminal_width = TERMINAL_WIDTH;) \ + IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ } while (0) -static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) -{ - struct stat dstat; - struct dnode *cur; - IF_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; - } - } +/*** Output code ***/ - cur = xmalloc(sizeof(*cur)); - cur->fullname = fullname; - cur->name = name; - cur->dstat = dstat; - IF_SELINUX(cur->sid = sid;) - return cur; -} /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file * 3/7:multiplexed char/block device) * and we use 0 for unknown and 15 for executables (see below) */ #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)]) +/* un fi chr - dir - blk - file - link - sock - - exe */ +#define APPCHAR(mode) ("\0""|""\0""\0""/""\0""\0""\0""\0""\0""@""\0""=""\0""\0""\0" [TYPEINDEX(mode)]) /* 036 black foreground 050 black background 037 red foreground 051 red background 040 green foreground 052 green background @@ -336,7 +394,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f 045 gray foreground 057 white background */ #define COLOR(mode) ( \ - /*un fi chr dir blk file link sock exe */ \ + /*un fi chr - dir - blk - file - link - sock - - exe */ \ "\037\043\043\045\042\045\043\043\000\045\044\045\043\045\045\040" \ [TYPEINDEX(mode)]) /* Select normal (0) [actually "reset all"] or bold (1) @@ -345,7 +403,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f * Note: coreutils 6.9 uses inverted red for setuid binaries. */ #define ATTR(mode) ( \ - /*un fi chr dir blk file link sock exe */ \ + /*un fi chr - dir - blk - file- link- sock- - exe */ \ "\01\00\01\07\01\07\01\07\00\07\01\07\01\07\07\01" \ [TYPEINDEX(mode)]) @@ -365,14 +423,14 @@ static char bold(mode_t mode) } #endif -#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR +#if ENABLE_FEATURE_LS_FILETYPES static char append_char(mode_t mode) { - if (!(all_fmt & LIST_FILETYPE)) + if (!(G.all_fmt & LIST_FILETYPE)) return '\0'; if (S_ISDIR(mode)) return '/'; - if (!(all_fmt & LIST_EXEC)) + if (!(G.all_fmt & LIST_CLASSIFY)) return '\0'; if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; @@ -380,149 +438,6 @@ static char append_char(mode_t mode) } #endif -static unsigned count_dirs(struct dnode **dn, int which) -{ - unsigned dirs, all; - - if (!dn) - return 0; - - dirs = all = 0; - for (; *dn; dn++) { - const char *name; - - all++; - if (!S_ISDIR((*dn)->dstat.st_mode)) - continue; - name = (*dn)->name; - if (which != SPLIT_SUBDIR /* if not requested to skip . / .. */ - /* or if it's not . or .. */ - || name[0] != '.' || (name[1] && (name[1] != '.' || name[2])) - ) { - dirs++; - } - } - return which != SPLIT_FILE ? dirs : all - dirs; -} - -/* get memory to hold an array of pointers */ -static struct dnode **dnalloc(unsigned num) -{ - if (num < 1) - return NULL; - - num++; /* so that we have terminating NULL */ - return xzalloc(num * sizeof(struct dnode *)); -} - -#if ENABLE_FEATURE_LS_RECURSIVE -static void dfree(struct dnode **dnp) -{ - unsigned i; - - if (dnp == NULL) - return; - - for (i = 0; dnp[i]; i++) { - struct dnode *cur = dnp[i]; - if (cur->fname_allocated) - free((char*)cur->fullname); - free(cur); - } - free(dnp); -} -#else -#define dfree(...) ((void)0) -#endif - -/* Returns NULL-terminated malloced vector of pointers (or NULL) */ -static struct dnode **splitdnarray(struct dnode **dn, int which) -{ - unsigned dncnt, d; - struct dnode **dnp; - - if (dn == NULL) - return NULL; - - /* count how many dirs or files there are */ - dncnt = count_dirs(dn, which); - - /* allocate a file array and a dir array */ - dnp = dnalloc(dncnt); - - /* copy the entrys into the file or dir array */ - for (d = 0; *dn; dn++) { - if (S_ISDIR((*dn)->dstat.st_mode)) { - const char *name; - - if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) - continue; - name = (*dn)->name; - if ((which & SPLIT_DIR) - || name[0]!='.' || (name[1] && (name[1]!='.' || name[2])) - ) { - dnp[d++] = *dn; - } - } else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) { - dnp[d++] = *dn; - } - } - 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; - off_t dif; - - dif = 0; /* assume SORT_NAME */ - // TODO: use pre-initialized function pointer - // instead of branch forest - if (sort_opts == SORT_SIZE) { - dif = (d2->dstat.st_size - d1->dstat.st_size); - } else if (sort_opts == SORT_ATIME) { - dif = (d2->dstat.st_atime - d1->dstat.st_atime); - } else if (sort_opts == SORT_CTIME) { - dif = (d2->dstat.st_ctime - d1->dstat.st_ctime); - } else if (sort_opts == SORT_MTIME) { - dif = (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, or tie_breaker for other sorts */ - if (ENABLE_LOCALE_SUPPORT) - dif = strcoll(d1->name, d2->name); - else - dif = strcmp(d1->name, d2->name); - } - - /* Make dif fit into an int */ - if (sizeof(dif) > sizeof(int)) { - enum { BITS_TO_SHIFT = 8 * (sizeof(dif) - sizeof(int)) }; - /* shift leaving only "int" worth of bits */ - if (dif != 0) { - dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); - } - } - - return (all_fmt & SORT_REVERSE) ? -(int)dif : (int)dif; -} - -static void dnsort(struct dnode **dn, int size) -{ - qsort(dn, size, sizeof(*dn), sortcmp); -} -#else -#define dnsort(dn, size) ((void)0) -#endif - - static unsigned calc_name_len(const char *name) { unsigned len; @@ -545,9 +460,8 @@ static unsigned calc_name_len(const char *name) return len; } - /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value. + * Note that only STYLE_COLUMNAR uses return value. * STYLE_SINGLE and STYLE_LONG don't care. * coreutils 7.2 also supports: * ls -b (--escape) = octal escapes (although it doesn't look like working) @@ -581,92 +495,92 @@ static unsigned print_name(const char *name) } /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value, + * Note that only STYLE_COLUMNAR uses return value, * STYLE_SINGLE and STYLE_LONG don't care. */ -static NOINLINE unsigned list_single(const struct dnode *dn) +static NOINLINE unsigned display_single(const struct dnode *dn) { unsigned column = 0; - char *lpath = lpath; /* for compiler */ + char *lpath; #if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR - struct stat info; + struct stat statbuf; char append; #endif - /* Never happens: - if (dn->fullname == NULL) - return 0; - */ - #if ENABLE_FEATURE_LS_FILETYPES - append = append_char(dn->dstat.st_mode); + append = append_char(dn->dn_mode); #endif /* Do readlink early, so that if it fails, error message * does not appear *inside* the "ls -l" line */ - if (all_fmt & LIST_SYMLINK) - if (S_ISLNK(dn->dstat.st_mode)) + lpath = NULL; + if (G.all_fmt & LIST_SYMLINK) + if (S_ISLNK(dn->dn_mode)) lpath = xmalloc_readlink_or_warn(dn->fullname); - if (all_fmt & LIST_INO) - column += printf("%7llu ", (long long) dn->dstat.st_ino); - if (all_fmt & LIST_BLOCKS) - column += printf("%4"OFF_FMT"u ", (off_t) (dn->dstat.st_blocks >> 1)); - if (all_fmt & LIST_MODEBITS) - column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode)); - if (all_fmt & LIST_NLINKS) - column += printf("%4lu ", (long) dn->dstat.st_nlink); + if (G.all_fmt & LIST_INO) + column += printf("%7llu ", (long long) dn->dn_ino); +//TODO: -h should affect -s too: + if (G.all_fmt & LIST_BLOCKS) + column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); + if (G.all_fmt & LIST_MODEBITS) + column += printf("%-10s ", (char *) bb_mode_string(dn->dn_mode)); + if (G.all_fmt & LIST_NLINKS) + column += printf("%4lu ", (long) dn->dn_nlink); + if (G.all_fmt & LIST_ID_NUMERIC) { + if (option_mask32 & OPT_g) + column += printf("%-8u ", (int) dn->dn_gid); + else + column += printf("%-8u %-8u ", + (int) dn->dn_uid, + (int) dn->dn_gid); + } #if ENABLE_FEATURE_LS_USERNAME - if (all_fmt & LIST_ID_NAME) { + else if (G.all_fmt & LIST_ID_NAME) { if (option_mask32 & OPT_g) { column += printf("%-8.8s ", - get_cached_groupname(dn->dstat.st_gid)); + get_cached_groupname(dn->dn_gid)); } else { column += printf("%-8.8s %-8.8s ", - get_cached_username(dn->dstat.st_uid), - get_cached_groupname(dn->dstat.st_gid)); + get_cached_username(dn->dn_uid), + get_cached_groupname(dn->dn_gid)); } } #endif - if (all_fmt & LIST_ID_NUMERIC) { - if (option_mask32 & OPT_g) - column += printf("%-8u ", (int) dn->dstat.st_gid); - else - column += printf("%-8u %-8u ", - (int) dn->dstat.st_uid, - (int) dn->dstat.st_gid); - } - if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) { - if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { + if (G.all_fmt & LIST_SIZE) { + if (S_ISBLK(dn->dn_mode) || S_ISCHR(dn->dn_mode)) { column += printf("%4u, %3u ", - (int) major(dn->dstat.st_rdev), - (int) minor(dn->dstat.st_rdev)); + dn->dn_rdev_maj, + dn->dn_rdev_min); } else { - if (all_fmt & LS_DISP_HR) { + if (option_mask32 & OPT_h) { column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", - /* print st_size, show one fractional, use suffixes */ - make_human_readable_str(dn->dstat.st_size, 1, 0) + /* print size, show one fractional, use suffixes */ + make_human_readable_str(dn->dn_size, 1, 0) ); } else { - column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size); + column += printf("%9"OFF_FMT"u ", dn->dn_size); } } } #if ENABLE_FEATURE_LS_TIMESTAMPS - if (all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) { + if (G.all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) { char *filetime; - time_t ttime = dn->dstat.st_mtime; - if (all_fmt & TIME_ACCESS) - ttime = dn->dstat.st_atime; - if (all_fmt & TIME_CHANGE) - ttime = dn->dstat.st_ctime; + time_t ttime = dn->dn_mtime; + if (G.all_fmt & TIME_ACCESS) + ttime = dn->dn_atime; + if (G.all_fmt & TIME_CHANGE) + ttime = dn->dn_ctime; filetime = ctime(&ttime); /* filetime's format: "Wed Jun 30 21:49:08 1993\n" */ - if (all_fmt & LIST_FULLTIME) + if (G.all_fmt & LIST_FULLTIME) { /* -e */ + /* Note: coreutils 8.4 ls --full-time prints: + * 2009-07-13 17:49:27.000000000 +0200 + */ column += printf("%.24s ", filetime); - else { /* LIST_DATE_TIME */ - /* current_time_t ~== time(NULL) */ - time_t age = current_time_t - ttime; + } else { /* LIST_DATE_TIME */ + /* G.current_time_t ~== time(NULL) */ + time_t age = G.current_time_t - ttime; printf("%.6s ", filetime + 4); /* "Jun 30" */ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { /* hh:mm if less than 6 months old */ @@ -679,51 +593,52 @@ static NOINLINE unsigned list_single(const struct dnode *dn) } #endif #if ENABLE_SELINUX - if (all_fmt & LIST_CONTEXT) { + if (G.all_fmt & LIST_CONTEXT) { column += printf("%-32s ", dn->sid ? dn->sid : "unknown"); freecon(dn->sid); } #endif - if (all_fmt & LIST_FILENAME) { + #if ENABLE_FEATURE_LS_COLOR - if (show_color) { - info.st_mode = 0; /* for fgcolor() */ - lstat(dn->fullname, &info); - printf("\033[%u;%um", bold(info.st_mode), - fgcolor(info.st_mode)); - } + if (G_show_color) { + mode_t mode = dn->dn_mode_lstat; + if (!mode) + if (lstat(dn->fullname, &statbuf) == 0) + mode = statbuf.st_mode; + printf("\033[%u;%um", bold(mode), fgcolor(mode)); + } #endif - column += print_name(dn->name); - if (show_color) { - printf("\033[0m"); - } + column += print_name(dn->name); + if (G_show_color) { + printf("\033[0m"); } - if (all_fmt & LIST_SYMLINK) { - if (S_ISLNK(dn->dstat.st_mode) && lpath) { - printf(" -> "); + + if (lpath) { + printf(" -> "); #if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR -#if ENABLE_FEATURE_LS_COLOR - info.st_mode = 0; /* for fgcolor() */ -#endif - if (stat(dn->fullname, &info) == 0) { - append = append_char(info.st_mode); - } -#endif -#if ENABLE_FEATURE_LS_COLOR - if (show_color) { - printf("\033[%u;%um", bold(info.st_mode), - fgcolor(info.st_mode)); + if ((G.all_fmt & LIST_FILETYPE) || G_show_color) { + mode_t mode = dn->dn_mode_stat; + if (!mode) + if (stat(dn->fullname, &statbuf) == 0) + mode = statbuf.st_mode; +# if ENABLE_FEATURE_LS_FILETYPES + append = append_char(mode); +# endif +# if ENABLE_FEATURE_LS_COLOR + if (G_show_color) { + printf("\033[%u;%um", bold(mode), fgcolor(mode)); } +# endif + } #endif - column += print_name(lpath) + 4; - if (show_color) { - printf("\033[0m"); - } - free(lpath); + column += print_name(lpath) + 4; + free(lpath); + if (G_show_color) { + printf("\033[0m"); } } #if ENABLE_FEATURE_LS_FILETYPES - if (all_fmt & LIST_FILETYPE) { + if (G.all_fmt & LIST_FILETYPE) { if (append) { putchar(append); column++; @@ -734,14 +649,14 @@ static NOINLINE unsigned list_single(const struct dnode *dn) return column; } -static void showfiles(struct dnode **dn, unsigned nfiles) +static void display_files(struct dnode **dn, unsigned nfiles) { unsigned i, ncols, nrows, row, nc; - unsigned column = 0; - unsigned nexttab = 0; - unsigned column_width = 0; /* used only by STYLE_COLUMNS */ + unsigned column; + unsigned nexttab; + unsigned column_width = 0; /* used only by STYLE_COLUMNAR */ - if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ + if (G.all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ ncols = 1; } else { /* find the longest file name, use that as the column width */ @@ -750,11 +665,11 @@ static void showfiles(struct dnode **dn, unsigned nfiles) if (column_width < len) column_width = len; } - column_width += tabstops + - IF_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); + column_width += 1 + + IF_SELINUX( ((G.all_fmt & LIST_CONTEXT) ? 33 : 0) + ) + ((G.all_fmt & LIST_INO) ? 8 : 0) + + ((G.all_fmt & LIST_BLOCKS) ? 5 : 0); + ncols = (unsigned)G_terminal_width / column_width; } if (ncols > 1) { @@ -766,21 +681,23 @@ static void showfiles(struct dnode **dn, unsigned nfiles) ncols = 1; } + column = 0; + nexttab = 0; for (row = 0; row < nrows; row++) { for (nc = 0; nc < ncols; nc++) { /* reach into the array based on the column and row */ - if (all_fmt & DISP_ROWS) + if (G.all_fmt & DISP_ROWS) i = (row * ncols) + nc; /* display across row */ else i = (nc * nrows) + row; /* display by column */ if (i < nfiles) { if (column > 0) { nexttab -= column; - printf("%*s", nexttab, ""); - column += nexttab; + printf("%*s ", nexttab, ""); + column += nexttab + 1; } nexttab = column + column_width; - column += list_single(dn[i]); + column += display_single(dn[i]); } } putchar('\n'); @@ -789,104 +706,241 @@ static void showfiles(struct dnode **dn, unsigned nfiles) } -#if ENABLE_DESKTOP -/* http://www.opengroup.org/onlinepubs/9699919799/utilities/ls.html - * If any of the -l, -n, -s options is specified, each list - * of files within the directory shall be preceded by a - * status line indicating the number of file system blocks - * occupied by files in the directory in 512-byte units if - * the -k option is not specified, or 1024-byte units if the - * -k option is specified, rounded up to the next integral - * number of units. - */ -/* by Jorgen Overgaard (jorgen AT antistaten.se) */ -static off_t calculate_blocks(struct dnode **dn) +/*** Dir scanning code ***/ + +static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) { - uoff_t blocks = 1; - if (dn) { - while (*dn) { - /* st_blocks is in 512 byte blocks */ - blocks += (*dn)->dstat.st_blocks; - dn++; + struct stat statbuf; + struct dnode *cur; + + cur = xzalloc(sizeof(*cur)); + cur->fullname = fullname; + cur->name = name; + + if ((option_mask32 & OPT_L) || force_follow) { +#if ENABLE_SELINUX + if (is_selinux_enabled()) { + getfilecon(fullname, &cur->sid); } +#endif + if (stat(fullname, &statbuf)) { + bb_simple_perror_msg(fullname); + G.exit_code = EXIT_FAILURE; + free(cur); + return NULL; + } + cur->dn_mode_stat = statbuf.st_mode; + } else { +#if ENABLE_SELINUX + if (is_selinux_enabled()) { + lgetfilecon(fullname, &cur->sid); + } +#endif + if (lstat(fullname, &statbuf)) { + bb_simple_perror_msg(fullname); + G.exit_code = EXIT_FAILURE; + free(cur); + return NULL; + } + cur->dn_mode_lstat = statbuf.st_mode; } - /* Even though standard says use 512 byte blocks, coreutils use 1k */ - /* Actually, we round up by calculating (blocks + 1) / 2, - * "+ 1" was done when we initialized blocks to 1 */ - return blocks >> 1; -} + /* cur->dstat = statbuf: */ + cur->dn_mode = statbuf.st_mode ; + cur->dn_size = statbuf.st_size ; +#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES + cur->dn_atime = statbuf.st_atime ; + cur->dn_mtime = statbuf.st_mtime ; + cur->dn_ctime = statbuf.st_ctime ; #endif + cur->dn_ino = statbuf.st_ino ; + cur->dn_blocks = statbuf.st_blocks; + cur->dn_nlink = statbuf.st_nlink ; + cur->dn_uid = statbuf.st_uid ; + cur->dn_gid = statbuf.st_gid ; + cur->dn_rdev_maj = major(statbuf.st_rdev); + cur->dn_rdev_min = minor(statbuf.st_rdev); + return cur; +} -static struct dnode **list_dir(const char *, unsigned *); - -static void showdirs(struct dnode **dn, int first) +static unsigned count_dirs(struct dnode **dn, int which) { - unsigned nfiles; - unsigned dndirs; - struct dnode **subdnp; - struct dnode **dnd; + unsigned dirs, all; - /* Never happens: - if (dn == NULL || ndirs < 1) { - return; - } - */ + if (!dn) + return 0; + dirs = all = 0; for (; *dn; dn++) { - if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { - if (!first) - bb_putchar('\n'); - first = 0; - printf("%s:\n", (*dn)->fullname); + const char *name; + + all++; + if (!S_ISDIR((*dn)->dn_mode)) + continue; + + name = (*dn)->name; + if (which != SPLIT_SUBDIR /* if not requested to skip . / .. */ + /* or if it's not . or .. */ + || name[0] != '.' + || (name[1] && (name[1] != '.' || name[2])) + ) { + dirs++; } - subdnp = list_dir((*dn)->fullname, &nfiles); -#if ENABLE_DESKTOP - if ((all_fmt & STYLE_MASK) == STYLE_LONG) - printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); + } + return which != SPLIT_FILE ? dirs : all - dirs; +} + +/* get memory to hold an array of pointers */ +static struct dnode **dnalloc(unsigned num) +{ + if (num < 1) + return NULL; + + num++; /* so that we have terminating NULL */ + return xzalloc(num * sizeof(struct dnode *)); +} + +#if ENABLE_FEATURE_LS_RECURSIVE +static void dfree(struct dnode **dnp) +{ + unsigned i; + + if (dnp == NULL) + return; + + for (i = 0; dnp[i]; i++) { + struct dnode *cur = dnp[i]; + if (cur->fname_allocated) + free((char*)cur->fullname); + free(cur); + } + free(dnp); +} +#else +#define dfree(...) ((void)0) #endif - if (nfiles > 0) { - /* list all files at this level */ - dnsort(subdnp, nfiles); - showfiles(subdnp, nfiles); - if (ENABLE_FEATURE_LS_RECURSIVE - && (all_fmt & DISP_RECURSIVE) + +/* Returns NULL-terminated malloced vector of pointers (or NULL) */ +static struct dnode **splitdnarray(struct dnode **dn, int which) +{ + unsigned dncnt, d; + struct dnode **dnp; + + if (dn == NULL) + return NULL; + + /* count how many dirs or files there are */ + dncnt = count_dirs(dn, which); + + /* allocate a file array and a dir array */ + dnp = dnalloc(dncnt); + + /* copy the entrys into the file or dir array */ + for (d = 0; *dn; dn++) { + if (S_ISDIR((*dn)->dn_mode)) { + const char *name; + + if (which == SPLIT_FILE) + continue; + + name = (*dn)->name; + if ((which & SPLIT_DIR) /* any dir... */ + /* ... or not . or .. */ + || name[0] != '.' + || (name[1] && (name[1] != '.' || name[2])) ) { - /* recursive - list the sub-dirs */ - dnd = splitdnarray(subdnp, SPLIT_SUBDIR); - dndirs = count_dirs(subdnp, SPLIT_SUBDIR); - if (dndirs > 0) { - dnsort(dnd, dndirs); - showdirs(dnd, 0); - /* free the array of dnode pointers to the dirs */ - free(dnd); - } + dnp[d++] = *dn; } - /* free the dnodes and the fullname mem */ - dfree(subdnp); + } else + if (which == SPLIT_FILE) { + dnp[d++] = *dn; + } + } + 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 = G.all_fmt & SORT_MASK; + off_t dif; + + dif = 0; /* assume SORT_NAME */ + // TODO: use pre-initialized function pointer + // instead of branch forest + if (sort_opts == SORT_SIZE) { + dif = (d2->dn_size - d1->dn_size); + } else + if (sort_opts == SORT_ATIME) { + dif = (d2->dn_atime - d1->dn_atime); + } else + if (sort_opts == SORT_CTIME) { + dif = (d2->dn_ctime - d1->dn_ctime); + } else + if (sort_opts == SORT_MTIME) { + dif = (d2->dn_mtime - d1->dn_mtime); + } else + if (sort_opts == SORT_DIR) { + dif = S_ISDIR(d2->dn_mode) - S_ISDIR(d1->dn_mode); + } else +#if defined(HAVE_STRVERSCMP) && HAVE_STRVERSCMP == 1 + if (sort_opts == SORT_VERSION) { + dif = strverscmp(d1->name, d2->name); + } else +#endif + if (sort_opts == SORT_EXT) { + dif = strcmp(strchrnul(d1->name, '.'), strchrnul(d2->name, '.')); + } + if (dif == 0) { + /* sort by name, use as tie breaker for other sorts */ + if (ENABLE_LOCALE_SUPPORT) + dif = strcoll(d1->name, d2->name); + else + dif = strcmp(d1->name, d2->name); + } + + /* Make dif fit into an int */ + if (sizeof(dif) > sizeof(int)) { + enum { BITS_TO_SHIFT = 8 * (sizeof(dif) - sizeof(int)) }; + /* shift leaving only "int" worth of bits */ + if (dif != 0) { + dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); } } + + return (G.all_fmt & SORT_REVERSE) ? -(int)dif : (int)dif; } +static void dnsort(struct dnode **dn, int size) +{ + qsort(dn, size, sizeof(*dn), sortcmp); +} + +static void sort_and_display_files(struct dnode **dn, unsigned nfiles) +{ + dnsort(dn, nfiles); + display_files(dn, nfiles); +} +#else +# define dnsort(dn, size) ((void)0) +# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles) +#endif /* Returns NULL-terminated malloced vector of pointers (or NULL) */ -static struct dnode **list_dir(const char *path, unsigned *nfiles_p) +static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) { struct dnode *dn, *cur, **dnp; struct dirent *entry; DIR *dir; unsigned i, nfiles; - /* Never happens: - if (path == NULL) - return NULL; - */ - *nfiles_p = 0; dir = warn_opendir(path); if (dir == NULL) { - exit_code = EXIT_FAILURE; + G.exit_code = EXIT_FAILURE; return NULL; /* could not open the dir */ } dn = NULL; @@ -897,11 +951,11 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) /* 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) + && !(G.all_fmt & DISP_DOT) ) { continue; } - if (!(all_fmt & DISP_HIDDEN)) + if (!(G.all_fmt & DISP_HIDDEN)) continue; } fullname = concat_path_file(path, entry->d_name); @@ -911,7 +965,7 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) continue; } cur->fname_allocated = 1; - cur->next = dn; + cur->dn_next = dn; dn = cur; nfiles++; } @@ -927,7 +981,7 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) dnp = dnalloc(nfiles); for (i = 0; /* i < nfiles - detected via !dn below */; i++) { dnp[i] = dn; /* save pointer to node in array */ - dn = dn->next; + dn = dn->dn_next; if (!dn) break; } @@ -935,6 +989,77 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) return dnp; } +#if ENABLE_DESKTOP +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/ls.html + * If any of the -l, -n, -s options is specified, each list + * of files within the directory shall be preceded by a + * status line indicating the number of file system blocks + * occupied by files in the directory in 512-byte units if + * the -k option is not specified, or 1024-byte units if the + * -k option is specified, rounded up to the next integral + * number of units. + */ +/* by Jorgen Overgaard (jorgen AT antistaten.se) */ +static off_t calculate_blocks(struct dnode **dn) +{ + uoff_t blocks = 1; + if (dn) { + while (*dn) { + /* st_blocks is in 512 byte blocks */ + blocks += (*dn)->dn_blocks; + dn++; + } + } + + /* Even though standard says use 512 byte blocks, coreutils use 1k */ + /* Actually, we round up by calculating (blocks + 1) / 2, + * "+ 1" was done when we initialized blocks to 1 */ + return blocks >> 1; +} +#endif + +static void scan_and_display_dirs_recur(struct dnode **dn, int first) +{ + unsigned nfiles; + struct dnode **subdnp; + + for (; *dn; dn++) { + if (G.all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { + if (!first) + bb_putchar('\n'); + first = 0; + printf("%s:\n", (*dn)->fullname); + } + subdnp = scan_one_dir((*dn)->fullname, &nfiles); +#if ENABLE_DESKTOP + if ((G.all_fmt & STYLE_MASK) == STYLE_LONG) + printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); +#endif + if (nfiles > 0) { + /* list all files at this level */ + sort_and_display_files(subdnp, nfiles); + + if (ENABLE_FEATURE_LS_RECURSIVE + && (G.all_fmt & DISP_RECURSIVE) + ) { + struct dnode **dnd; + unsigned dndirs; + /* recursive - list the sub-dirs */ + dnd = splitdnarray(subdnp, SPLIT_SUBDIR); + dndirs = count_dirs(subdnp, SPLIT_SUBDIR); + if (dndirs > 0) { + dnsort(dnd, dndirs); + scan_and_display_dirs_recur(dnd, 0); + /* free the array of dnode pointers to the dirs */ + free(dnd); + } + } + /* free the dnodes and the fullname mem */ + dfree(subdnp); + } + } +} + int ls_main(int argc UNUSED_PARAM, char **argv) { @@ -972,59 +1097,63 @@ int ls_main(int argc UNUSED_PARAM, char **argv) init_unicode(); - all_fmt = LIST_SHORT | - (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); + if (ENABLE_FEATURE_LS_SORTFILES) + G.all_fmt = SORT_NAME; #if ENABLE_FEATURE_AUTOWIDTH /* obtain the terminal width */ - get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL); + get_terminal_width_height(STDIN_FILENO, &G_terminal_width, NULL); /* go one less... */ - terminal_width--; + G_terminal_width--; #endif /* process options */ IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) -#if ENABLE_FEATURE_AUTOWIDTH - opt_complementary = "T+:w+"; /* -T N, -w N */ - opt = getopt32(argv, ls_options, &tabstops, &terminal_width - IF_FEATURE_LS_COLOR(, &color_opt)); -#else - opt = getopt32(argv, ls_options IF_FEATURE_LS_COLOR(, &color_opt)); -#endif - for (i = 0; opt_flags[i] != (1U<<31); i++) { + opt_complementary = + /* -e implies -l */ + IF_FEATURE_LS_TIMESTAMPS("el") + /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: + * in some pairs of opts, only last one takes effect: + */ + IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ + // ":m-l:l-m" - we don't have -m + IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") + ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ + ":C-1:1-C" /* bycols/oneline */ + ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ + IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ + /* -w NUM: */ + IF_FEATURE_AUTOWIDTH(":w+"); + opt = getopt32(argv, ls_options + IF_FEATURE_AUTOWIDTH(, NULL, &G_terminal_width) + IF_FEATURE_LS_COLOR(, &color_opt) + ); + 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; + uint32_t flags = opt_flags[i]; + + if (flags & STYLE_MASK) + G.all_fmt &= ~STYLE_MASK; + if (flags & SORT_MASK) + G.all_fmt &= ~SORT_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; + G.all_fmt &= ~TIME_MASK; + + G.all_fmt |= flags; } } #if ENABLE_FEATURE_LS_COLOR - /* find color bit value - last position for short getopt */ + /* set G_show_color = 1/0 */ 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") != 0)) - show_color = 1; + G_show_color = 1; } if (opt & OPT_color) { if (color_opt[0] == 'n') - show_color = 0; + G_show_color = 0; else switch (index_in_substrings(color_str, color_opt)) { case 3: case 4: @@ -1033,56 +1162,61 @@ int ls_main(int argc UNUSED_PARAM, char **argv) case 0: case 1: case 2: - show_color = 1; + G_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_RECURSIVE && (G.all_fmt & DISP_NOLIST)) + G.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 (G.all_fmt & TIME_CHANGE) + G.all_fmt = (G.all_fmt & ~SORT_MASK) | SORT_CTIME; + if (G.all_fmt & TIME_ACCESS) + G.all_fmt = (G.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 */ + if ((G.all_fmt & STYLE_MASK) != STYLE_LONG) /* not -l? */ + G.all_fmt &= ~(LIST_ID_NUMERIC|LIST_ID_NAME|LIST_FULLTIME); - /* choose a display format */ - if (!(all_fmt & STYLE_MASK)) - all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); + /* choose a display format if one was not already specified by an option */ + if (!(G.all_fmt & STYLE_MASK)) + G.all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNAR : STYLE_SINGLE); argv += optind; if (!argv[0]) *--argv = (char*)"."; if (argv[1]) - all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */ + G.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 { - /* NB: follow links on command line unless -l or -s */ - cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS))); + cur = my_stat(*argv, *argv, + /* follow links on command line unless -l, -s or -F: */ + !((G.all_fmt & STYLE_MASK) == STYLE_LONG + || (G.all_fmt & LIST_BLOCKS) + || (option_mask32 & OPT_F) + ) + /* ... or if -H: */ + || (option_mask32 & OPT_H) + /* ... or if -L, but my_stat always follows links if -L */ + ); argv++; if (!cur) continue; - cur->fname_allocated = 0; - cur->next = dn; + /*cur->fname_allocated = 0; - already is */ + cur->dn_next = dn; dn = cur; nfiles++; } while (*argv); /* nfiles _may_ be 0 here - try "ls doesnt_exist" */ if (nfiles == 0) - return exit_code; + return G.exit_code; /* now that we know how many files there are * allocate memory for an array to hold dnode pointers @@ -1090,33 +1224,32 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dnp = dnalloc(nfiles); for (i = 0; /* i < nfiles - detected via !dn below */; i++) { dnp[i] = dn; /* save pointer to node in array */ - dn = dn->next; + dn = dn->dn_next; if (!dn) break; } - if (all_fmt & DISP_NOLIST) { - dnsort(dnp, nfiles); - showfiles(dnp, nfiles); + if (G.all_fmt & DISP_NOLIST) { + sort_and_display_files(dnp, nfiles); } else { dnd = splitdnarray(dnp, SPLIT_DIR); dnf = splitdnarray(dnp, SPLIT_FILE); dndirs = count_dirs(dnp, SPLIT_DIR); dnfiles = nfiles - dndirs; if (dnfiles > 0) { - dnsort(dnf, dnfiles); - showfiles(dnf, dnfiles); + sort_and_display_files(dnf, dnfiles); if (ENABLE_FEATURE_CLEAN_UP) free(dnf); } if (dndirs > 0) { dnsort(dnd, dndirs); - showdirs(dnd, dnfiles == 0); + scan_and_display_dirs_recur(dnd, dnfiles == 0); if (ENABLE_FEATURE_CLEAN_UP) free(dnd); } } + if (ENABLE_FEATURE_CLEAN_UP) dfree(dnp); - return exit_code; + return G.exit_code; } diff --git a/release/src/router/busybox/coreutils/md5_sha1_sum.c b/release/src/router/busybox/coreutils/md5_sha1_sum.c index 3b897c18f7..2cb6dd43c1 100644 --- a/release/src/router/busybox/coreutils/md5_sha1_sum.c +++ b/release/src/router/busybox/coreutils/md5_sha1_sum.c @@ -6,6 +6,56 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define md5sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define md5sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define md5sum_example_usage +//usage: "$ md5sum < busybox\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003\n" +//usage: "$ md5sum busybox\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" +//usage: "$ md5sum -c -\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" +//usage: "busybox: OK\n" +//usage: "^D\n" +//usage: +//usage:#define sha1sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha1sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define sha256sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha256sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define sha512sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha512sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -41,8 +91,7 @@ static uint8_t *hash_file(const char *filename) sha1_ctx_t sha1; md5_ctx_t md5; } context; - uint8_t *hash_value = NULL; - RESERVE_CONFIG_UBUFFER(in_buf, 4096); + uint8_t *hash_value; void FAST_FUNC (*update)(void*, const void*, size_t); void FAST_FUNC (*final)(void*, void*); char hash_algo; @@ -54,7 +103,7 @@ static uint8_t *hash_file(const char *filename) hash_algo = applet_name[3]; - /* figure specific hash algorithims */ + /* figure specific hash algorithms */ if (ENABLE_MD5SUM && hash_algo == HASH_MD5) { md5_begin(&context.md5); update = (void*)md5_hash; @@ -79,17 +128,19 @@ static uint8_t *hash_file(const char *filename) xfunc_die(); /* can't reach this */ } - while ((count = safe_read(src_fd, in_buf, 4096)) > 0) { - update(&context, in_buf, count); - } - - if (count == 0) { - final(&context, in_buf); - hash_value = hash_bin_to_hex(in_buf, hash_len); + { + RESERVE_CONFIG_UBUFFER(in_buf, 4096); + while ((count = safe_read(src_fd, in_buf, 4096)) > 0) { + update(&context, in_buf, count); + } + hash_value = NULL; + if (count == 0) { + final(&context, in_buf); + hash_value = hash_bin_to_hex(in_buf, hash_len); + } + RELEASE_CONFIG_BUFFER(in_buf); } - RELEASE_CONFIG_BUFFER(in_buf); - if (src_fd != STDIN_FILENO) { close(src_fd); } @@ -124,66 +175,58 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) } } - if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { - FILE *pre_computed_stream; - int count_total = 0; - int count_failed = 0; - char *line; + do { + if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { + FILE *pre_computed_stream; + char *line; + int count_total = 0; + int count_failed = 0; - if (argv[1]) { - bb_error_msg_and_die("only one argument may be specified with -c"); - } - - pre_computed_stream = xfopen_stdin(argv[0]); + pre_computed_stream = xfopen_stdin(*argv); - while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { - uint8_t *hash_value; - char *filename_ptr; + while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { + uint8_t *hash_value; + 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_total++; + filename_ptr = strstr(line, " "); + /* handle format for binary checksums */ + if (filename_ptr == NULL) { + filename_ptr = strstr(line, " *"); } - count_failed++; - return_value = EXIT_FAILURE; + 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); + + 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); - continue; } - *filename_ptr = '\0'; - filename_ptr += 2; - - hash_value = hash_file(filename_ptr); - - 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; + if (count_failed && !(flags & FLAG_SILENT)) { + bb_error_msg("WARNING: %d of %d computed checksums did NOT match", + count_failed, count_total); } - /* 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("can't close file %s", file_ptr); - } - */ - } else { - do { + fclose_if_not_stdin(pre_computed_stream); + } else { uint8_t *hash_value = hash_file(*argv); if (hash_value == NULL) { return_value = EXIT_FAILURE; @@ -191,7 +234,8 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) printf("%s %s\n", hash_value, *argv); free(hash_value); } - } while (*++argv); - } + } + } while (*++argv); + return return_value; } diff --git a/release/src/router/busybox/coreutils/mkdir.c b/release/src/router/busybox/coreutils/mkdir.c index 0de0d5c3b1..b33b6bba3b 100644 --- a/release/src/router/busybox/coreutils/mkdir.c +++ b/release/src/router/busybox/coreutils/mkdir.c @@ -19,6 +19,24 @@ /* Nov 28, 2006 Yoshinori Sato : Add SELinux Support. */ +//usage:#define mkdir_trivial_usage +//usage: "[OPTIONS] DIRECTORY..." +//usage:#define mkdir_full_usage "\n\n" +//usage: "Create DIRECTORY\n" +//usage: "\n -m MODE Mode" +//usage: "\n -p No error if exists; make parent directories as needed" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) +//usage: +//usage:#define mkdir_example_usage +//usage: "$ mkdir /tmp/foo\n" +//usage: "$ mkdir /tmp/foo\n" +//usage: "/tmp/foo: File exists\n" +//usage: "$ mkdir /tmp/foo/bar/baz\n" +//usage: "/tmp/foo/bar/baz: No such file or directory\n" +//usage: "$ mkdir -p /tmp/foo/bar/baz\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ @@ -36,7 +54,7 @@ static const char mkdir_longopts[] ALIGN1 = int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mkdir_main(int argc UNUSED_PARAM, char **argv) { - mode_t mode = (mode_t)(-1); + long mode = -1; int status = EXIT_SUCCESS; int flags = 0; unsigned opt; @@ -50,10 +68,11 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { - mode = 0777; - if (!bb_parse_mode(smode, &mode)) { + mode_t mmode = 0777; + if (!bb_parse_mode(smode, &mmode)) { bb_error_msg_and_die("invalid mode '%s'", smode); } + mode = mmode; } if (opt & 2) flags |= FILEUTILS_RECUR; diff --git a/release/src/router/busybox/coreutils/mkfifo.c b/release/src/router/busybox/coreutils/mkfifo.c index d908ce45e4..ef58325b36 100644 --- a/release/src/router/busybox/coreutils/mkfifo.c +++ b/release/src/router/busybox/coreutils/mkfifo.c @@ -10,6 +10,15 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/mkfifo.html */ +//usage:#define mkfifo_trivial_usage +//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME" +//usage:#define mkfifo_full_usage "\n\n" +//usage: "Create named pipe\n" +//usage: "\n -m MODE Mode (default a=rw)" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) + #include "libbb.h" #include "libcoreutils/coreutils.h" diff --git a/release/src/router/busybox/coreutils/mknod.c b/release/src/router/busybox/coreutils/mknod.c index 14d91b5df8..32d3659acc 100644 --- a/release/src/router/busybox/coreutils/mknod.c +++ b/release/src/router/busybox/coreutils/mknod.c @@ -9,6 +9,23 @@ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//usage:#define mknod_trivial_usage +//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE MAJOR MINOR" +//usage:#define mknod_full_usage "\n\n" +//usage: "Create a special file (block, character, or pipe)\n" +//usage: "\n -m MODE Creation mode (default a=rw)" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) +//usage: "\nTYPE:" +//usage: "\n b Block device" +//usage: "\n c or u Character device" +//usage: "\n p Named pipe (MAJOR and MINOR are ignored)" +//usage: +//usage:#define mknod_example_usage +//usage: "$ mknod /dev/fd0 b 2 0\n" +//usage: "$ mknod -m 644 /tmp/pipe p\n" + #include // For makedev #include "libbb.h" diff --git a/release/src/router/busybox/coreutils/mv.c b/release/src/router/busybox/coreutils/mv.c index 399f391b26..87f4cd5a54 100644 --- a/release/src/router/busybox/coreutils/mv.c +++ b/release/src/router/busybox/coreutils/mv.c @@ -21,7 +21,6 @@ //usage: "or: mv [-fin] SOURCE... DIRECTORY" //usage:#define mv_full_usage "\n\n" //usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" -//usage: "\nOptions:" //usage: "\n -f Don't prompt before overwriting" //usage: "\n -i Interactive, prompt before overwrite" //usage: "\n -n Don't overwrite an existing file" diff --git a/release/src/router/busybox/coreutils/nice.c b/release/src/router/busybox/coreutils/nice.c index 35d6bf3d99..ce759916fa 100644 --- a/release/src/router/busybox/coreutils/nice.c +++ b/release/src/router/busybox/coreutils/nice.c @@ -7,6 +7,12 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define nice_trivial_usage +//usage: "[-n ADJUST] [PROG ARGS]" +//usage:#define nice_full_usage "\n\n" +//usage: "Change scheduling priority, run PROG\n" +//usage: "\n -n ADJUST Adjust priority by ADJUST" + #include #include "libbb.h" diff --git a/release/src/router/busybox/coreutils/nohup.c b/release/src/router/busybox/coreutils/nohup.c index c21aae9f58..63853fd550 100644 --- a/release/src/router/busybox/coreutils/nohup.c +++ b/release/src/router/busybox/coreutils/nohup.c @@ -10,6 +10,14 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define nohup_trivial_usage +//usage: "PROG ARGS" +//usage:#define nohup_full_usage "\n\n" +//usage: "Run PROG immune to hangups, with output to a non-tty" +//usage: +//usage:#define nohup_example_usage +//usage: "$ nohup make &" + #include "libbb.h" /* Compat info: nohup (GNU coreutils 6.8) does this: diff --git a/release/src/router/busybox/coreutils/od.c b/release/src/router/busybox/coreutils/od.c index e62711671c..fb11fcfe32 100644 --- a/release/src/router/busybox/coreutils/od.c +++ b/release/src/router/busybox/coreutils/od.c @@ -11,6 +11,12 @@ * Original copyright notice is retained at the end of this file. */ +//usage:#if !ENABLE_DESKTOP +//usage:#define od_trivial_usage +//usage: "[-aBbcDdeFfHhIiLlOovXx] [FILE]" +//usage:#define od_full_usage "\n\n" +//usage: "Print FILE (or stdin) unambiguously, as octal bytes by default" +//usage:#endif #include "libbb.h" #if ENABLE_DESKTOP diff --git a/release/src/router/busybox/coreutils/od_bloaty.c b/release/src/router/busybox/coreutils/od_bloaty.c index a9a45c8d3a..347f879d70 100644 --- a/release/src/router/busybox/coreutils/od_bloaty.c +++ b/release/src/router/busybox/coreutils/od_bloaty.c @@ -13,48 +13,64 @@ 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. */ - + 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 */ -/* 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. +/* #include "libbb.h" - done in od.c */ +#define assert(a) ((void)0) -#!/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; } -*/ +//usage:#if ENABLE_DESKTOP +//usage:#define od_trivial_usage +//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE...]" +// We don't support: +// ... [FILE] [[+]OFFSET[.][b]] +// Support is buggy for: +// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]] + +//usage:#define od_full_usage "\n\n" +//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default" +//usage:#endif + +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, + /* 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: */ + 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_LONG_OPTS, +}; -#include "libbb.h" +#define OD_GETOPT32() 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) -#define assert(a) ((void)0) /* Check for 0x7f is a coreutils 6.3 addition */ -#define ISPRINT(c) (((c)>=' ') && (c) != 0x7f) +#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f) typedef long double longdouble_t; typedef unsigned long long ulonglong_t; @@ -158,17 +174,9 @@ 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 smallint exit_code; -static size_t string_min; +static unsigned string_min; /* An array of specs describing how to format each input block. */ static size_t n_specs; @@ -179,7 +187,11 @@ static struct tspec *spec; static void (*format_address)(off_t, char); /* The difference between the old-style pseudo starting address and the number of bytes to skip. */ +#if ENABLE_LONG_OPTS static off_t pseudo_offset; +#else +enum { pseudo_offset = 0 }; +#endif /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all input is formatted. */ @@ -214,7 +226,7 @@ static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 #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 */ + /* gcc seems to allow repeated indexes. Last one wins */ [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE, [sizeof(double)] = FLOAT_DOUBLE, [sizeof(float)] = FLOAT_SINGLE @@ -376,7 +388,7 @@ print_named_ascii(size_t n_bytes, const char *block, }; // 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. + // actually " x\0 xxx\0", but want to share string with print_ascii. // [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. @@ -472,10 +484,10 @@ open_next_file(void) if (in_stream) { break; } - ioerror = 1; + exit_code = 1; } - if (limit_bytes_to_format && !flag_dump_strings) + if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N) setbuf(in_stream, NULL); } @@ -495,15 +507,14 @@ check_and_close(void) ? bb_msg_standard_input : file_list[-1] ); - ioerror = 1; + exit_code = 1; } fclose_if_not_stdin(in_stream); in_stream = NULL; } if (ferror(stdout)) { - bb_error_msg(bb_msg_write_error); - ioerror = 1; + bb_error_msg_and_die(bb_msg_write_error); } } @@ -535,7 +546,6 @@ decode_one_format(const char *s_orig, const char *s, struct tspec *tspec) unsigned field_width = 0; int pos; - switch (*s) { case 'd': case 'o': @@ -781,7 +791,7 @@ skip(off_t n_skip) /* take "check & close / open_next" route */ } else { if (fseeko(in_stream, n_skip, SEEK_CUR) != 0) - ioerror = 1; + exit_code = 1; return; } } else { @@ -882,7 +892,8 @@ write_block(off_t current_offset, size_t n_bytes, static char prev_pair_equal = 0; size_t i; - if (!verbose && !first + if (!(option_mask32 & OPT_v) + && !first && n_bytes == bytes_per_block && memcmp(prev_block, curr_block, bytes_per_block) == 0 ) { @@ -904,9 +915,9 @@ write_block(off_t current_offset, size_t n_bytes, (*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; + unsigned datum_width = width_bytes[spec[i].size]; + unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width; + unsigned field_width = spec[i].field_width + 1; printf("%*s", blank_fields * field_width, ""); dump_hexl_mode_trailer(n_bytes, curr_block); } @@ -954,42 +965,6 @@ get_lcm(void) return l_c_m; } -#if ENABLE_LONG_OPTS -/* 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 }, - { "", 0 } - }; - 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 @@ -1007,27 +982,25 @@ dump(off_t current_offset, off_t end_offset) int idx; size_t n_bytes_read; - block[0] = xmalloc(2*bytes_per_block); + block[0] = xmalloc(2 * bytes_per_block); block[1] = block[0] + bytes_per_block; idx = 0; - if (limit_bytes_to_format) { + if (option_mask32 & OPT_N) { 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); + 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]); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); current_offset += n_bytes_read; - idx = !idx; + idx ^= 1; } } else { while (1) { @@ -1035,10 +1008,9 @@ dump(off_t current_offset, off_t end_offset) 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]); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); current_offset += n_bytes_read; - idx = !idx; + idx ^= 1; } } @@ -1054,41 +1026,18 @@ dump(off_t current_offset, off_t end_offset) memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read); write_block(current_offset, bytes_to_write, - block[!idx], block[idx]); + block[idx ^ 1], block[idx]); current_offset += n_bytes_read; } format_address(current_offset, '\n'); - if (limit_bytes_to_format && current_offset >= end_offset) + if ((option_mask32 & OPT_N) && 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 @@ -1112,8 +1061,8 @@ read_char(int *c) static void dump_strings(off_t address, off_t end_offset) { - size_t bufsize = MAX(100, string_min); - char *buf = xmalloc(bufsize); + unsigned bufsize = MAX(100, string_min); + unsigned char *buf = xmalloc(bufsize); while (1) { size_t i; @@ -1121,19 +1070,25 @@ dump_strings(off_t address, off_t end_offset) /* See if the next 'string_min' chars are all printing chars. */ tryline: - if (limit_bytes_to_format && (end_offset - string_min <= address)) + if ((option_mask32 & OPT_N) && (end_offset - string_min <= address)) break; i = 0; - while (!limit_bytes_to_format || address < end_offset) { + while (!(option_mask32 & OPT_N) || address < end_offset) { if (i == bufsize) { bufsize += bufsize/8; buf = xrealloc(buf, bufsize); } - read_char(&c); - if (c < 0) { /* EOF */ - free(buf); - return; + + while (in_stream) { /* !EOF */ + c = fgetc(in_stream); + if (c != EOF) + goto got_char; + check_and_close(); + open_next_file(); } + /* EOF */ + goto ret; + got_char: address++; if (!c) break; @@ -1145,8 +1100,7 @@ dump_strings(off_t address, off_t end_offset) 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. */ + /* If we get here, the string is all printable and NUL-terminated */ buf[i] = 0; format_address(address - i - 1, ' '); @@ -1167,13 +1121,50 @@ dump_strings(off_t address, off_t end_offset) /* We reach this point only if we search through (max_bytes_to_format - string_min) bytes before reaching EOF. */ + check_and_close(); + ret: free(buf); +} - check_and_close(); +#if ENABLE_LONG_OPTS +/* 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 }, + { "", 0 } + }; + char *p; + int radix; + + /* Skip over any leading '+'. */ + if (s[0] == '+') ++s; + if (!isdigit(s[0])) return 0; /* not a number */ + + /* 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 int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int od_main(int argc, char **argv) +int od_main(int argc UNUSED_PARAM, char **argv) { static const struct suffix_mult bkm[] = { { "b", 512 }, @@ -1181,27 +1172,6 @@ int od_main(int argc, char **argv) { "m", 1024*1024 }, { "", 0 } }; - 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_LONG_OPTS, - }; #if ENABLE_LONG_OPTS static const char od_longopts[] ALIGN1 = "skip-bytes\0" Required_argument "j" @@ -1209,18 +1179,18 @@ int od_main(int argc, char **argv) "read-bytes\0" Required_argument "N" "format\0" Required_argument "t" "output-duplicates\0" No_argument "v" + /* Yes, it's true: -S NUM, but --strings[=NUM]! + * that is, NUM is mandatory for -S but optional for --strings! + */ "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; + const char *str_A, *str_N, *str_j, *str_S = "3"; 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. */ @@ -1232,20 +1202,13 @@ int od_main(int argc, char **argv) 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_LONG_OPTS 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; + opt = OD_GETOPT32(); argv += optind; if (opt & OPT_A) { static const char doxn[] ALIGN1 = "doxn"; @@ -1267,7 +1230,6 @@ int od_main(int argc, char **argv) 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"); @@ -1280,28 +1242,23 @@ int od_main(int argc, char **argv) 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"); + // Bloat: + //if ((option_mask32 & OPT_S) && 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]]] + * 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 @@ -1309,93 +1266,91 @@ int od_main(int argc, char **argv) #if ENABLE_LONG_OPTS 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"); + if (argv[0]) { + off_t pseudo_start = -1; + off_t o1, o2; + + if (!argv[1]) { /* one arg */ + if (parse_old_offset(argv[0], &o1)) { + /* od --traditional OFFSET */ + n_bytes_to_skip = o1; + argv++; + } + /* od --traditional FILE */ + } else if (!argv[2]) { /* two args */ + if (parse_old_offset(argv[0], &o1) + && parse_old_offset(argv[1], &o2) + ) { + /* od --traditional OFFSET LABEL */ + n_bytes_to_skip = o1; + pseudo_start = o2; + argv += 2; + } else if (parse_old_offset(argv[1], &o2)) { + /* od --traditional FILE OFFSET */ + n_bytes_to_skip = o2; + argv[1] = NULL; + } else { + bb_error_msg_and_die("invalid second argument '%s'", argv[1]); + } + } else if (!argv[3]) { /* three args */ + if (parse_old_offset(argv[1], &o1) + && parse_old_offset(argv[2], &o2) + ) { + /* od --traditional FILE OFFSET LABEL */ + n_bytes_to_skip = o1; + pseudo_start = o2; + argv[1] = NULL; + } else { + bb_error_msg_and_die("the last two arguments must be offsets"); + } + } else { /* >3 args */ + bb_error_msg_and_die("too many arguments"); } - } 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; + if (pseudo_start >= 0) { + 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; + } + pseudo_offset = pseudo_start - n_bytes_to_skip; + } } + /* else: od --traditional (without args) */ } #endif - if (limit_bytes_to_format) { + if (option_mask32 & OPT_N) { 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"); + bb_error_msg_and_die("SKIP + SIZE is too large"); } if (n_specs == 0) { decode_format_string("o2"); - n_specs = 1; + /*n_specs = 1; - done by decode_format_string */ } /* 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) { + if (argv[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 the first input file */ open_next_file(); - /* skip over any unwanted header bytes */ + /* 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. */ + /* Compute output block length */ l_c_m = get_lcm(); if (opt & OPT_w) { /* -w: width */ @@ -1417,13 +1372,13 @@ int od_main(int argc, char **argv) } #endif - if (flag_dump_strings) + if (option_mask32 & OPT_S) dump_strings(n_bytes_to_skip, end_offset); else dump(n_bytes_to_skip, end_offset); - if (fclose(stdin) == EOF) + if (fclose(stdin)) bb_perror_msg_and_die(bb_msg_standard_input); - return ioerror; + return exit_code; } diff --git a/release/src/router/busybox/coreutils/printenv.c b/release/src/router/busybox/coreutils/printenv.c index d0fb71636d..bd5db7073a 100644 --- a/release/src/router/busybox/coreutils/printenv.c +++ b/release/src/router/busybox/coreutils/printenv.c @@ -8,6 +8,12 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define printenv_trivial_usage +//usage: "[VARIABLE]..." +//usage:#define printenv_full_usage "\n\n" +//usage: "Print environment VARIABLEs.\n" +//usage: "If no VARIABLE specified, print all." + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/printf.c b/release/src/router/busybox/coreutils/printf.c index c8395fa899..3dd43a9782 100644 --- a/release/src/router/busybox/coreutils/printf.c +++ b/release/src/router/busybox/coreutils/printf.c @@ -36,7 +36,16 @@ David MacKenzie */ -// 19990508 Busy Boxed! Dave Cinege +/* 19990508 Busy Boxed! Dave Cinege */ + +//usage:#define printf_trivial_usage +//usage: "FORMAT [ARG]..." +//usage:#define printf_full_usage "\n\n" +//usage: "Format and print ARG(s) according to FORMAT (a-la C printf)" +//usage: +//usage:#define printf_example_usage +//usage: "$ printf \"Val=%d\\n\" 5\n" +//usage: "Val=5\n" #include "libbb.h" @@ -122,13 +131,28 @@ static double my_xstrtod(const char *arg) return result; } +/* Handles %b */ static void print_esc_string(const char *str) { char c; while ((c = *str) != '\0') { str++; - if (c == '\\') - c = bb_process_escape_sequence(&str); + if (c == '\\') { + /* %b also accepts 4-digit octals of the form \0### */ + if (*str == '0') { + if ((unsigned char)(str[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + str++; + } + } + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. */ + const char *z = str; + c = bb_process_escape_sequence(&z); + str = z; + } + } putchar(c); } } diff --git a/release/src/router/busybox/coreutils/pwd.c b/release/src/router/busybox/coreutils/pwd.c index 2949c55c24..bb3ad04fc0 100644 --- a/release/src/router/busybox/coreutils/pwd.c +++ b/release/src/router/busybox/coreutils/pwd.c @@ -7,17 +7,76 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define pwd_trivial_usage +//usage: "" +//usage:#define pwd_full_usage "\n\n" +//usage: "Print the full filename of the current working directory" +//usage: +//usage:#define pwd_example_usage +//usage: "$ pwd\n" +//usage: "/root\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ +static int logical_getcwd(void) +{ + struct stat st1; + struct stat st2; + char *wd; + char *p; + + wd = getenv("PWD"); + if (!wd || wd[0] != '/') + return 0; + + p = wd; + while (*p) { + /* doing strstr(p, "/.") by hand is smaller and faster... */ + if (*p++ != '/') + continue; + if (*p != '.') + continue; + /* we found "/.", skip to next char */ + p++; + if (*p == '.') + p++; /* we found "/.." */ + if (*p == '\0' || *p == '/') + return 0; /* "/./" or "/../" component: bad */ + } + + if (stat(wd, &st1) != 0) + return 0; + if (stat(".", &st2) != 0) + return 0; + if (st1.st_ino != st2.st_ino) + return 0; + if (st1.st_dev != st2.st_dev) + return 0; + + puts(wd); + return 1; +} + int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int pwd_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { char *buf; + if (ENABLE_DESKTOP) { + /* TODO: assume -L if $POSIXLY_CORRECT? (coreutils does that) + * Rationale: + * POSIX requires a default of -L, but most scripts expect -P + */ + unsigned opt = getopt32(argv, "LP"); + if ((opt & 1) && logical_getcwd()) + return fflush_all(); + } + buf = xrealloc_getcwd_or_warn(NULL); - if (buf != NULL) { + + if (buf) { puts(buf); free(buf); return fflush_all(); diff --git a/release/src/router/busybox/coreutils/readlink.c b/release/src/router/busybox/coreutils/readlink.c index 87602fbc69..f7ad791ec8 100644 --- a/release/src/router/busybox/coreutils/readlink.c +++ b/release/src/router/busybox/coreutils/readlink.c @@ -6,6 +6,17 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define readlink_trivial_usage +//usage: IF_FEATURE_READLINK_FOLLOW("[-fnv] ") "FILE" +//usage:#define readlink_full_usage "\n\n" +//usage: "Display the value of a symlink" +//usage: IF_FEATURE_READLINK_FOLLOW( "\n" +//usage: "\n -f Canonicalize by following all symlinks" +//usage: "\n -n Don't add newline" +//usage: "\n -v Verbose" +//usage: ) + #include "libbb.h" /* diff --git a/release/src/router/busybox/coreutils/realpath.c b/release/src/router/busybox/coreutils/realpath.c index 5933062b8a..c513b55495 100644 --- a/release/src/router/busybox/coreutils/realpath.c +++ b/release/src/router/busybox/coreutils/realpath.c @@ -10,6 +10,11 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define realpath_trivial_usage +//usage: "FILE..." +//usage:#define realpath_full_usage "\n\n" +//usage: "Return the absolute pathnames of given FILE" + #include "libbb.h" int realpath_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/coreutils/rm.c b/release/src/router/busybox/coreutils/rm.c index 69c473ddbf..042fba1623 100644 --- a/release/src/router/busybox/coreutils/rm.c +++ b/release/src/router/busybox/coreutils/rm.c @@ -15,6 +15,17 @@ * Size reduction. */ +//usage:#define rm_trivial_usage +//usage: "[-irf] FILE..." +//usage:#define rm_full_usage "\n\n" +//usage: "Remove (unlink) FILEs\n" +//usage: "\n -i Always prompt before removing" +//usage: "\n -f Never prompt" +//usage: "\n -R,-r Recurse" +//usage: +//usage:#define rm_example_usage +//usage: "$ rm -rf /tmp/foo\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/rmdir.c b/release/src/router/busybox/coreutils/rmdir.c index 231793ce0e..2840d1cfaa 100644 --- a/release/src/router/busybox/coreutils/rmdir.c +++ b/release/src/router/busybox/coreutils/rmdir.c @@ -10,6 +10,21 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */ +//usage:#define rmdir_trivial_usage +//usage: "[OPTIONS] DIRECTORY..." +//usage:#define rmdir_full_usage "\n\n" +//usage: "Remove DIRECTORY if it is empty\n" +//usage: IF_FEATURE_RMDIR_LONG_OPTIONS( +//usage: "\n -p|--parents Include parents" +//usage: "\n --ignore-fail-on-non-empty" +//usage: ) +//usage: IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( +//usage: "\n -p Include parents" +//usage: ) +//usage: +//usage:#define rmdir_example_usage +//usage: "# rmdir /tmp/foo\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/seq.c b/release/src/router/busybox/coreutils/seq.c index 22bf3ec9de..8986192930 100644 --- a/release/src/router/busybox/coreutils/seq.c +++ b/release/src/router/busybox/coreutils/seq.c @@ -6,6 +6,15 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define seq_trivial_usage +//usage: "[-w] [-s SEP] [FIRST [INC]] LAST" +//usage:#define seq_full_usage "\n\n" +//usage: "Print numbers from FIRST to LAST, in steps of INC.\n" +//usage: "FIRST, INC default to 1.\n" +//usage: "\n -w Pad to last with leading zeros" +//usage: "\n -s SEP String separator" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/sleep.c b/release/src/router/busybox/coreutils/sleep.c index 433f9d6eec..0ffbd16eb7 100644 --- a/release/src/router/busybox/coreutils/sleep.c +++ b/release/src/router/busybox/coreutils/sleep.c @@ -18,6 +18,21 @@ * time suffixes for seconds, minutes, hours, and days. */ +//usage:#define sleep_trivial_usage +//usage: IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...") +//usage:#define sleep_full_usage "\n\n" +//usage: IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds") +//usage: IF_FEATURE_FANCY_SLEEP( +//usage: "Pause for a time equal to the total of the args given, where each arg can\n" +//usage: "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays") +//usage: +//usage:#define sleep_example_usage +//usage: "$ sleep 2\n" +//usage: "[2 second delay results]\n" +//usage: IF_FEATURE_FANCY_SLEEP( +//usage: "$ sleep 1d 3h 22m 8s\n" +//usage: "[98528 second delay results]\n") + #include "libbb.h" /* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ diff --git a/release/src/router/busybox/coreutils/sort.c b/release/src/router/busybox/coreutils/sort.c index 3562464d16..1df07285c7 100644 --- a/release/src/router/busybox/coreutils/sort.c +++ b/release/src/router/busybox/coreutils/sort.c @@ -12,6 +12,53 @@ * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html */ +//usage:#define sort_trivial_usage +//usage: "[-nru" +//usage: IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") +//usage: "] [FILE]..." +//usage:#define sort_full_usage "\n\n" +//usage: "Sort lines of text\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -b Ignore leading blanks" +//usage: "\n -c Check whether input is sorted" +//usage: "\n -d Dictionary order (blank or alphanumeric only)" +//usage: "\n -f Ignore case" +//usage: "\n -g General numerical sort" +//usage: "\n -i Ignore unprintable characters" +//usage: "\n -k Sort key" +//usage: "\n -M Sort month" +//usage: ) +//usage: "\n -n Sort numbers" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -o Output to file" +//usage: "\n -k Sort by key" +//usage: "\n -t CHAR Key separator" +//usage: ) +//usage: "\n -r Reverse sort order" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -s Stable (don't sort ties alphabetically)" +//usage: ) +//usage: "\n -u Suppress duplicate lines" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -z Lines are terminated by NUL, not newline" +//usage: "\n -mST Ignored for GNU compatibility") +//usage: +//usage:#define sort_example_usage +//usage: "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" +//usage: "d\n" +//usage: "e\n" +//usage: "f\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" +//usage: "d 2\n" +//usage: "b 2\n" +//usage: "c 3\n" +//usage: ) +//usage: "" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/split.c b/release/src/router/busybox/coreutils/split.c index db5a1727a5..11e6404425 100644 --- a/release/src/router/busybox/coreutils/split.c +++ b/release/src/router/busybox/coreutils/split.c @@ -9,6 +9,18 @@ * SUSv3 requirements: * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html */ + +//usage:#define split_trivial_usage +//usage: "[OPTIONS] [INPUT [PREFIX]]" +//usage:#define split_full_usage "\n\n" +//usage: " -b N[k|m] Split by N (kilo|mega)bytes" +//usage: "\n -l N Split by N lines" +//usage: "\n -a N Use N letters as suffix" +//usage: +//usage:#define split_example_usage +//usage: "$ split TODO foo\n" +//usage: "$ cat TODO | split -a 2 -l 2 TODO_\n" + #include "libbb.h" static const struct suffix_mult split_suffices[] = { @@ -32,7 +44,7 @@ static char *next_file(char *old, unsigned suffix_len) unsigned i = 1; char *curr; - do { + while (1) { curr = old + end - i; if (*curr < 'z') { *curr += 1; @@ -43,7 +55,7 @@ static char *next_file(char *old, unsigned suffix_len) return NULL; } *curr = 'a'; - } while (1); + } return old; } diff --git a/release/src/router/busybox/coreutils/stat.c b/release/src/router/busybox/coreutils/stat.c index 7351f59563..2797719dd1 100644 --- a/release/src/router/busybox/coreutils/stat.c +++ b/release/src/router/busybox/coreutils/stat.c @@ -12,6 +12,66 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define stat_trivial_usage +//usage: "[OPTIONS] FILE..." +//usage:#define stat_full_usage "\n\n" +//usage: "Display file (default) or filesystem status\n" +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n -c fmt Use the specified format" +//usage: ) +//usage: "\n -f Display filesystem status" +//usage: "\n -L Follow links" +//usage: "\n -t Display info in terse form" +//usage: IF_SELINUX( +//usage: "\n -Z Print security context" +//usage: ) +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n\nValid format sequences for files:\n" +//usage: " %a Access rights in octal\n" +//usage: " %A Access rights in human readable form\n" +//usage: " %b Number of blocks allocated (see %B)\n" +//usage: " %B The size in bytes of each block reported by %b\n" +//usage: " %d Device number in decimal\n" +//usage: " %D Device number in hex\n" +//usage: " %f Raw mode in hex\n" +//usage: " %F File type\n" +//usage: " %g Group ID of owner\n" +//usage: " %G Group name of owner\n" +//usage: " %h Number of hard links\n" +//usage: " %i Inode number\n" +//usage: " %n File name\n" +//usage: " %N File name, with -> TARGET if symlink\n" +//usage: " %o I/O block size\n" +//usage: " %s Total size, in bytes\n" +//usage: " %t Major device type in hex\n" +//usage: " %T Minor device type in hex\n" +//usage: " %u User ID of owner\n" +//usage: " %U User name of owner\n" +//usage: " %x Time of last access\n" +//usage: " %X Time of last access as seconds since Epoch\n" +//usage: " %y Time of last modification\n" +//usage: " %Y Time of last modification as seconds since Epoch\n" +//usage: " %z Time of last change\n" +//usage: " %Z Time of last change as seconds since Epoch\n" +//usage: "\nValid format sequences for file systems:\n" +//usage: " %a Free blocks available to non-superuser\n" +//usage: " %b Total data blocks in file system\n" +//usage: " %c Total file nodes in file system\n" +//usage: " %d Free file nodes in file system\n" +//usage: " %f Free blocks in file system\n" +//usage: IF_SELINUX( +//usage: " %C Security context in selinux\n" +//usage: ) +//usage: " %i File System ID in hex\n" +//usage: " %l Maximum length of filenames\n" +//usage: " %n File name\n" +//usage: " %s Block size (for faster transfer)\n" +//usage: " %S Fundamental block size (for block counts)\n" +//usage: " %t Type in hex\n" +//usage: " %T Type in human readable form" +//usage: ) + #include "libbb.h" #define OPT_FILESYS (1 << 0) diff --git a/release/src/router/busybox/coreutils/stty.c b/release/src/router/busybox/coreutils/stty.c index e28e15c979..0668cf7be5 100644 --- a/release/src/router/busybox/coreutils/stty.c +++ b/release/src/router/busybox/coreutils/stty.c @@ -21,6 +21,16 @@ */ +//usage:#define stty_trivial_usage +//usage: "[-a|g] [-F DEVICE] [SETTING]..." +//usage:#define stty_full_usage "\n\n" +//usage: "Without arguments, prints baud rate, line discipline,\n" +//usage: "and deviations from stty sane\n" +//usage: "\n -F DEVICE Open device instead of stdin" +//usage: "\n -a Print all current settings in human-readable form" +//usage: "\n -g Print in stty-readable form" +//usage: "\n [SETTING] See manpage" + #include "libbb.h" #ifndef _POSIX_VDISABLE @@ -59,6 +69,10 @@ #if defined(VEOL2) && !defined(CEOL2) # define CEOL2 _POSIX_VDISABLE #endif +/* glibc-2.12.1 uses only VSWTC name */ +#if defined(VSWTC) && !defined(VSWTCH) +# define VSWTCH VSWTC +#endif /* ISC renamed swtch to susp for termios, but we'll accept either name */ #if defined(VSUSP) && !defined(VSWTCH) # define VSWTCH VSUSP @@ -221,6 +235,9 @@ #ifndef XCASE # define XCASE 0 #endif +#ifndef IUTF8 +# define IUTF8 0 +#endif /* Which speeds to set */ enum speed_setting { @@ -338,7 +355,7 @@ static const char mode_name[] = 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 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif @@ -348,6 +365,9 @@ static const char mode_name[] = #if IMAXBEL MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) #endif +#if IUTF8 + MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) +#endif MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) #if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) @@ -415,7 +435,7 @@ static const char mode_name[] = #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("crterase", local, OMIT | REV, 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 ) @@ -427,15 +447,15 @@ static const char mode_name[] = #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif ; @@ -492,7 +512,7 @@ static const struct mode_info mode_info[] = { 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 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif @@ -502,6 +522,9 @@ static const struct mode_info mode_info[] = { #if IMAXBEL MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) #endif +#if IUTF8 + MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) +#endif MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) #if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) @@ -569,7 +592,7 @@ static const struct mode_info mode_info[] = { #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("crterase", local, OMIT | REV, 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 ) @@ -581,15 +604,15 @@ static const struct mode_info mode_info[] = { #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif }; @@ -991,8 +1014,9 @@ static void display_speed(const struct termios *mode, int fancy) 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 = cfgetispeed(mode); + ospeed = cfgetospeed(mode); + if (ispeed == 0 || ispeed == ospeed) { 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;"; @@ -1011,7 +1035,7 @@ static void do_display(const struct termios *mode, int all) display_speed(mode, 1); if (all) display_window_size(1); -#ifdef HAVE_C_LINE +#ifdef __linux__ wrapf("line = %u;\n", mode->c_line); #else newline(); @@ -1344,7 +1368,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) } switch (param) { -#ifdef HAVE_C_LINE +#ifdef __linux__ case param_line: # ifndef TIOCGWINSZ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); @@ -1380,13 +1404,15 @@ int stty_main(int argc UNUSED_PARAM, char **argv) /* 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"); + (STTY_verbose_output | STTY_recoverable_output) + ) { + bb_error_msg_and_die("-a and -g 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)) + if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) + && !(stty_state & STTY_noargs) ) { - bb_error_msg_and_die("modes may not be set when specifying an output style"); + bb_error_msg_and_die("modes may not be set when -a or -g is used"); } /* Now it is safe to start doing things */ @@ -1448,7 +1474,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) } switch (param) { -#ifdef HAVE_C_LINE +#ifdef __linux__ case param_line: mode.c_line = xatoul_sfx(argnext, stty_suffixes); stty_state |= STTY_require_set_attr; diff --git a/release/src/router/busybox/coreutils/sum.c b/release/src/router/busybox/coreutils/sum.c index e087fb85bb..95110a6da6 100644 --- a/release/src/router/busybox/coreutils/sum.c +++ b/release/src/router/busybox/coreutils/sum.c @@ -13,6 +13,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define sum_trivial_usage +//usage: "[-rs] [FILE]..." +//usage:#define sum_full_usage "\n\n" +//usage: "Checksum and count the blocks in a file\n" +//usage: "\n -r Use BSD sum algorithm (1K blocks)" +//usage: "\n -s Use System V sum algorithm (512byte blocks)" + #include "libbb.h" enum { SUM_BSD, PRINT_NAME, SUM_SYSV }; diff --git a/release/src/router/busybox/coreutils/sync.c b/release/src/router/busybox/coreutils/sync.c index bb112ea38c..7d98a1e301 100644 --- a/release/src/router/busybox/coreutils/sync.c +++ b/release/src/router/busybox/coreutils/sync.c @@ -9,6 +9,11 @@ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//usage:#define sync_trivial_usage +//usage: "" +//usage:#define sync_full_usage "\n\n" +//usage: "Write all buffered blocks to disk" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/tac.c b/release/src/router/busybox/coreutils/tac.c index ab3e66ac20..94d669de19 100644 --- a/release/src/router/busybox/coreutils/tac.c +++ b/release/src/router/busybox/coreutils/tac.c @@ -16,6 +16,11 @@ * http://www.uclibc.org/lists/busybox/2003-July/008813.html */ +//usage:#define tac_trivial_usage +//usage: "[FILE]..." +//usage:#define tac_full_usage "\n\n" +//usage: "Concatenate FILEs and print them in reverse" + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/tail.c b/release/src/router/busybox/coreutils/tail.c index df881a37a1..b376ec863f 100644 --- a/release/src/router/busybox/coreutils/tail.c +++ b/release/src/router/busybox/coreutils/tail.c @@ -24,6 +24,30 @@ * 7) lseek attempted when count==0 even if arg was +0 (from top) */ +//usage:#define tail_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define tail_full_usage "\n\n" +//usage: "Print last 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -f Print data as file grows" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -s SECONDS Wait SECONDS between reads with -f" +//usage: ) +//usage: "\n -n N[kbm] Print last N lines" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -c N[kbm] Print last N bytes" +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: "\n" +//usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." +//usage: "\nIf N starts with a '+', output begins with the Nth item from the start" +//usage: "\nof each file, not from the end." +//usage: ) +//usage: +//usage:#define tail_example_usage +//usage: "$ tail -n 1 /etc/resolv.conf\n" +//usage: "nameserver 10.0.0.1\n" + #include "libbb.h" static const struct suffix_mult tail_suffixes[] = { @@ -34,9 +58,11 @@ static const struct suffix_mult tail_suffixes[] = { }; struct globals { - bool status; + bool from_top; + bool exitcode; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) static void tail_xprint_header(const char *fmt, const char *filename) { @@ -60,7 +86,7 @@ static ssize_t tail_read(int fd, char *buf, size_t count) r = full_read(fd, buf, count); if (r < 0) { bb_perror_msg(bb_msg_read_error); - G.status = EXIT_FAILURE; + G.exitcode = EXIT_FAILURE; } return r; @@ -74,7 +100,7 @@ static unsigned eat_num(const char *p) p++; else if (*p == '+') { p++; - G.status = 1; /* mark that we saw "+" */ + G.from_top = 1; } return xatou_sfx(p, tail_suffixes); } @@ -84,7 +110,6 @@ int tail_main(int argc, char **argv) { unsigned count = 10; unsigned sleep_period = 1; - bool from_top; const char *str_c, *str_n; char *tailbuf; @@ -96,6 +121,8 @@ int tail_main(int argc, char **argv) int *fds; const char *fmt; + INIT_G(); + #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] == '-') @@ -127,8 +154,6 @@ int tail_main(int argc, char **argv) #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(fds[0]) * (argc + 1)); @@ -146,7 +171,7 @@ int tail_main(int argc, char **argv) do { int fd = open_or_warn_stdin(argv[i]); if (fd < 0 && !FOLLOW_RETRY) { - G.status = EXIT_FAILURE; + G.exitcode = EXIT_FAILURE; continue; } fds[nfiles] = fd; @@ -158,15 +183,19 @@ int tail_main(int argc, char **argv) /* prepare the buffer */ tailbufsize = BUFSIZ; - if (!from_top && COUNT_BYTES) { + if (!G.from_top && COUNT_BYTES) { if (tailbufsize < count + BUFSIZ) { tailbufsize = count + BUFSIZ; } } - tailbuf = xmalloc(tailbufsize); + /* tail -c1024m REGULAR_FILE doesn't really need 1G mem block. + * (In fact, it doesn't need ANY memory). So delay allocation. + */ + tailbuf = NULL; /* tail the files */ - fmt = header_fmt_str + 1; /* skip header leading newline on first output */ + + fmt = header_fmt_str + 1; /* skip leading newline in the header on the first output */ i = 0; do { char *buf; @@ -177,14 +206,14 @@ int tail_main(int argc, char **argv) int fd = fds[i]; if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) - continue; /* may happen with -E */ + continue; /* may happen with -F */ if (nfiles > header_threshhold) { tail_xprint_header(fmt, argv[i]); fmt = header_fmt_str; } - if (!from_top) { + if (!G.from_top) { off_t current = lseek(fd, 0, SEEK_END); if (current > 0) { unsigned off; @@ -217,20 +246,23 @@ int tail_main(int argc, char **argv) } } + if (!tailbuf) + tailbuf = xmalloc(tailbufsize); + buf = tailbuf; taillen = 0; /* "We saw 1st line/byte". * Used only by +N code ("start from Nth", 1-based): */ seen = 1; newlines_seen = 0; - while ((nread = tail_read(fd, buf, tailbufsize-taillen)) > 0) { - if (from_top) { + while ((nread = tail_read(fd, buf, tailbufsize - taillen)) > 0) { + if (G.from_top) { int nwrite = nread; if (seen < count) { /* We need to skip a few more bytes/lines */ if (COUNT_BYTES) { nwrite -= (count - seen); - seen = count; + seen += nread; } else { char *s = buf; do { @@ -288,7 +320,7 @@ int tail_main(int argc, char **argv) buf = tailbuf + taillen; } } /* while (tail_read() > 0) */ - if (!from_top) { + if (!G.from_top) { xwrite(STDOUT_FILENO, tailbuf, taillen); } } while (++i < nfiles); @@ -343,10 +375,11 @@ int tail_main(int argc, char **argv) xwrite(STDOUT_FILENO, tailbuf, nread); } } while (++i < nfiles); - } + } /* while (1) */ + if (ENABLE_FEATURE_CLEAN_UP) { free(fds); free(tailbuf); } - return G.status; + return G.exitcode; } diff --git a/release/src/router/busybox/coreutils/tee.c b/release/src/router/busybox/coreutils/tee.c index e66e885ec9..48cc0508fc 100644 --- a/release/src/router/busybox/coreutils/tee.c +++ b/release/src/router/busybox/coreutils/tee.c @@ -10,6 +10,18 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */ +//usage:#define tee_trivial_usage +//usage: "[-ai] [FILE]..." +//usage:#define tee_full_usage "\n\n" +//usage: "Copy stdin to each FILE, and also to stdout\n" +//usage: "\n -a Append to the given FILEs, don't overwrite" +//usage: "\n -i Ignore interrupt signals (SIGINT)" +//usage: +//usage:#define tee_example_usage +//usage: "$ echo \"Hello\" | tee /tmp/foo\n" +//usage: "$ cat /tmp/foo\n" +//usage: "Hello\n" + #include "libbb.h" int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/coreutils/test.c b/release/src/router/busybox/coreutils/test.c index 8ec8da0378..0bc008e7c8 100644 --- a/release/src/router/busybox/coreutils/test.c +++ b/release/src/router/busybox/coreutils/test.c @@ -39,6 +39,29 @@ //config: help //config: Enable 64-bit support in test. +/* "test --help" does not print help (POSIX compat), only "[ --help" does. + * We display " EXPRESSION ]" here (not " EXPRESSION") + * Unfortunately, it screws up generated BusyBox.html. TODO. */ +//usage:#define test_trivial_usage +//usage: "EXPRESSION ]" +//usage:#define test_full_usage "\n\n" +//usage: "Check file types, compare values etc. Return a 0/1 exit code\n" +//usage: "depending on logical value of EXPRESSION" +//usage: +//usage:#define test_example_usage +//usage: "$ test 1 -eq 2\n" +//usage: "$ echo $?\n" +//usage: "1\n" +//usage: "$ test 1 -eq 1\n" +//usage: "$ echo $?\n" +//usage: "0\n" +//usage: "$ [ -d /etc ]\n" +//usage: "$ echo $?\n" +//usage: "0\n" +//usage: "$ [ -d /junk ]\n" +//usage: "$ echo $?\n" +//usage: "1\n" + #include "libbb.h" #include @@ -687,7 +710,8 @@ static number_t nexpr(enum token n) if (n == EOI) { /* special case: [ ! ], [ a -a ! ] are valid */ /* IOW, "! ARG" may miss ARG */ - unnest_msg("aexpr(%s)\n", TOKSTR[n]); res = nexpr(n); - dbg_msg("aexpr: nexpr:%lld, next args:%s\n", res, args[1]); + dbg_msg("aexpr: nexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); if (check_operator(*++args) == BAND) { - dbg_msg("aexpr: arg is AND, next args:%s\n", args[1]); + dbg_msg("aexpr: arg is AND, next args:%s(%p)\n", args[1], &args[1]); res = aexpr(check_operator(*++args)) && res; unnest_msg("oexpr(%s)\n", TOKSTR[n]); res = aexpr(n); - dbg_msg("oexpr: aexpr:%lld, next args:%s\n", res, args[1]); + dbg_msg("oexpr: aexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); if (check_operator(*++args) == BOR) { - dbg_msg("oexpr: next arg is OR, next args:%s\n", args[1]); + dbg_msg("oexpr: next arg is OR, next args:%s(%p)\n", args[1], &args[1]); res = oexpr(check_operator(*++args)) || res; unnest_msg(" diff --git a/release/src/router/busybox/coreutils/uniq.c b/release/src/router/busybox/coreutils/uniq.c index decf7e4f82..9208d34ec4 100644 --- a/release/src/router/busybox/coreutils/uniq.c +++ b/release/src/router/busybox/coreutils/uniq.c @@ -10,6 +10,23 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ +//usage:#define uniq_trivial_usage +//usage: "[-cdu][-f,s,w N] [INPUT [OUTPUT]]" +//usage:#define uniq_full_usage "\n\n" +//usage: "Discard duplicate lines\n" +//usage: "\n -c Prefix lines by the number of occurrences" +//usage: "\n -d Only print duplicate lines" +//usage: "\n -u Only print unique lines" +//usage: "\n -f N Skip first N fields" +//usage: "\n -s N Skip first N chars (after any skipped fields)" +//usage: "\n -w N Compare N characters in line" +//usage: +//usage:#define uniq_example_usage +//usage: "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" + #include "libbb.h" int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/coreutils/usleep.c b/release/src/router/busybox/coreutils/usleep.c index cb4ec5898e..2e4eb57211 100644 --- a/release/src/router/busybox/coreutils/usleep.c +++ b/release/src/router/busybox/coreutils/usleep.c @@ -9,6 +9,15 @@ /* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */ +//usage:#define usleep_trivial_usage +//usage: "N" +//usage:#define usleep_full_usage "\n\n" +//usage: "Pause for N microseconds" +//usage: +//usage:#define usleep_example_usage +//usage: "$ usleep 1000000\n" +//usage: "[pauses for 1 second]\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ @@ -20,9 +29,7 @@ int usleep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } - if (usleep(xatou(argv[1]))) { - bb_perror_nomsg_and_die(); - } + usleep(xatou(argv[1])); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/coreutils/uudecode.c b/release/src/router/busybox/coreutils/uudecode.c index 0c4311f246..b298fcb953 100644 --- a/release/src/router/busybox/coreutils/uudecode.c +++ b/release/src/router/busybox/coreutils/uudecode.c @@ -10,6 +10,18 @@ * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the * "end" line */ + +//usage:#define uudecode_trivial_usage +//usage: "[-o OUTFILE] [INFILE]" +//usage:#define uudecode_full_usage "\n\n" +//usage: "Uudecode a file\n" +//usage: "Finds OUTFILE in uuencoded source unless -o is given" +//usage: +//usage:#define uudecode_example_usage +//usage: "$ uudecode -o busybox busybox.uu\n" +//usage: "$ ls -l busybox\n" +//usage: "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" + #include "libbb.h" #if ENABLE_UUDECODE @@ -113,10 +125,11 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) mode = bb_strtou(line_ptr, NULL, 8); if (outname == NULL) { outname = strchr(line_ptr, ' '); - if ((outname == NULL) || (*outname == '\0')) { + if (!outname) break; - } outname++; + if (!outname[0]) + break; } dst_stream = stdout; if (NOT_LONE_DASH(outname)) { @@ -132,7 +145,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) } #endif -//applet:IF_BASE64(APPLET(base64, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_BASE64(APPLET(base64, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_BASE64) += uudecode.o @@ -146,7 +159,6 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) //usage: "[-d] [FILE]" //usage:#define base64_full_usage "\n\n" //usage: "Base64 encode or decode FILE to standard output" -//usage: "\nOptions:" //usage: "\n -d Decode data" ////usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" ////usage: "\n -i When decoding, ignore non-alphabet characters" diff --git a/release/src/router/busybox/coreutils/uuencode.c b/release/src/router/busybox/coreutils/uuencode.c index fe9e8c6646..673ef36e70 100644 --- a/release/src/router/busybox/coreutils/uuencode.c +++ b/release/src/router/busybox/coreutils/uuencode.c @@ -8,6 +8,19 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define uuencode_trivial_usage +//usage: "[-m] [FILE] STORED_FILENAME" +//usage:#define uuencode_full_usage "\n\n" +//usage: "Uuencode FILE (or stdin) to stdout\n" +//usage: "\n -m Use base64 encoding per RFC1521" +//usage: +//usage:#define uuencode_example_usage +//usage: "$ uuencode busybox busybox\n" +//usage: "begin 755 busybox\n" +//usage: "\n" +//usage: "$ uudecode busybox busybox > busybox.uu\n" +//usage: "$\n" + #include "libbb.h" enum { diff --git a/release/src/router/busybox/coreutils/wc.c b/release/src/router/busybox/coreutils/wc.c index 6e22c66c8c..a410e407a0 100644 --- a/release/src/router/busybox/coreutils/wc.c +++ b/release/src/router/busybox/coreutils/wc.c @@ -64,7 +64,6 @@ //usage: //usage:#define wc_full_usage "\n\n" //usage: "Count lines, words, and bytes for each FILE (or stdin)\n" -//usage: "\nOptions:" //usage: "\n -c Count bytes" //usage: IF_UNICODE_SUPPORT( //usage: "\n -m Count characters" diff --git a/release/src/router/busybox/coreutils/who.c b/release/src/router/busybox/coreutils/who.c index 8384d95349..f955ce6d35 100644 --- a/release/src/router/busybox/coreutils/who.c +++ b/release/src/router/busybox/coreutils/who.c @@ -18,8 +18,39 @@ */ /* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */ +//config:config WHO +//config: bool "who" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: who is used to show who is logged on. + +//config:config USERS +//config: bool "users" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Print users currently logged on. + +//applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) +//applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_USERS) += who.o +//kbuild:lib-$(CONFIG_WHO) += who.o + +//usage:#define users_trivial_usage +//usage: "" +//usage:#define users_full_usage "\n\n" +//usage: "Print the users currently logged on" + +//usage:#define who_trivial_usage +//usage: "[-a]" +//usage:#define who_full_usage "\n\n" +//usage: "Show who is logged on\n" +//usage: "\n -a Show all" +//usage: "\n -H Print column headers" + #include "libbb.h" -#include static void idle_string(char *str6, time_t t) { @@ -44,9 +75,11 @@ int who_main(int argc UNUSED_PARAM, char **argv) { struct utmp *ut; unsigned opt; + int do_users = (ENABLE_USERS && (!ENABLE_WHO || applet_name[0] == 'u')); + const char *fmt = "%s"; opt_complementary = "=0"; - opt = getopt32(argv, "aH"); + opt = getopt32(argv, do_users ? "" : "aH"); if (opt & 2) // -H printf("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST\n"); @@ -55,36 +88,43 @@ int who_main(int argc UNUSED_PARAM, char **argv) if (ut->ut_user[0] && ((opt & 1) || ut->ut_type == USER_PROCESS) ) { - char str6[6]; - char name[sizeof("/dev/") + sizeof(ut->ut_line) + 1]; - struct stat st; - time_t seconds; + if (!do_users) { + char str6[6]; + char name[sizeof("/dev/") + sizeof(ut->ut_line) + 1]; + struct stat st; + time_t seconds; - str6[0] = '?'; - str6[1] = '\0'; - strcpy(name, "/dev/"); - safe_strncpy(ut->ut_line[0] == '/' ? name : name + sizeof("/dev/")-1, - ut->ut_line, - sizeof(ut->ut_line)+1 - ); - 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 */ - seconds = ut->ut_tv.tv_sec; - /* How wide time field can be? - * "Nov 10 19:33:20": 15 chars - * "2010-11-10 19:33": 16 chars - */ - printf("%-15.*s %-15.*s %-7s %-16.16s %.*s\n", - (int)sizeof(ut->ut_user), ut->ut_user, - (int)sizeof(ut->ut_line), ut->ut_line, - str6, - ctime(&seconds) + 4, - (int)sizeof(ut->ut_host), ut->ut_host - ); + str6[0] = '?'; + str6[1] = '\0'; + strcpy(name, "/dev/"); + safe_strncpy(ut->ut_line[0] == '/' ? name : name + sizeof("/dev/")-1, + ut->ut_line, + sizeof(ut->ut_line)+1 + ); + 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 */ + seconds = ut->ut_tv.tv_sec; + /* How wide time field can be? + * "Nov 10 19:33:20": 15 chars + * "2010-11-10 19:33": 16 chars + */ + printf("%-15.*s %-15.*s %-7s %-16.16s %.*s\n", + (int)sizeof(ut->ut_user), ut->ut_user, + (int)sizeof(ut->ut_line), ut->ut_line, + str6, + ctime(&seconds) + 4, + (int)sizeof(ut->ut_host), ut->ut_host + ); + } else { + printf(fmt, ut->ut_user); + fmt = " %s"; + } } } + if (do_users) + bb_putchar('\n'); if (ENABLE_FEATURE_CLEAN_UP) endutent(); return EXIT_SUCCESS; diff --git a/release/src/router/busybox/coreutils/whoami.c b/release/src/router/busybox/coreutils/whoami.c index 78d20db140..30b17cab35 100644 --- a/release/src/router/busybox/coreutils/whoami.c +++ b/release/src/router/busybox/coreutils/whoami.c @@ -9,6 +9,11 @@ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//usage:#define whoami_trivial_usage +//usage: "" +//usage:#define whoami_full_usage "\n\n" +//usage: "Print the user name associated with the current effective user id" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/release/src/router/busybox/debianutils/mktemp.c b/release/src/router/busybox/debianutils/mktemp.c index 86881f86d7..dbe4309555 100644 --- a/release/src/router/busybox/debianutils/mktemp.c +++ b/release/src/router/busybox/debianutils/mktemp.c @@ -31,6 +31,25 @@ * -p; else /tmp [deprecated] */ +//usage:#define mktemp_trivial_usage +//usage: "[-dt] [-p DIR] [TEMPLATE]" +//usage:#define mktemp_full_usage "\n\n" +//usage: "Create a temporary file with name based on TEMPLATE and print its name.\n" +//usage: "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" +//usage: "Without TEMPLATE, -t tmp.XXXXXX is assumed.\n" +//usage: "\n -d Make directory, not file" +////usage: "\n -q Fail silently on errors" - we ignore this opt +//usage: "\n -t Prepend base directory name to TEMPLATE" +//usage: "\n -p DIR Use DIR as a base directory (implies -t)" +//usage: "\n -u Do not create anything; print a name" +//usage: "\n" +//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /tmp" +//usage: +//usage:#define mktemp_example_usage +//usage: "$ mktemp /tmp/temp.XXXXXX\n" +//usage: "/tmp/temp.mWiLjM\n" +//usage: "$ ls -la /tmp/temp.mWiLjM\n" +//usage: "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" #include "libbb.h" @@ -40,28 +59,57 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv) const char *path; char *chp; unsigned opts; + enum { + OPT_d = 1 << 0, + OPT_q = 1 << 1, + OPT_t = 1 << 2, + OPT_p = 1 << 3, + OPT_u = 1 << 4, + }; path = getenv("TMPDIR"); if (!path || path[0] == '\0') path = "/tmp"; - /* -q and -t are ignored */ + /* -q is ignored */ opt_complementary = "?1"; /* 1 argument max */ - opts = getopt32(argv, "dqtp:", &path); + opts = getopt32(argv, "dqtp:u", &path); - chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); - if (!strchr(chp, '/') || (opts & 8)) + chp = argv[optind]; + if (!chp) { + /* GNU coreutils 8.4: + * bare "mktemp" -> "mktemp -t tmp.XXXXXX" + */ + chp = xstrdup("tmp.XXXXXX"); + opts |= OPT_t; + } + + if (opts & OPT_u) { + /* Remove (up to) 6 X's */ + unsigned len = strlen(chp); + int cnt = len > 6 ? 6 : len; + while (--cnt >= 0 && chp[--len] == 'X') + chp[len] = '\0'; + + chp = tempnam(opts & (OPT_t|OPT_p) ? path : "./", chp); + if (!chp) + return EXIT_FAILURE; + if (!(opts & (OPT_t|OPT_p))) + chp += 2; + goto ret; + } + + if (opts & (OPT_t|OPT_p)) chp = concat_path_file(path, chp); - if (opts & 1) { /* -d */ + if (opts & OPT_d) { if (mkdtemp(chp) == NULL) return EXIT_FAILURE; } else { if (mkstemp(chp) < 0) return EXIT_FAILURE; } - + ret: puts(chp); - return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/debianutils/pipe_progress.c b/release/src/router/busybox/debianutils/pipe_progress.c index 1e57dc241b..2c7444f311 100644 --- a/release/src/router/busybox/debianutils/pipe_progress.c +++ b/release/src/router/busybox/debianutils/pipe_progress.c @@ -6,6 +6,10 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define pipe_progress_trivial_usage NOUSAGE_STR +//usage:#define pipe_progress_full_usage "" + #include "libbb.h" #define PIPE_PROGRESS_SIZE 4096 diff --git a/release/src/router/busybox/debianutils/run_parts.c b/release/src/router/busybox/debianutils/run_parts.c index b93a5a917a..8f08f6dc66 100644 --- a/release/src/router/busybox/debianutils/run_parts.c +++ b/release/src/router/busybox/debianutils/run_parts.c @@ -30,6 +30,31 @@ * -u MASK umask. Set the umask of the program executed to MASK. */ +//usage:#define run_parts_trivial_usage +//usage: "[-t] "IF_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY" +//usage:#define run_parts_full_usage "\n\n" +//usage: "Run a bunch of scripts in DIRECTORY\n" +//usage: "\n -t Print what would be run, but don't actually run anything" +//usage: "\n -a ARG Pass ARG as argument for every program" +//usage: "\n -u MASK Set the umask to MASK before running every program" +//usage: IF_FEATURE_RUN_PARTS_FANCY( +//usage: "\n -l Print names of all matching files even if they are not executable" +//usage: ) +//usage: +//usage:#define run_parts_example_usage +//usage: "$ run-parts -a start /etc/init.d\n" +//usage: "$ run-parts -a stop=now /etc/init.d\n\n" +//usage: "Let's assume you have a script foo/dosomething:\n" +//usage: "#!/bin/sh\n" +//usage: "for i in $*; do eval $i; done; unset i\n" +//usage: "case \"$1\" in\n" +//usage: "start*) echo starting something;;\n" +//usage: "stop*) set -x; shutdown -h $stop;;\n" +//usage: "esac\n\n" +//usage: "Running this yields:\n" +//usage: "$run-parts -a stop=+4m foo/\n" +//usage: "+ shutdown -h +4m" + #include "libbb.h" struct globals { @@ -41,6 +66,7 @@ struct globals { #define names (G.names) #define cur (G.cur ) #define cmd (G.cmd ) +#define INIT_G() do { } while (0) enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; @@ -118,6 +144,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) unsigned n; int ret; + INIT_G(); + #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS applet_long_options = runparts_longopts; #endif diff --git a/release/src/router/busybox/debianutils/start_stop_daemon.c b/release/src/router/busybox/debianutils/start_stop_daemon.c index d2ee950685..7dadc3c9ee 100644 --- a/release/src/router/busybox/debianutils/start_stop_daemon.c +++ b/release/src/router/busybox/debianutils/start_stop_daemon.c @@ -31,7 +31,8 @@ Options controlling process matching [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. + command in /proc/$PID/exe and /proc/$PID/cmdline + (/proc/$PID/cmdline is a bbox extension) 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 @@ -56,6 +57,69 @@ Misc options: -v,--verbose Verbose */ +//usage:#define start_stop_daemon_trivial_usage +//usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]" +//usage:#define start_stop_daemon_full_usage "\n\n" +//usage: "Search for matching processes, and then\n" +//usage: "-K: stop all matching processes.\n" +//usage: "-S: start a process unless a matching process is found.\n" +//usage: IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( +//usage: "\nProcess matching:" +//usage: "\n -u,--user USERNAME|UID Match only this user's processes" +//usage: "\n -n,--name NAME Match processes with NAME" +//usage: "\n in comm field in /proc/PID/stat" +//usage: "\n -x,--exec EXECUTABLE Match processes with this command" +//usage: "\n in /proc/PID/{exe,cmdline}" +//usage: "\n -p,--pidfile FILE Match a process with PID from the file" +//usage: "\n All specified conditions must match" +//usage: "\n-S only:" +//usage: "\n -x,--exec EXECUTABLE Program to run" +//usage: "\n -a,--startas NAME Zeroth argument" +//usage: "\n -b,--background Background" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -N,--nicelevel N Change nice level" +//usage: ) +//usage: "\n -c,--chuid USER[:[GRP]] Change to user/group" +//usage: "\n -m,--make-pidfile Write PID to the pidfile specified by -p" +//usage: "\n-K only:" +//usage: "\n -s,--signal SIG Signal to send" +//usage: "\n -t,--test Match only, exit with 0 if a process is found" +//usage: "\nOther:" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -o,--oknodo Exit with status 0 if nothing is done" +//usage: "\n -v,--verbose Verbose" +//usage: ) +//usage: "\n -q,--quiet Quiet" +//usage: ) +//usage: IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( +//usage: "\nProcess matching:" +//usage: "\n -u USERNAME|UID Match only this user's processes" +//usage: "\n -n NAME Match processes with NAME" +//usage: "\n in comm field in /proc/PID/stat" +//usage: "\n -x EXECUTABLE Match processes with this command" +//usage: "\n command in /proc/PID/cmdline" +//usage: "\n -p FILE Match a process with PID from the file" +//usage: "\n All specified conditions must match" +//usage: "\n-S only:" +//usage: "\n -x EXECUTABLE Program to run" +//usage: "\n -a NAME Zeroth argument" +//usage: "\n -b Background" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -N N Change nice level" +//usage: ) +//usage: "\n -c USER[:[GRP]] Change to user/group" +//usage: "\n -m Write PID to the pidfile specified by -p" +//usage: "\n-K only:" +//usage: "\n -s SIG Signal to send" +//usage: "\n -t Match only, exit with 0 if a process is found" +//usage: "\nOther:" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -o Exit with status 0 if nothing is done" +//usage: "\n -v Verbose" +//usage: ) +//usage: "\n -q Quiet" +//usage: ) + #include /* Override ENABLE_FEATURE_PIDFILE */ @@ -135,8 +199,18 @@ static int pid_is_exec(pid_t pid) { ssize_t bytes; char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; + char *procname, *exelink; + int match; + + procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3; + + exelink = xmalloc_readlink(buf); + match = (exelink && strcmp(execname, exelink) == 0); + free(exelink); + if (match) + return match; - sprintf(buf, "/proc/%u/cmdline", (unsigned)pid); + strcpy(procname, "cmdline"); bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof); if (bytes > 0) { G.execname_cmpbuf[bytes] = '\0'; @@ -274,11 +348,17 @@ static int do_stop(void) goto ret; } for (p = G.found_procs; p; p = p->next) { - if (TEST || kill(p->pid, signal_nr) == 0) { + if (kill(p->pid, TEST ? 0 : signal_nr) == 0) { killed++; } else { - p->pid = 0; bb_perror_msg("warning: killing process %u", (unsigned)p->pid); + p->pid = 0; + if (TEST) { + /* Example: -K --test --pidfile PIDFILE detected + * that PIDFILE's pid doesn't exist */ + killed = -1; + goto ret; + } } } if (!QUIET && killed) { @@ -405,7 +485,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) *--argv = startas; if (opt & OPT_BACKGROUND) { #if BB_MMU - bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); + bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else @@ -433,8 +513,16 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_c) { struct bb_uidgid_t ugid = { -1, -1 }; 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 (ugid.uid != (uid_t) -1) { + struct passwd *pw = xgetpwuid(ugid.uid); + if (ugid.gid != (gid_t) -1) + pw->pw_gid = ugid.gid; + /* initgroups, setgid, setuid: */ + change_identity(pw); + } else if (ugid.gid != (gid_t) -1) { + xsetgid(ugid.gid); + setgroups(1, &ugid.gid); + } } #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY if (opt & OPT_NICELEVEL) { diff --git a/release/src/router/busybox/debianutils/which.c b/release/src/router/busybox/debianutils/which.c index a82641909a..15fd598b78 100644 --- a/release/src/router/busybox/debianutils/which.c +++ b/release/src/router/busybox/debianutils/which.c @@ -10,6 +10,15 @@ * Based on which from debianutils */ +//usage:#define which_trivial_usage +//usage: "[COMMAND]..." +//usage:#define which_full_usage "\n\n" +//usage: "Locate a COMMAND" +//usage: +//usage:#define which_example_usage +//usage: "$ which login\n" +//usage: "/bin/login\n" + #include "libbb.h" int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/docs/.gitignore b/release/src/router/busybox/docs/.gitignore index 11d6163602..3d1c5bd8ad 100644 --- a/release/src/router/busybox/docs/.gitignore +++ b/release/src/router/busybox/docs/.gitignore @@ -1,4 +1,5 @@ /busybox.1 /BusyBox.html +/busybox.net /BusyBox.txt /busybox.pod diff --git a/release/src/router/busybox/docs/ctty.htm b/release/src/router/busybox/docs/ctty.htm index 8f466cdde6..3cb2dd2bdb 100644 --- a/release/src/router/busybox/docs/ctty.htm +++ b/release/src/router/busybox/docs/ctty.htm @@ -9,6 +9,8 @@

Before looking at the Linux implementation, first a general Unix description of threads, processes, process groups and sessions. +

+(See also General Terminal Interface)

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. @@ -277,6 +279,7 @@ and inspect it by 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. +[vda: correction. SUS says that if SIGTTOU is blocked/ignored, write succeeds. ]

Orphaned process groups

diff --git a/release/src/router/busybox/docs/mdev.txt b/release/src/router/busybox/docs/mdev.txt index 2d03bd8b2f..61f93c9df1 100644 --- a/release/src/router/busybox/docs/mdev.txt +++ b/release/src/router/busybox/docs/mdev.txt @@ -51,19 +51,25 @@ device nodes if your system needs something more than the default root/root 660 permissions. The file has the format: - : - or @ : + [-] : +or + @ : +or + $envvar= : For example: - hd[a-z][0-9]* 0:3 660 + 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/move device nodes by using the next optional field. + : [=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/ diff --git a/release/src/router/busybox/docs/new-applet-HOWTO.txt b/release/src/router/busybox/docs/new-applet-HOWTO.txt index bb29999cf1..6a8054d0e8 100644 --- a/release/src/router/busybox/docs/new-applet-HOWTO.txt +++ b/release/src/router/busybox/docs/new-applet-HOWTO.txt @@ -161,7 +161,7 @@ algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily: Be sure to read the top of applets.src.h before adding your applet. /* all programs above here are alphabetically "less than" 'mu' */ - IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + IF_MU(APPLET(mu, BB_DIR_USR_BIN, BB_SUID_DROP)) /* all programs below here are alphabetically "greater than" 'mu' */ diff --git a/release/src/router/busybox/docs/nofork_noexec.txt b/release/src/router/busybox/docs/nofork_noexec.txt index 06c789affd..c58f5a83f1 100644 --- a/release/src/router/busybox/docs/nofork_noexec.txt +++ b/release/src/router/busybox/docs/nofork_noexec.txt @@ -44,9 +44,11 @@ NOEXEC trick is disabled for NOMMU build. NOFORK NOFORK applet should work correctly if another applet simply runs -_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: +_main(argc,argv) and then continues with its business. +xargs, find, shells do it (grep for "spawn_and_wait" and +"run_nofork_applet" to find more users). + +This poses much more serious limitations on what applet can do: * all NOEXEC limitations apply. * do not ever exit() or exec(). @@ -56,7 +58,7 @@ on what applet can/cannot do: 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). + (e.g. bb_common_bufsiz1) prior to returning. - 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 @@ -77,3 +79,20 @@ script loops. Applets which mess with signal handlers, termios etc are probably not worth the effort. Any NOFORK applet is also a NOEXEC applet. + + + Relevant CONFIG options + +FEATURE_PREFER_APPLETS + BB_EXECVP(cmd, argv) will try to exec /proc/self/exe + if command's name matches some applet name + applet tables will contain NOFORK/NOEXEC bits + spawn_and_wait(argv) will do NOFORK/NOEXEC tricks + +FEATURE_SH_STANDALONE (needs FEATURE_PREFER_APPLETS=y) + shells will try to exec /proc/self/exe if command's name matches + some applet name + shells will do NOEXEC trick on NOEXEC applets + +FEATURE_SH_NOFORK (needs FEATURE_PREFER_APPLETS=y) + shells will do NOFORK trick on NOFORK applets diff --git a/release/src/router/busybox/docs/style-guide.txt b/release/src/router/busybox/docs/style-guide.txt index fdf6cfe4da..10ed893dc9 100644 --- a/release/src/router/busybox/docs/style-guide.txt +++ b/release/src/router/busybox/docs/style-guide.txt @@ -679,11 +679,10 @@ line in the midst of your #includes, if you need to parse long options: Then have long options defined: - static const struct option _long_options[] = { - { "list", 0, NULL, 't' }, - { "extract", 0, NULL, 'x' }, - { NULL, 0, NULL, 0 } - }; + static const char _longopts[] ALIGN1 = + "list\0" No_argument "t" + "extract\0" No_argument "x" + ; And a code block similar to the following near the top of your applet_main() routine: @@ -691,7 +690,7 @@ routine: char *str_b; opt_complementary = "cryptic_string"; - applet_long_options = _long_options; /* if you have them */ + applet_long_options = _longopts; /* if you have them */ opt = getopt32(argc, argv, "ab:c", &str_b); if (opt & 1) { handle_option_a(); diff --git a/release/src/router/busybox/docs/syslog.conf.txt b/release/src/router/busybox/docs/syslog.conf.txt new file mode 100644 index 0000000000..6d9c4a173a --- /dev/null +++ b/release/src/router/busybox/docs/syslog.conf.txt @@ -0,0 +1,28 @@ +If syslogd applet compiled with FEATURE_SYSLOGD_CFG=y, then it supports restricted syslog.conf. +The config resembles rsyslog.conf in RULES part: + +LINE = DELIM [RULE | COMMENT] +COMMENT = #.* +DELIM = SPACE TAB +RULE = SELECTOR [;SELECTOR]* DELIM* ACTION DELIM* +SELECTOR = FACILITY [,FACILITY]* .[[!]=] PRIORITY +FACILITY = * | kern | user ... (see syslog.h) +PRIORITY = * | emerg | alert ... (see syslog.h) +ACTION = FILE + +"mark" facility is NOT supported. +"none" priority is supported. +In FACILITY and PRIORITY "*" stands for "any". +FILE is a regular file or tty device. + +Here is an example: + +#syslog.conf +kern,user.* /var/log/messages #all messages of kern and user facilities +kern.!err /var/log/critical #all messages of kern facility with priorities lower than err (warn, notice ...) +*.*;auth,authpriv.none /var/log/noauth #all messages except ones with auth and authpriv facilities +kern,user.*;kern.!=notice;*.err;syslog.none /var/log/OMG #some whicked rule just as an example =) +*.* /dev/null #this prevents from logging to default log file (-O FILE or /var/log/messages) + +Even in the case of match with some rule another rules will be tried too. +If there was no match with any of the rules, logging to default log file or shared memory will be performed. diff --git a/release/src/router/busybox/docs/unicode.txt b/release/src/router/busybox/docs/unicode.txt index 32df24dc89..9c159ce2a8 100644 --- a/release/src/router/busybox/docs/unicode.txt +++ b/release/src/router/busybox/docs/unicode.txt @@ -29,7 +29,7 @@ But we also need to handle the following problematic moments: Editors (vi, ed) This case is a bit similar to "shell input", but unlike shell, -editors may encounder many more unexpected unicode sequences +editors may encounter many more unexpected unicode sequences (try to load a random binary file...), and they need to preserve them, unlike shell which can afford to drop bogus input. diff --git a/release/src/router/busybox/e2fsprogs/Config.src b/release/src/router/busybox/e2fsprogs/Config.src index 6043e9b57b..a113378fb4 100644 --- a/release/src/router/busybox/e2fsprogs/Config.src +++ b/release/src/router/busybox/e2fsprogs/Config.src @@ -9,22 +9,23 @@ INSERT config CHATTR bool "chattr" - default y + default n help chattr changes the file attributes on a second extended file system. -### config E2FSCK -### bool "e2fsck" -### default y -### 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 E2FSCK + bool "e2fsck" + default n + select VOLUMEID + 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 y + 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 @@ -32,40 +33,32 @@ config FSCK config LSATTR bool "lsattr" - default y - depends on PLATFORM_LINUX + default n help lsattr lists the file attributes on a second extended file system. -### config MKE2FS -### bool "mke2fs" -### default y -### help -### mke2fs is used to create an ext2/ext3 filesystem. The normal compat -### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided. +config MKE2FS + bool "mke2fs" + default n + select VOLUMEID + 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 # off: it is too limited compared to upstream version + default n + select VOLUMEID help tune2fs allows the system administrator to adjust various tunable filesystem parameters on Linux ext2/ext3 filesystems. -### config E2LABEL -### bool "e2label" -### default y -### 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 y -### 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. +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. endmenu diff --git a/release/src/router/busybox/e2fsprogs/Kbuild.src b/release/src/router/busybox/e2fsprogs/Kbuild.src index b7a14c381c..8df2b17504 100644 --- a/release/src/router/busybox/e2fsprogs/Kbuild.src +++ b/release/src/router/busybox/e2fsprogs/Kbuild.src @@ -8,8 +8,11 @@ lib-y:= INSERT -lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o -lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o +lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o +lib-$(CONFIG_E2FSCK) += e2fsck.o util.o e2fs_lib.o +lib-$(CONFIG_FSCK) += fsck.o +lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o +lib-$(CONFIG_MKE2FS) += mke2fs.o util.o e2fs_lib.o +lib-$(CONFIG_TUNE2FS) += tune2fs.o util.o e2fs_lib.o -lib-$(CONFIG_FSCK) += fsck.o -lib-$(CONFIG_TUNE2FS) += tune2fs.o +CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h diff --git a/release/src/router/busybox/e2fsprogs/README b/release/src/router/busybox/e2fsprogs/README dissimilarity index 99% index eb158e5881..fac0901931 100644 --- a/release/src/router/busybox/e2fsprogs/README +++ b/release/src/router/busybox/e2fsprogs/README @@ -1,12 +1,3 @@ -Authors and contributors of original e2fsprogs: - -Remy Card -Theodore Ts'o -Stephen C. Tweedie -Andreas Gruenbacher, -Kaz Kylheku -F.W. ten Wolde -Jeremy Fitzhardinge -M.J.E. Mol -Miquel van Smoorenburg -Uwe Ohse +This is a pretty straight rip from the e2fsprogs pkg. + +See README's in subdirs for specific info. diff --git a/release/src/router/busybox/e2fsprogs/blkid/Kbuild.src b/release/src/router/busybox/e2fsprogs/blkid/Kbuild.src new file mode 100644 index 0000000000..02b4d24961 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/Kbuild.src @@ -0,0 +1,26 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +NEEDED-$(CONFIG_E2FSCK) = y +NEEDED-$(CONFIG_FSCK) = y +NEEDED-$(CONFIG_MKE2FS) = y +NEEDED-$(CONFIG_TUNE2FS) = y + +lib-y:= + +INSERT + +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/release/src/router/busybox/e2fsprogs/blkid/blkid.h b/release/src/router/busybox/e2fsprogs/blkid/blkid.h new file mode 100644 index 0000000000..9a3c2afdbd --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/blkid.h @@ -0,0 +1,104 @@ +/* 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 1 + +#include +#include + +#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 diff --git a/release/src/router/busybox/e2fsprogs/blkid/blkidP.h b/release/src/router/busybox/e2fsprogs/blkid/blkidP.h new file mode 100644 index 0000000000..d6b2b42cc5 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/blkidP.h @@ -0,0 +1,186 @@ +/* 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 1 + +#include +#include + +#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 +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 diff --git a/release/src/router/busybox/e2fsprogs/blkid/blkid_getsize.c b/release/src/router/busybox/e2fsprogs/blkid/blkid_getsize.c new file mode 100644 index 0000000000..e1f6ba6d2a --- /dev/null +++ b/release/src/router/busybox/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 +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#include +#endif +#ifdef HAVE_SYS_DISK_H +#ifdef HAVE_SYS_QUEUE_H +#include /* for LIST_HEAD */ +#endif +#include +#endif +#ifdef __linux__ +#include +#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__ + uname(&ut); + if ((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/release/src/router/busybox/e2fsprogs/blkid/cache.c b/release/src/router/busybox/e2fsprogs/blkid/cache.c new file mode 100644 index 0000000000..d1d29146b3 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#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/release/src/router/busybox/e2fsprogs/blkid/dev.c b/release/src/router/busybox/e2fsprogs/blkid/dev.c new file mode 100644 index 0000000000..bb0cc914a0 --- /dev/null +++ b/release/src/router/busybox/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 +#include + +#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 +#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/release/src/router/busybox/e2fsprogs/blkid/devname.c b/release/src/router/busybox/e2fsprogs/blkid/devname.c new file mode 100644 index 0000000000..fad92cb313 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#include + +#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 +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_for_read(lvm_device)) == 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_for_read(PROC_EVMS_VOLUMES); + 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 = NULL; + 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(NULL) - 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_for_read(PROC_PARTITIONS); + 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(NULL); + 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/release/src/router/busybox/e2fsprogs/blkid/devno.c b/release/src/router/busybox/e2fsprogs/blkid/devno.c new file mode 100644 index 0000000000..ae326f81a0 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#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/release/src/router/busybox/e2fsprogs/blkid/list.c b/release/src/router/busybox/e2fsprogs/blkid/list.c new file mode 100644 index 0000000000..04d61a19ba --- /dev/null +++ b/release/src/router/busybox/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/release/src/router/busybox/e2fsprogs/blkid/list.h b/release/src/router/busybox/e2fsprogs/blkid/list.h new file mode 100644 index 0000000000..a24baaa912 --- /dev/null +++ b/release/src/router/busybox/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 1 + +#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 diff --git a/release/src/router/busybox/e2fsprogs/blkid/probe.c b/release/src/router/busybox/e2fsprogs/blkid/probe.c new file mode 100644 index 0000000000..651193b426 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/probe.c @@ -0,0 +1,726 @@ +/* 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 +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#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 = NULL; + + 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 = NULL; + 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 = NULL; + 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 = NULL; + + 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 = NULL; + + 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 = NULL; + + 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 = NULL; + + 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 = NULL; + + 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(NULL); + 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)); + + fd = open(dev->bid_name, O_RDONLY); + if (fd < 0 + || fstat(fd, &st) < 0 + ) { + if (fd >= 0) + close(fd); + 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); + close(fd); + return NULL; + } + +found_type: + if (dev && type) { + dev->bid_devno = st.st_rdev; + dev->bid_time = time(NULL); + 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/release/src/router/busybox/e2fsprogs/blkid/probe.h b/release/src/router/busybox/e2fsprogs/blkid/probe.h new file mode 100644 index 0000000000..b6d8f8e7dd --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/probe.h @@ -0,0 +1,374 @@ +/* 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 1 + +#include + +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/release/src/router/busybox/e2fsprogs/blkid/read.c b/release/src/router/busybox/e2fsprogs/blkid/read.c new file mode 100644 index 0000000000..f795a5d145 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/blkid/read.c @@ -0,0 +1,459 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#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 + * + * The following tags are required for each entry: + * unique (within this file) ID number of this device + * (ascii time_t) time this entry was last read from disk + * (detected) type of filesystem/data for this partition + * + * The following tags may be present, depending on the device contents + * (user supplied) label (volume name, etc) + * (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 " continue parsing line + * line starts with " 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, "", 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: + * devname + * devnamebar + */ +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 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 value 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 /dev/foo + * + * 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 = xfdopen_for_read(fd); + + 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/release/src/router/busybox/e2fsprogs/blkid/resolve.c b/release/src/router/busybox/e2fsprogs/blkid/resolve.c new file mode 100644 index 0000000000..295ca61bff --- /dev/null +++ b/release/src/router/busybox/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 +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#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 = NULL, *v = NULL; + 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, "Can't 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 : ""); + } else { + value = blkid_get_devname(cache, argv[1], NULL); + printf("%s has tag %s\n", value ? value : "", argv[1]); + } + blkid_put_cache(cache); + return value ? 0 : 1; +} +#endif diff --git a/release/src/router/busybox/e2fsprogs/blkid/save.c b/release/src/router/busybox/e2fsprogs/blkid/save.c new file mode 100644 index 0000000000..e60cca445f --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#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, + "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\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 = xfdopen_for_write(fd); + opened = tmp; + } + fchmod(fd, 0644); + } + + if (!file) { + file = fopen_for_write(filename); + 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/release/src/router/busybox/e2fsprogs/blkid/tag.c b/release/src/router/busybox/e2fsprogs/blkid/tag.c new file mode 100644 index 0000000000..8337b46b6b --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include + +#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 = NULL; + + 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 +#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/release/src/router/busybox/e2fsprogs/chattr.c b/release/src/router/busybox/e2fsprogs/chattr.c index ab52cb0094..ae39d92245 100644 --- a/release/src/router/busybox/e2fsprogs/chattr.c +++ b/release/src/router/busybox/e2fsprogs/chattr.c @@ -19,75 +19,106 @@ * 98/12/29 - Display version info only when -V specified (G M Sipe) */ -#include "libbb.h" -#include "e2fs_lib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; -struct globals { - unsigned long version; - unsigned long af; - unsigned long rf; - smallint flags; - smallint 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 char *fp = strchr(e2attr_flags_sname_chattr, c); - if (fp) - return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr]; + 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(const char *arg, struct globals *gp) +static int decode_arg(char *arg) { unsigned long *fl; char opt = *arg++; - fl = &gp->af; if (opt == '-') { - gp->flags |= OPT_REM; - fl = &gp->rf; + flags |= OPT_REM; + fl = &rf; } else if (opt == '+') { - gp->flags |= OPT_ADD; + flags |= OPT_ADD; + fl = ⁡ } else if (opt == '=') { - gp->flags |= OPT_SET; + flags |= OPT_SET; + fl = &sf; } else - return 0; + return EOF; - while (*arg) - *fl |= get_flag(*arg++); + for (; *arg; ++arg) + (*fl) |= get_flag(*arg); return 1; } -static void change_attributes(const char *name, struct globals *gp); - -static int FAST_FUNC 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 int chattr_dir_proc(const char *, struct dirent *, void *); -static void change_attributes(const char *name, struct globals *gp) +static void change_attributes(const char * name) { unsigned long fsflags; struct stat st; - if (lstat(name, &st) != 0) { - bb_perror_msg("stat %s", name); + if (lstat(name, &st) == -1) { + bb_error_msg("stat %s failed", name); return; } - if (S_ISLNK(st.st_mode) && gp->recursive) + if (S_ISLNK(st.st_mode) && recursive) return; /* Don't try to open device files, fifos etc. We probably @@ -97,76 +128,93 @@ static void change_attributes(const char *name, struct globals *gp) 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 (flags & OPT_SET_VER) + if (fsetversion(name, version) == -1) + bb_error_msg("setting version on %s", name); - if (gp->flags & OPT_SET) { - fsflags = gp->af; + if (flags & OPT_SET) { + fsflags = sf; } else { - if (fgetflags(name, &fsflags) != 0) { - bb_perror_msg("reading flags on %s", name); + if (fgetflags(name, &fsflags) == -1) { + bb_error_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 (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) != 0) - bb_perror_msg("setting flags on %s", name); + if (fsetflags(name, fsflags) == -1) + bb_error_msg("setting flags on %s", name); - skip_setflags: - if (gp->recursive && S_ISDIR(st.st_mode)) - iterate_on_dir(name, chattr_dir_proc, gp); +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 UNUSED_PARAM, char **argv) +int chattr_main(int argc, char **argv) { - struct globals g; + int i; char *arg; - memset(&g, 0, sizeof(g)); - /* parse the args */ - while ((arg = *++argv)) { + for (i = 1; i < argc; ++i) { + arg = argv[i]; + /* take care of -R and -v */ - if (arg[0] == '-' - && (arg[1] == 'R' || arg[1] == 'v') - && !arg[2] - ) { - if (arg[1] == 'R') { - g.recursive = 1; + 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; } - /* arg[1] == 'v' */ - if (!*++argv) - bb_show_usage(); - g.version = xatoul(*argv); - g.flags |= OPT_SET_VER; - continue; } - if (!decode_arg(arg, &g)) + if (decode_arg(arg) == EOF) break; } /* run sanity checks on all the arguments given us */ - if (!*argv) + if (i >= argc) bb_show_usage(); - if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) + if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & 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 +"); + 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 */ - do change_attributes(*argv, &g); while (*++argv); + while (i < argc) + change_attributes(argv[i++]); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/e2fsprogs/e2fs_lib.h b/release/src/router/busybox/e2fsprogs/e2fs_lib.h index 9e49057297..fbabe9f46b 100644 --- a/release/src/router/busybox/e2fsprogs/e2fs_lib.h +++ b/release/src/router/busybox/e2fsprogs/e2fs_lib.h @@ -7,7 +7,7 @@ */ /* Constants and structures */ -#include "e2fs_defs.h" +#include "bb_e2fs_defs.h" PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN diff --git a/release/src/router/busybox/e2fsprogs/e2fsbb.h b/release/src/router/busybox/e2fsprogs/e2fsbb.h new file mode 100644 index 0000000000..d31c319556 --- /dev/null +++ b/release/src/router/busybox/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< + * 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 , 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 source tree. + */ + +//usage:#define e2fsck_trivial_usage +//usage: "[-panyrcdfvstDFSV] [-b superblock] [-B blocksize] " +//usage: "[-I inode_buffer_blocks] [-P process_inode_size] " +//usage: "[-l|-L bad_blocks_file] [-C fd] [-j external_journal] " +//usage: "[-E extended-options] device" +//usage:#define e2fsck_full_usage "\n\n" +//usage: "Check ext2/ext3 file system\n" +//usage: "\n -p Automatic repair (no questions)" +//usage: "\n -n Make no changes to the filesystem" +//usage: "\n -y Assume 'yes' to all questions" +//usage: "\n -c Check for bad blocks and add them to the badblock list" +//usage: "\n -f Force checking even if filesystem is marked clean" +//usage: "\n -v Verbose" +//usage: "\n -b superblock Use alternative superblock" +//usage: "\n -B blocksize Force blocksize when looking for superblock" +//usage: "\n -j journal Set location of the external journal" +//usage: "\n -l file Add to badblocks list" +//usage: "\n -L file Set badblocks list" +//usage: +//applet:IF_E2FSCK(APPLET(e2fsck, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, e2fsck)) +//applet:IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, e2fsck)) + + +#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 fl_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 + * + * 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 = xmalloc(sizeof(*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 = xmalloc(sizeof(dnode_t)); + + dnode_init(node, data); + dict_insert(dict, node, key); + return 1; +} + +/* + * 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 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); + + 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 = NULL; + 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]; + + unparse_uuid(sb->s_journal_uuid, uuid); + ctx->journal_name = get_devname_from_uuid(uuid); + if (!ctx->journal_name) + ctx->journal_name = get_devname_from_device(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 { + __u8 uuid[16]; + __u32 val[4]; + } u; + __u32 new_seq = 0; + int i; + + /* Leave a valid existing V1 superblock signature alone. + * Anything unrecognizable 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). + */ + generate_uuid(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(NULL); + 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 block number + * %B integer + * %c block number + * %Di ->ino inode number + * %Dn ->name string + * %Dr ->rec_len + * %Dl ->name_len + * %Dt ->filetype + * %d inode number + * %g integer + * %i inode number + * %Is -> i_size + * %IS -> i_extra_isize + * %Ib -> i_blocks + * %Il -> i_links_count + * %Im -> i_mode + * %IM -> i_mtime + * %IF -> i_faddr + * %If -> i_file_acl + * %Id -> i_dir_acl + * %Iu -> i_uid + * %Ig -> i_gid + * %j inode number + * %m + * %N + * %p ext2fs_get_pathname of directory + * %P ext2fs_get_pathname of ->ino with as + * the containing directory. (If dirent is NULL + * then return the pathname of directory ) + * %q ext2fs_get_pathname of directory + * %Q ext2fs_get_pathname of directory with as + * the containing directory. + * %s miscellaneous string + * %S backup superblock + * %X 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 '@' is expanded by looking up the index + * letter 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_(""), /* 0 */ + N_(""), /* 1 */ + "/", /* 2 */ + N_(""), /* 3 */ + N_(""), /* 4 */ + N_(""), /* 5 */ + N_(""), /* 6 */ + N_(""), /* 7 */ + N_(""), /* 8 */ + N_(""), /* 9 */ + N_(""), /* 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 = (char *)""; + 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 = xzalloc(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 = xmalloc(sizeof(struct region_el)); + 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(NULL); + 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(NULL); + 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(NULL); + 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(NULL); + 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(NULL); + 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(NULL); + 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 EXT2FS_ATTR((unused))) +{ + 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 fl_bool) +{ + ext2_filsys fs = ctx->fs; + + if (fl_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(NULL); + 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 = NULL; +#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(NULL); + 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(NULL); + 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(NULL); + 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(NULL); + 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 = NULL; + 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_("can't 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 = NULL; + 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 , 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 = xrealloc(fd->harray, + sizeof(struct hash_entry) * (fd->max_array+500)); + 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 = xrealloc(outdir->buf, blocks * fs->blocksize); + outdir->buf = new_mem; + new_mem = xrealloc(outdir->hashes, + blocks * sizeof(ext2_dirhash_t)); + outdir->hashes = new_mem; + } else { + outdir->buf = xmalloc(blocks * fs->blocksize); + outdir->hashes = xmalloc(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 = NULL; + 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 = NULL; + 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 = xmalloc(inode.i_size); + + fd.max_array = inode.i_size / 32; + fd.num_array = 0; + fd.harray = xmalloc(fd.max_array * sizeof(struct hash_entry)); + + 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 = xmalloc(hash_size * sizeof(struct list_head)); + + 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; ihash_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(NULL); + } 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 = NULL, *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_INO)) { + 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_INO) + 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_INO)) { + 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)) { + generate_uuid(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 EXT2FS_ATTR((unused)), unsigned int size, + const char *description EXT2FS_ATTR((unused))) +{ + void *ret; + + ret = xzalloc(size); + return ret; +} + +static char *string_copy(const char *str, int len) +{ + char *ret; + + if (!str) + return NULL; + if (!len) + len = strlen(str); + ret = xmalloc(len+1); + 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_stdin_TCSANOW(&tmp); +#endif + + if (def == 1) + defstr = ""; + else if (def == 0) + defstr = ""; + 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_stdin_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_stdin_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(_("can't 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_for_read("/proc/apm"); + 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_for_read(fname); + 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(NULL); + + 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 (!(ctx->options & E2F_OPT_PREEN) && + 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); + xwrite_str(ctx->progress_fd, 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=\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 = NULL; + + 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); + + 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 = argv[optind]; + if (resolve_mount_spec(&ctx->filesystem_name) < 0 || + !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(_("can't 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/release/src/router/busybox/e2fsprogs/e2fsck.h b/release/src/router/busybox/e2fsprogs/e2fsck.h new file mode 100644 index 0000000000..754d6f1097 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2fsck.h @@ -0,0 +1,637 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ext2fs/kernel-list.h" +#include +#include + +/* + * Now pull in the real linux/jfs.h definitions. + */ +#include "ext2fs/kernel-jbd.h" + + + +#include "fsck.h" + +#include "ext2fs/ext2_fs.h" +#include "volume_id.h" +#include "ext2fs/ext2_ext_attr.h" +#include "e2fs_lib.h" +#include "libbb.h" + +#ifdef HAVE_CONIO_H +#undef HAVE_TERMIOS_H +#include +#define read_a_char() getch() +#else +#ifdef HAVE_TERMIOS_H +#include +#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 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; + + 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/release/src/router/busybox/e2fsprogs/e2p/Kbuild.src b/release/src/router/busybox/e2fsprogs/e2p/Kbuild.src new file mode 100644 index 0000000000..01ac720b94 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2p/Kbuild.src @@ -0,0 +1,18 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +NEEDED-$(CONFIG_CHATTR) = y +NEEDED-$(CONFIG_LSATTR) = y +NEEDED-$(CONFIG_MKE2FS) = y +NEEDED-$(CONFIG_TUNE2FS) = y + +lib-y:= + +INSERT + +lib-$(NEEDED-y) += mntopts.o \ + feature.o ls.o pe.o ostype.o ps.o hashstr.o \ + parse_num.o diff --git a/release/src/router/busybox/e2fsprogs/e2p/e2p.h b/release/src/router/busybox/e2fsprogs/e2p/e2p.h new file mode 100644 index 0000000000..2abb92c8f3 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2p/e2p.h @@ -0,0 +1,41 @@ +/* vi: set sw=4 ts=4: */ +#include "libbb.h" +#include /* Needed by dirent.h on netbsd */ +#include +#include + +#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'. */ + + +/*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_fs_state (FILE *f, unsigned short state); + +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); + +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/release/src/router/busybox/e2fsprogs/e2p/feature.c b/release/src/router/busybox/e2fsprogs/e2p/feature.c new file mode 100644 index 0000000000..2102ed8e76 --- /dev/null +++ b/release/src/router/busybox/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 + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include +#include +#include +#include +#include + +#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_INO, + "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/release/src/router/busybox/e2fsprogs/e2p/fgetsetflags.c b/release/src/router/busybox/e2fsprogs/e2p/fgetsetflags.c new file mode 100644 index 0000000000..008b798504 --- /dev/null +++ b/release/src/router/busybox/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 + * 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 +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_EXT2_IOCTLS +#include +#include +#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/release/src/router/busybox/e2fsprogs/e2p/fgetsetversion.c b/release/src/router/busybox/e2fsprogs/e2p/fgetsetversion.c new file mode 100644 index 0000000000..8d79054d6a --- /dev/null +++ b/release/src/router/busybox/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 + * 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 +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/e2p/hashstr.c b/release/src/router/busybox/e2fsprogs/e2p/hashstr.c new file mode 100644 index 0000000000..697ffadc37 --- /dev/null +++ b/release/src/router/busybox/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 + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include +#include +#include +#include +#include + +#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/release/src/router/busybox/e2fsprogs/e2p/iod.c b/release/src/router/busybox/e2fsprogs/e2p/iod.c new file mode 100644 index 0000000000..23ab8d5b54 --- /dev/null +++ b/release/src/router/busybox/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 + * 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 +#include +#include + +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/release/src/router/busybox/e2fsprogs/e2p/ls.c b/release/src/router/busybox/e2fsprogs/e2p/ls.c new file mode 100644 index 0000000000..4a2ed5ff8d --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2p/ls.c @@ -0,0 +1,274 @@ +/* vi: set sw=4 ts=4: */ +/* + * ls.c - List the contents of an ext2fs superblock + * + * Copyright (C) 1992, 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Copyright (C) 1995, 1996, 1997 Theodore Ts'o + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "e2p.h" +#include "../e2fs_lib.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 ""; + + 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], uuid_buf[37], *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, ""); + 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, ""); + fprintf(f, + "Last mounted on: %s\n" + "Filesystem UUID: %s\n" + "Filesystem magic number: 0x%04X\n" + "Filesystem revision #: %d", + buf, unparse_uuid(sb->s_uuid, uuid_buf), 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 (!uuid_is_null(sb->s_journal_uuid)) + fprintf(f, "Journal UUID: %s\n", + unparse_uuid(sb->s_journal_uuid, uuid_buf)); + 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 (!uuid_is_null(sb->s_hash_seed)) + fprintf(f, "Directory Hash Seed: %s\n", + unparse_uuid((unsigned char *)sb->s_hash_seed, uuid_buf)); + 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/release/src/router/busybox/e2fsprogs/e2p/mntopts.c b/release/src/router/busybox/e2fsprogs/e2p/mntopts.c new file mode 100644 index 0000000000..17c26c480b --- /dev/null +++ b/release/src/router/busybox/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 + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include +#include +#include +#include +#include + +#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/release/src/router/busybox/e2fsprogs/e2p/ostype.c b/release/src/router/busybox/e2fsprogs/e2p/ostype.c new file mode 100644 index 0000000000..6a2f178f33 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2p/ostype.c @@ -0,0 +1,72 @@ +/* vi: set sw=4 ts=4: */ +/* + * getostype.c - Get the Filesystem OS type + * + * Copyright (C) 2004,2005 Theodore Ts'o + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include "e2p.h" +#include +#include + +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/release/src/router/busybox/e2fsprogs/e2p/parse_num.c b/release/src/router/busybox/e2fsprogs/e2p/parse_num.c new file mode 100644 index 0000000000..6db076f9cd --- /dev/null +++ b/release/src/router/busybox/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 + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include "e2p.h" + +#include + +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 +#include + +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/release/src/router/busybox/e2fsprogs/e2p/pe.c b/release/src/router/busybox/e2fsprogs/e2p/pe.c new file mode 100644 index 0000000000..fd96dbeea4 --- /dev/null +++ b/release/src/router/busybox/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 + * 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 + +#include "e2p.h" + +void print_fs_errors(FILE *f, unsigned short errors) +{ + const 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/release/src/router/busybox/e2fsprogs/e2p/pf.c b/release/src/router/busybox/e2fsprogs/e2p/pf.c new file mode 100644 index 0000000000..02cbec7e0f --- /dev/null +++ b/release/src/router/busybox/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 + * 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 + +#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/release/src/router/busybox/e2fsprogs/e2p/ps.c b/release/src/router/busybox/e2fsprogs/e2p/ps.c new file mode 100644 index 0000000000..a6b4099db5 --- /dev/null +++ b/release/src/router/busybox/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 + * 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 + +#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/release/src/router/busybox/e2fsprogs/e2p/uuid.c b/release/src/router/busybox/e2fsprogs/e2p/uuid.c new file mode 100644 index 0000000000..474d64a5a4 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/e2p/uuid.c @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * uuid.c -- utility routines for manipulating UUID's. + */ + +#include +#include +#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 ""; + e2p_uuid_to_str(uu, buf); + return buf; +} diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/Kbuild.src b/release/src/router/busybox/e2fsprogs/ext2fs/Kbuild.src new file mode 100644 index 0000000000..12adc6e469 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/Kbuild.src @@ -0,0 +1,26 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +NEEDED-$(CONFIG_E2FSCK) = y +NEEDED-$(CONFIG_FSCK) = y +NEEDED-$(CONFIG_MKE2FS) = y +NEEDED-$(CONFIG_TUNE2FS) = y + +lib-y:= + +INSERT + +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/release/src/router/busybox/e2fsprogs/ext2fs/alloc.c b/release/src/router/busybox/e2fsprogs/ext2fs/alloc.c new file mode 100644 index 0000000000..cbb63e15a5 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/alloc.c @@ -0,0 +1,173 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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 = NULL; + + 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/release/src/router/busybox/e2fsprogs/ext2fs/alloc_sb.c b/release/src/router/busybox/e2fsprogs/ext2fs/alloc_sb.c new file mode 100644 index 0000000000..a7437c96f5 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/alloc_stats.c b/release/src/router/busybox/e2fsprogs/ext2fs/alloc_stats.c new file mode 100644 index 0000000000..f3ab06a237 --- /dev/null +++ b/release/src/router/busybox/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 + +#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/release/src/router/busybox/e2fsprogs/ext2fs/alloc_tables.c b/release/src/router/busybox/e2fsprogs/ext2fs/alloc_tables.c new file mode 100644 index 0000000000..7c60e2bf5f --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/alloc_tables.c @@ -0,0 +1,114 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/badblocks.c b/release/src/router/busybox/e2fsprogs/ext2fs/badblocks.c new file mode 100644 index 0000000000..6e5cc10b82 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/bb_compat.c b/release/src/router/busybox/e2fsprogs/ext2fs/bb_compat.c new file mode 100644 index 0000000000..419ac77859 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/bb_inode.c b/release/src/router/busybox/e2fsprogs/ext2fs/bb_inode.c new file mode 100644 index 0000000000..a967896181 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/bb_inode.c @@ -0,0 +1,262 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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(NULL); + if (!inode.i_ctime) + inode.i_ctime = time(NULL); + 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/release/src/router/busybox/e2fsprogs/ext2fs/bitmaps.c b/release/src/router/busybox/e2fsprogs/ext2fs/bitmaps.c new file mode 100644 index 0000000000..637ed27af9 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/bitops.c b/release/src/router/busybox/e2fsprogs/ext2fs/bitops.c new file mode 100644 index 0000000000..b4ec51ed7c --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_SYS_TYPES_H +#include +#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 EXT2FS_ATTR((unused)), + 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 EXT2FS_ATTR((unused)), 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/release/src/router/busybox/e2fsprogs/ext2fs/bitops.h b/release/src/router/busybox/e2fsprogs/ext2fs/bitops.h new file mode 100644 index 0000000000..7271a497bf --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/bitops.h @@ -0,0 +1,105 @@ +/* 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 , Copyright 1992, + * Linus Torvalds. + */ +#include + +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/release/src/router/busybox/e2fsprogs/ext2fs/block.c b/release/src/router/busybox/e2fsprogs/ext2fs/block.c new file mode 100644 index 0000000000..dbd04f8469 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/block.c @@ -0,0 +1,437 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/bmap.c b/release/src/router/busybox/e2fsprogs/ext2fs/bmap.c new file mode 100644 index 0000000000..796b0e4f51 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/bmap.c @@ -0,0 +1,261 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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 = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/bmove.c b/release/src/router/busybox/e2fsprogs/ext2fs/bmove.c new file mode 100644 index 0000000000..ec9244d0bc --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/bmove.c @@ -0,0 +1,155 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/brel.h b/release/src/router/busybox/e2fsprogs/ext2fs/brel.h new file mode 100644 index 0000000000..87bf72be45 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/brel.h @@ -0,0 +1,86 @@ +/* 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/release/src/router/busybox/e2fsprogs/ext2fs/brel_ma.c b/release/src/router/busybox/e2fsprogs/ext2fs/brel_ma.c new file mode 100644 index 0000000000..652a3509cb --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/check_desc.c b/release/src/router/busybox/e2fsprogs/ext2fs/check_desc.c new file mode 100644 index 0000000000..dd4b0e9cf5 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/closefs.c b/release/src/router/busybox/e2fsprogs/ext2fs/closefs.c new file mode 100644 index 0000000000..bfa15e22a8 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/closefs.c @@ -0,0 +1,380 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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 = NULL; + struct ext2_group_desc *group_shadow = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/cmp_bitmaps.c b/release/src/router/busybox/e2fsprogs/ext2fs/cmp_bitmaps.c new file mode 100644 index 0000000000..7f78ff8042 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/cmp_bitmaps.c @@ -0,0 +1,72 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/dblist.c b/release/src/router/busybox/e2fsprogs/ext2fs/dblist.c new file mode 100644 index 0000000000..06ff6d8079 --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/dblist_dir.c b/release/src/router/busybox/e2fsprogs/ext2fs/dblist_dir.c new file mode 100644 index 0000000000..b239204664 --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/dir_iterate.c b/release/src/router/busybox/e2fsprogs/ext2fs/dir_iterate.c new file mode 100644 index 0000000000..eb5dae0a64 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/dir_iterate.c @@ -0,0 +1,219 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/dirblock.c b/release/src/router/busybox/e2fsprogs/ext2fs/dirblock.c new file mode 100644 index 0000000000..f9c5a104b0 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/dirblock.c @@ -0,0 +1,132 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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 = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/dirhash.c b/release/src/router/busybox/e2fsprogs/ext2fs/dirhash.c new file mode 100644 index 0000000000..09e34be3b6 --- /dev/null +++ b/release/src/router/busybox/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 +#include + +#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 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/release/src/router/busybox/e2fsprogs/ext2fs/dupfs.c b/release/src/router/busybox/e2fsprogs/ext2fs/dupfs.c new file mode 100644 index 0000000000..d1879377a0 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/dupfs.c @@ -0,0 +1,95 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/e2image.h b/release/src/router/busybox/e2fsprogs/ext2fs/e2image.h new file mode 100644 index 0000000000..a598d01117 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/e2image.h @@ -0,0 +1,39 @@ +/* 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/release/src/router/busybox/e2fsprogs/ext2fs/expanddir.c b/release/src/router/busybox/e2fsprogs/ext2fs/expanddir.c new file mode 100644 index 0000000000..8a29ae5849 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/ext2_err.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_err.h new file mode 100644 index 0000000000..ead352810a --- /dev/null +++ b/release/src/router/busybox/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/release/src/router/busybox/e2fsprogs/ext2fs/ext2_ext_attr.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_ext_attr.h new file mode 100644 index 0000000000..ca309c0d03 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_ext_attr.h @@ -0,0 +1,52 @@ +/* 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, +*/ + +/* 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<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/release/src/router/busybox/e2fsprogs/ext2fs/ext2_fs.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_fs.h new file mode 100644 index 0000000000..80ea2cbddd --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_fs.h @@ -0,0 +1,569 @@ +/* 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 1 + +#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_INO 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 diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/ext2_io.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_io.h new file mode 100644 index 0000000000..1900a76392 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_io.h @@ -0,0 +1,112 @@ +/* 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 1 + +/* + * 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 diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/ext2_types.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_types.h new file mode 100644 index 0000000000..2c1196b8b7 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2_types.h @@ -0,0 +1,2 @@ +/* vi: set sw=4 ts=4: */ +#include diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs.h new file mode 100644 index 0000000000..ffd096f416 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs.h @@ -0,0 +1,926 @@ +/* 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 1 + + +#ifdef __GNUC__ +# define EXT2FS_ATTR(x) __attribute__(x) +#else +# define EXT2FS_ATTR(x) +#endif + +#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 +#endif + +#include +#include + +#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_INO|\ + 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 diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/ext2fsP.h b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fsP.h new file mode 100644 index 0000000000..7a02e9a8e3 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fsP.h @@ -0,0 +1,87 @@ +/* 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/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs_inline.c b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs_inline.c new file mode 100644 index 0000000000..7d37d232d8 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ext2fs_inline.c @@ -0,0 +1,365 @@ +/* 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 + +/* + * 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 = xrealloc(p, size); + 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/release/src/router/busybox/e2fsprogs/ext2fs/ext_attr.c b/release/src/router/busybox/e2fsprogs/ext2fs/ext_attr.c new file mode 100644 index 0000000000..a2ba12d45c --- /dev/null +++ b/release/src/router/busybox/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, + * + * Copyright (C) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#include +#include + +#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 = NULL; + + 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/release/src/router/busybox/e2fsprogs/ext2fs/fileio.c b/release/src/router/busybox/e2fsprogs/ext2fs/fileio.c new file mode 100644 index 0000000000..5a5ad3ef89 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/finddev.c b/release/src/router/busybox/e2fsprogs/ext2fs/finddev.c new file mode 100644 index 0000000000..e9e83fd7ad --- /dev/null +++ b/release/src/router/busybox/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 +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#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 = NULL, *new_list = NULL; + struct dir_list *current; + char *ret_path = NULL; + + /* + * 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/release/src/router/busybox/e2fsprogs/ext2fs/flushb.c b/release/src/router/busybox/e2fsprogs/ext2fs/flushb.c new file mode 100644 index 0000000000..45ed76512d --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_SYS_MOUNT_H +#include +#include /* 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/release/src/router/busybox/e2fsprogs/ext2fs/freefs.c b/release/src/router/busybox/e2fsprogs/ext2fs/freefs.c new file mode 100644 index 0000000000..0c5d48b113 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/freefs.c @@ -0,0 +1,127 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/gen_bitmap.c b/release/src/router/busybox/e2fsprogs/ext2fs/gen_bitmap.c new file mode 100644 index 0000000000..d0869c9191 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/get_pathname.c b/release/src/router/busybox/e2fsprogs/ext2fs/get_pathname.c new file mode 100644 index 0000000000..2bb1cc25ec --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/get_pathname.c @@ -0,0 +1,156 @@ +/* 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 . is the containing + * directory inode, and is the inode number itself. If + * is zero, then ext2fs_get_pathname will return pathname + * of the directory . + * + */ + +#include +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/getsectsize.c b/release/src/router/busybox/e2fsprogs/ext2fs/getsectsize.c new file mode 100644 index 0000000000..163ec65e5b --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_LINUX_FD_H +#include +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/getsize.c b/release/src/router/busybox/e2fsprogs/ext2fs/getsize.c new file mode 100644 index 0000000000..923334facc --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/getsize.c @@ -0,0 +1,292 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif +#ifdef HAVE_SYS_DISK_H +#ifdef HAVE_SYS_QUEUE_H +#include /* for LIST_HEAD */ +#endif +#include +#endif +#ifdef __linux__ +#include +#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 +#include + +#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__ + uname(&ut); + if ((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) { + close(fd); + *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/release/src/router/busybox/e2fsprogs/ext2fs/icount.c b/release/src/router/busybox/e2fsprogs/ext2fs/icount.c new file mode 100644 index 0000000000..7ab5f51f48 --- /dev/null +++ b/release/src/router/busybox/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 +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/imager.c b/release/src/router/busybox/e2fsprogs/ext2fs/imager.c new file mode 100644 index 0000000000..0f9cfcfafb --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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 = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/ind_block.c b/release/src/router/busybox/e2fsprogs/ext2fs/ind_block.c new file mode 100644 index 0000000000..a1038300b3 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ind_block.c @@ -0,0 +1,69 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/initialize.c b/release/src/router/busybox/e2fsprogs/ext2fs/initialize.c new file mode 100644 index 0000000000..da2d151375 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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_INO) + 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/release/src/router/busybox/e2fsprogs/ext2fs/inline.c b/release/src/router/busybox/e2fsprogs/ext2fs/inline.c new file mode 100644 index 0000000000..7457b93962 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/inline.c @@ -0,0 +1,32 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#define INCLUDE_INLINE_FUNCS +#include "ext2fs.h" diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/inode.c b/release/src/router/busybox/e2fsprogs/ext2fs/inode.c new file mode 100644 index 0000000000..7a1d5c94bb --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/inode.c @@ -0,0 +1,766 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/inode_io.c b/release/src/router/busybox/e2fsprogs/ext2fs/inode_io.c new file mode 100644 index 0000000000..b861d5ff69 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/inode_io.c @@ -0,0 +1,270 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/io_manager.c b/release/src/router/busybox/e2fsprogs/ext2fs/io_manager.c new file mode 100644 index 0000000000..b47038602a --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/io_manager.c @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * io_manager.c --- the I/O manager abstraction + */ + +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/irel.h b/release/src/router/busybox/e2fsprogs/ext2fs/irel.h new file mode 100644 index 0000000000..91d1d89d5f --- /dev/null +++ b/release/src/router/busybox/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/release/src/router/busybox/e2fsprogs/ext2fs/irel_ma.c b/release/src/router/busybox/e2fsprogs/ext2fs/irel_ma.c new file mode 100644 index 0000000000..c871b18919 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/ismounted.c b/release/src/router/busybox/e2fsprogs/ext2fs/ismounted.c new file mode 100644 index 0000000000..58dab79b1d --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/ismounted.c @@ -0,0 +1,356 @@ +/* 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 +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#endif +#ifdef HAVE_GETMNTINFO +#include +#include +#include +#endif /* HAVE_GETMNTINFO */ +#include +#include + +#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); + return retval; +#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_for_read("/proc/swaps"))) + 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, "", 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/release/src/router/busybox/e2fsprogs/ext2fs/jfs_dat.h b/release/src/router/busybox/e2fsprogs/ext2fs/jfs_dat.h new file mode 100644 index 0000000000..17c586a29b --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/jfs_dat.h @@ -0,0 +1,63 @@ +/* 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/release/src/router/busybox/e2fsprogs/ext2fs/kernel-jbd.h b/release/src/router/busybox/e2fsprogs/ext2fs/kernel-jbd.h new file mode 100644 index 0000000000..853d97ac7f --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/kernel-jbd.h @@ -0,0 +1,235 @@ +/* vi: set sw=4 ts=4: */ +/* + * linux/include/linux/jbd.h + * + * Written by Stephen C. Tweedie + * + * 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 1 + +#include +#include +#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 diff --git a/release/src/router/busybox/e2fsprogs/ext2fs/kernel-list.h b/release/src/router/busybox/e2fsprogs/ext2fs/kernel-list.h new file mode 100644 index 0000000000..d80716a454 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/kernel-list.h @@ -0,0 +1,113 @@ +/* vi: set sw=4 ts=4: */ +#ifndef LINUX_LIST_H +#define LINUX_LIST_H 1 + +/* + * 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/release/src/router/busybox/e2fsprogs/ext2fs/link.c b/release/src/router/busybox/e2fsprogs/ext2fs/link.c new file mode 100644 index 0000000000..08b2e96738 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/lookup.c b/release/src/router/busybox/e2fsprogs/ext2fs/lookup.c new file mode 100644 index 0000000000..b2e8de8ec5 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/lookup.c @@ -0,0 +1,68 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/mkdir.c b/release/src/router/busybox/e2fsprogs/ext2fs/mkdir.c new file mode 100644 index 0000000000..a86ac8e938 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/mkdir.c @@ -0,0 +1,139 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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 = NULL; + + 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/release/src/router/busybox/e2fsprogs/ext2fs/mkjournal.c b/release/src/router/busybox/e2fsprogs/ext2fs/mkjournal.c new file mode 100644 index 0000000000..748d9abc70 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/mkjournal.c @@ -0,0 +1,426 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#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 = NULL; + 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(NULL); + 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/release/src/router/busybox/e2fsprogs/ext2fs/namei.c b/release/src/router/busybox/e2fsprogs/ext2fs/namei.c new file mode 100644 index 0000000000..18244613c6 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/namei.c @@ -0,0 +1,204 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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 = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/newdir.c b/release/src/router/busybox/e2fsprogs/ext2fs/newdir.c new file mode 100644 index 0000000000..9f156626d8 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/newdir.c @@ -0,0 +1,72 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/openfs.c b/release/src/router/busybox/e2fsprogs/ext2fs/openfs.c new file mode 100644 index 0000000000..1b271196b1 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/read_bb.c b/release/src/router/busybox/e2fsprogs/ext2fs/read_bb.c new file mode 100644 index 0000000000..ce77bc9f6b --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/read_bb.c @@ -0,0 +1,96 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/read_bb_file.c b/release/src/router/busybox/e2fsprogs/ext2fs/read_bb_file.c new file mode 100644 index 0000000000..bf1fc328be --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/read_bb_file.c @@ -0,0 +1,96 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/res_gdt.c b/release/src/router/busybox/e2fsprogs/ext2fs/res_gdt.c new file mode 100644 index 0000000000..403463a90f --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/res_gdt.c @@ -0,0 +1,220 @@ +/* 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 +#include +#include +#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(NULL); + } + + 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(NULL); + 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/release/src/router/busybox/e2fsprogs/ext2fs/rs_bitmap.c b/release/src/router/busybox/e2fsprogs/ext2fs/rs_bitmap.c new file mode 100644 index 0000000000..32e87b77a9 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/rs_bitmap.c @@ -0,0 +1,106 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/rw_bitmaps.c b/release/src/router/busybox/e2fsprogs/ext2fs/rw_bitmaps.c new file mode 100644 index 0000000000..bba4326796 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/rw_bitmaps.c @@ -0,0 +1,294 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#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 = NULL, *inode_bitmap = NULL; + 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/release/src/router/busybox/e2fsprogs/ext2fs/sparse.c b/release/src/router/busybox/e2fsprogs/ext2fs/sparse.c new file mode 100644 index 0000000000..b3d3071e98 --- /dev/null +++ b/release/src/router/busybox/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 + +#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/release/src/router/busybox/e2fsprogs/ext2fs/swapfs.c b/release/src/router/busybox/e2fsprogs/ext2fs/swapfs.c new file mode 100644 index 0000000000..07b757abd2 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/swapfs.c @@ -0,0 +1,234 @@ +/* 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 +#include +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/test_io.c b/release/src/router/busybox/e2fsprogs/ext2fs/test_io.c new file mode 100644 index 0000000000..3d40d9a97f --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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_for_write(value); + 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/release/src/router/busybox/e2fsprogs/ext2fs/unix_io.c b/release/src/router/busybox/e2fsprogs/ext2fs/unix_io.c new file mode 100644 index 0000000000..8dde4c7322 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef __linux__ +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +#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__) && (__WORDSIZE == 32)) || (defined(__mips__) && (_MIPS_SZLONG == 32))) +#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/release/src/router/busybox/e2fsprogs/ext2fs/unlink.c b/release/src/router/busybox/e2fsprogs/ext2fs/unlink.c new file mode 100644 index 0000000000..71a9ffcb9b --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/ext2fs/unlink.c @@ -0,0 +1,99 @@ +/* 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 +#include +#if HAVE_UNISTD_H +#include +#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/release/src/router/busybox/e2fsprogs/ext2fs/valid_blk.c b/release/src/router/busybox/e2fsprogs/ext2fs/valid_blk.c new file mode 100644 index 0000000000..8ed77ae2ac --- /dev/null +++ b/release/src/router/busybox/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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/version.c b/release/src/router/busybox/e2fsprogs/ext2fs/version.c new file mode 100644 index 0000000000..d2981e867e --- /dev/null +++ b/release/src/router/busybox/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 +#endif +#include +#include +#include + +#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/release/src/router/busybox/e2fsprogs/ext2fs/write_bb_file.c b/release/src/router/busybox/e2fsprogs/ext2fs/write_bb_file.c new file mode 100644 index 0000000000..5b19eefa09 --- /dev/null +++ b/release/src/router/busybox/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 + +#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/release/src/router/busybox/e2fsprogs/fsck.c b/release/src/router/busybox/e2fsprogs/fsck.c index a86a9d96f6..3a0743bb12 100644 --- a/release/src/router/busybox/e2fsprogs/fsck.c +++ b/release/src/router/busybox/e2fsprogs/fsck.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * fsck --- A generic, parallelizing front-end for the fsck program. + * 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, @@ -23,126 +23,79 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsck.h" +#include "blkid/blkid.h" + +#include "e2fsbb.h" #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 - -/* fsck 1.41.4 (27-Jan-2009) manpage says: - * 0 - No errors - * 1 - File system errors corrected - * 2 - System should be rebooted - * 4 - File system errors left uncorrected - * 8 - Operational error - * 16 - Usage or syntax error - * 32 - Fsck canceled by user request - * 128 - Shared library error +#ifndef _PATH_MNTTAB +#define _PATH_MNTTAB "/etc/fstab" +#endif + +/* + * fsck.h */ -#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 */ + +#ifndef DEFAULT_FSTYPE +#define DEFAULT_FSTYPE "ext2" +#endif + +#define MAX_DEVICES 32 +#define MAX_ARGS 32 /* - * Internal structure for mount table entries. + * 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; - 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 + int exit_status; time_t start_time; -#endif - char *prog; - char *device; - char *base_device; /* /dev/hda for /dev/hdaN etc */ + char * prog; + char * type; + char * device; + char * base_device; + struct fsck_instance *next; }; -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 **args; -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 smallint noexecute; -static smallint serialize; -static smallint skip_root; -/* static smallint like_mount; */ -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; - /* + * 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 @@ -150,53 +103,57 @@ static struct fsck_instance *instance_list; * * The base_device() function returns an allocated string which must * be freed. + * */ -#if ENABLE_FEATURE_DEVFS + + +#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", NULL + "host", "bus", "target", "lun", 0 }; #endif static char *base_device(const char *device) { char *str, *cp; -#if ENABLE_FEATURE_DEVFS +#ifdef CONFIG_FEATURE_DEVFS const char *const *hier; const char *disk; int len; #endif - str = xstrdup(device); - /* Skip over "/dev/"; if it's not present, give up */ - cp = skip_dev_pfx(str); - if (cp == str) + 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; + *(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])) + if (cp[0] != 'c' || cp[2] != 'd' || + !isdigit(cp[1]) || !isdigit(cp[3])) goto errout; - cp[4] = 0; + *(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') { + 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)) @@ -204,11 +161,11 @@ static char *base_device(const char *device) /* What follows must be an alpha char, or give up */ if (!isalpha(*cp)) goto errout; - cp[1] = 0; + *(cp + 1) = 0; return str; } -#if ENABLE_FEATURE_DEVFS +#ifdef CONFIG_FEATURE_DEVFS /* Now let's handle devfs (ugh) names */ len = 0; if (strncmp(cp, "ide/", 4) == 0) @@ -235,7 +192,7 @@ static char *base_device(const char *device) } cp++; } - cp[-1] = 0; + *(cp - 1) = 0; return str; } @@ -259,35 +216,169 @@ static char *base_device(const char *device) return str; } #endif - errout: + +errout: free(str); return NULL; } -static void free_instance(struct fsck_instance *p) + +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) { - free(p->prog); - free(p->device); - free(p->base_device); - free(p); + 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; + + strcpy_and_process_escape_sequences(word, word); +} + +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 passno) + int freq, int passno) { struct fs_info *fs; - fs = xzalloc(sizeof(*fs)); - fs->device = xstrdup(device); - fs->mountpt = xstrdup(mntpnt); - if (strchr(type, ',')) - type = (char *)"auto"; - fs->type = xstrdup(type); - fs->opts = xstrdup(opts ? opts : ""); - fs->passno = passno < 0 ? 1 : passno; - /*fs->flags = 0; */ - /*fs->next = NULL; */ + fs = xmalloc(sizeof(struct fs_info)); + + 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; @@ -298,29 +389,115 @@ static struct fs_info *create_fs_device(const char *device, const char *mntpnt, return fs; } -/* Load the filesystem database from /etc/fstab */ + + +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 *fstab; - struct mntent mte; + FILE *f; + char buf[1024]; + int lineno = 0; + int old_fstab = 1; struct fs_info *fs; - fstab = setmntent(filename, "r"); - if (!fstab) { - bb_perror_msg("can't read '%s'", filename); + 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); - // Loop through entries - while (getmntent_r(fstab, &mte, bb_common_bufsiz1, COMMON_BUFSIZE)) { - //bb_info_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir, - // mte.mnt_type, mte.mnt_opts, - // mte.mnt_passno); - fs = create_fs_device(mte.mnt_fsname, mte.mnt_dir, - mte.mnt_type, mte.mnt_opts, - mte.mnt_passno); + for (fs = filesys_info; fs; fs = fs->next) { + fs->passno = 1; + } } - endmntent(fstab); } /* Lookup filesys in /etc/fstab and return the corresponding entry. */ @@ -328,17 +505,39 @@ 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) == 0 - || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0) - ) + if (!strcmp(filesys, fs->device) || + (fs->mountpt && !strcmp(filesys, fs->mountpt))) break; } return fs; } -#if DO_PROGRESS_INDICATOR +/* 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; @@ -351,213 +550,248 @@ static int progress_active(void) } return 0; } -#endif +/* + * 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 = xzalloc(sizeof(struct fsck_instance)); + + prog = xasprintf("fsck.%s", type); + argv[0] = prog; + argc = 1; + + for (i=0; i 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("vfork"+1); + 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 void kill_all_if_got_signal(void) +static int kill_all(int signum) { - static smallint kill_sent; - struct fsck_instance *inst; - - if (!bb_got_signal || kill_sent) - return; + int n = 0; for (inst = instance_list; inst; inst = inst->next) { if (inst->flags & FLAG_DONE) continue; - kill(inst->pid, SIGTERM); + kill(inst->pid, signum); + n++; } - kill_sent = 1; + return n; } /* * 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. + * the list of executing child processes, and return it. */ -static int wait_one(int flags) +static struct fsck_instance *wait_one(int flags) { - int status; - int sig; - struct fsck_instance *inst, *prev; - pid_t pid; + int status; + int sig; + struct fsck_instance *inst, *inst2, *prev; + pid_t pid; if (!instance_list) - return -1; - /* if (noexecute) { already returned -1; } */ + 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; - while (1) { + do { pid = waitpid(-1, &status, flags); - kill_all_if_got_signal(); - if (pid == 0) /* flags == WNOHANG and no children exited */ - return -1; + if (cancel_requested && !kill_sent) { + kill_all(SIGTERM); + kill_sent++; + } + if ((pid == 0) && (flags & WNOHANG)) + return NULL; if (pid < 0) { - if (errno == EINTR) + if ((errno == EINTR) || (errno == EAGAIN)) continue; - if (errno == ECHILD) { /* paranoia */ - bb_error_msg("wait: no more children"); - return -1; + if (errno == ECHILD) { + bb_error_msg("wait: no more child process?!?"); + return NULL; } - bb_perror_msg("wait"); + perror("wait"); continue; } - prev = NULL; - inst = instance_list; - do { + for (prev = 0, inst = instance_list; + inst; + prev = inst, inst = inst->next) { if (inst->pid == pid) - goto child_died; - prev = inst; - inst = inst->next; - } while (inst); - } - child_died: + break; + } + } while (!inst); 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); + 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); + 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; + 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") != 0 - && strcmp(inst2->type, "ext3") != 0 - ) { + if (strcmp(inst2->type, "ext2") && + strcmp(inst2->type, "ext3")) 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); + 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; } } -#endif - +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, status); + inst->device, inst->exit_status); num_running--; - free_instance(inst); - - return status; + 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. */ -#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 */) -{ - int i; struct fsck_instance *inst; - pid_t pid; - - args[0] = xasprintf("fsck.%s", type); - -#if DO_PROGRESS_INDICATOR - if (progress && !progress_active()) { - if (strcmp(type, "ext2") == 0 - || strcmp(type, "ext3") == 0 - ) { - args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */ - inst->flags |= FLAG_PROGRESS; - } - } -#endif - - args[num_args - 2] = (char*)device; - /* args[num_args - 1] = NULL; - already is */ - - if (verbose || noexecute) { - printf("[%s (%d) -- %s]", args[0], num_running, - mntpt ? mntpt : device); - for (i = 0; args[i]; i++) - printf(" %s", args[i]); - bb_putchar('\n'); - } - - /* Fork and execute the correct program. */ - pid = -1; - if (!noexecute) { - pid = spawn(args); - if (pid < 0) - bb_simple_perror_msg(args[0]); - } - -#if DO_PROGRESS_INDICATOR - free(args[XXX]); + 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 - - /* No child, so don't record an instance */ - if (pid <= 0) { - free(args[0]); - return; + if (flags & FLAG_WAIT_ATLEAST_ONE) + wait_flags = WNOHANG; } - - inst = xzalloc(sizeof(*inst)); - inst->pid = pid; - inst->prog = args[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; + return global_status; } /* @@ -568,77 +802,104 @@ static void execute(const char *type, const char *device, * 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". + * specified in /etc/fstab, or DEFAULT_FSTYPE. */ -static void fsck_device(struct fs_info *fs /*, int interactive */) +static void fsck_device(struct fs_info *fs, int interactive) { const char *type; + int retval; - if (strcmp(fs->type, "auto") != 0) { + interpret_type(fs); + + 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, ',') - ) { + else if (fstype && strncmp(fstype, "no", 2) && + strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && + !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)"); - } + else + type = DEFAULT_FSTYPE; num_running++; - execute(type, fs->device, fs->mountpt /*, interactive */); + 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--; + } } + /* - * Returns TRUE if a partition on the same disk is already being - * checked. + * Deal with the fsck -t argument. */ -static int device_already_active(char *device) -{ - struct fsck_instance *inst; - char *base; +struct fs_type_compile { + char **list; + int *type; + int negate; +} fs_type_compiled; - if (force_all_parallel) - return 0; +#define FS_TYPE_NORMAL 0 +#define FS_TYPE_OPT 1 +#define FS_TYPE_NEGOPT 2 -#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; +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++; + } } -#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); + cmp->list = xzalloc(num * sizeof(char *)); + cmp->type = xzalloc(num * sizeof(int)); + cmp->negate = 0; - for (inst = instance_list; inst; inst = inst->next) { - if (!inst->base_device || !strcmp(base, inst->base_device)) { - free(base); - return 1; + 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(base); - return 0; + free(list); } /* @@ -647,157 +908,199 @@ static int device_already_active(char *device) */ static int opt_in_list(char *opt, char *optlist) { - char *s; - int len; + char *list, *s; if (!optlist) return 0; + list = string_copy(optlist); - 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; + 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) +static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp) { - int n, ret, checked_type; + int n, ret = 0, checked_type = 0; char *cp; - if (!fs_type_list) + if (cmp->list == 0 || cmp->list[0] == 0) 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: + for (n=0; (cp = cmp->list[n]); n++) { + switch (cmp->type[n]) { + case FS_TYPE_NORMAL: checked_type++; - if (strcmp(cp, fs->type) == 0) + if (strcmp(cp, fs->type) == 0) { ret = 1; + } break; - case FS_TYPE_FLAG_NEGOPT: + case FS_TYPE_NEGOPT: if (opt_in_list(cp, fs->opts)) return 0; break; - case FS_TYPE_FLAG_OPT: + case FS_TYPE_OPT: if (!opt_in_list(cp, fs->opts)) return 0; break; } - n++; } if (checked_type == 0) return 1; - - return (fs_type_negated ? !ret : ret); + 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)) - return 1; + if (!fs_match(fs, &fs_type_compiled)) return 1; /* Are we ignoring this type? */ - if (index_in_strings(ignored_types, fs->type) >= 0) + 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 program is available. */ + s = find_fsck(fs->type); + if (s == NULL) { + if (wanted) + bb_error_msg("can't 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; + struct fs_info *fs = NULL; int status = EXIT_OK; - smallint not_done_yet; - smallint pass_done; - int passno; + int not_done_yet = 1; + int passno = 1; + int pass_done; if (verbose) - puts("Checking all filesystems"); + 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) + 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; + 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 has root - * filesystem listed twice. - * "Skip root" will skip _all_ root entries. + * 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; - 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 (bb_got_signal) + 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 + * than the current pass number, then we don't * do it yet. */ if (fs->passno > passno) { - not_done_yet = 1; + not_done_yet++; continue; } /* @@ -812,7 +1115,7 @@ static int check_all(void) /* * Spawn off the fsck process */ - fsck_device(fs /*, serialize*/); + fsck_device(fs, serialize); fs->flags |= FLAG_DONE; /* @@ -820,14 +1123,13 @@ static int check_all(void) * have a limit on the number of fsck's extant * at one time, apply that limit. */ - if (serialize - || (max_running && (num_running >= max_running)) - ) { + if (serialize || + (max_running && (num_running >= max_running))) { pass_done = 0; break; } } - if (bb_got_signal) + if (cancel_requested) break; if (verbose > 1) printf("--waiting-- (pass %d)\n", passno); @@ -835,250 +1137,240 @@ static int check_all(void) FLAG_WAIT_ATLEAST_ONE); if (pass_done) { if (verbose > 1) - puts("----------------------------------"); + printf("----------------------------------\n"); passno++; } else - not_done_yet = 1; + not_done_yet++; + } + if (cancel_requested && !kill_sent) { + kill_all(SIGTERM); + kill_sent++; } - kill_all_if_got_signal(); 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 char **new_args(void) +static void signal_cancel(int sig FSCK_ATTR((unused))) { - args = xrealloc_vector(args, 2, num_args); - return &args[num_args++]; + cancel_requested++; } -int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int fsck_main(int argc UNUSED_PARAM, char **argv) +static void PRS(int argc, char **argv) { - int i, status; - /*int interactive;*/ - struct fs_info *fs; - const char *fstab; - char *tmp; - char **devices; - int num_devices; - smallint opts_for_fsck; - smallint doall; - smallint notitle; - - /* we want wait() to be interruptible */ - signal_no_SA_RESTART_empty_mask(SIGINT, record_signo); - signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo); + int i, j; + char *arg, *dev, *tmp = NULL; + char options[128]; + int opt = 0; + int opts_for_fsck = 0; + struct sigaction sa; - setbuf(stdout, NULL); + /* + * Set up signal action + */ + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = signal_cancel; + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); - opts_for_fsck = doall = notitle = 0; - devices = NULL; num_devices = 0; - new_args(); /* args[0] = NULL, will be replaced by fsck. */ - /* instance_list = NULL; - in bss, so already zeroed */ - - while (*++argv) { - int j; - int optpos; - char *options; - char *arg = *argv; + num_args = 0; + instance_list = 0; - /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ + for (i=1; i < argc; i++) { + arg = argv[i]; + if (!arg) + continue; 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_vector(devices, 2, num_devices); - devices[num_devices++] = 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("can't 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( + "can't find matching filesystem: %s", arg); + } + devices[num_devices++] = dev ? dev : string_copy(arg); continue; } - if (arg[0] != '-' || opts_for_fsck) { - *new_args() = arg; - continue; - } - - if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */ - opts_for_fsck = 1; + if (num_args >= MAX_ARGS) { + bb_error_msg_and_die("too many arguments"); + } + args[num_args++] = string_copy(arg); continue; } - - optpos = 0; - options = NULL; - for (j = 1; arg[j]; j++) { + for (j=1; arg[j]; j++) { + if (opts_for_fsck) { + options[++opt] = arg[j]; + continue; + } switch (arg[j]) { case 'A': - doall = 1; + doall++; break; -#if DO_PROGRESS_INDICATOR case 'C': - progress = 1; - if (arg[++j]) { /* -Cn */ - progress_fd = xatoi_positive(&arg[j]); - goto next_arg; + 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++; + } } - /* -C n */ - if (!*++argv) - bb_show_usage(); - progress_fd = xatoi_positive(*argv); - goto next_arg; -#endif + break; case 'V': verbose++; break; case 'N': - noexecute = 1; + noexecute++; break; case 'R': - skip_root = 1; + skip_root++; break; case 'T': - notitle = 1; + notitle++; + break; + case 'M': + like_mount++; break; -/* case 'M': - like_mount = 1; - break; */ case 'P': - parallel_root = 1; + parallel_root++; break; case 's': - serialize = 1; + serialize++; break; case 't': + tmp = 0; if (fstype) bb_show_usage(); - if (arg[++j]) - tmp = &arg[j]; - else if (*++argv) - tmp = *argv; + if (arg[j+1]) + tmp = arg+j+1; + else if ((i+1) < argc) + tmp = argv[++i]; else bb_show_usage(); - fstype = xstrdup(tmp); - compile_fs_type(fstype); + 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: - optpos++; - /* one extra for '\0' */ - options = xrealloc(options, optpos + 2); - options[optpos] = arg[j]; + options[++opt] = arg[j]; break; } } - next_arg: - if (optpos) { + next_arg: + if (opt) { options[0] = '-'; - options[optpos + 1] = '\0'; - *new_args() = options; + 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 = 1; - tmp = getenv("FSCK_MAX_INST"); - if (tmp) - max_running = xatoi(tmp); - new_args(); /* args[num_args - 2] will be replaced by */ - new_args(); /* args[num_args - 1] is the last, NULL element */ + 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) - puts("fsck (busybox "BB_VER", "BB_BT")"); + printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); - /* 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"; + fstab = _PATH_MNTTAB; load_fs_info(fstab); - /*interactive = (num_devices == 1) | serialize;*/ + fsck_path = e2fs_set_sbin_path(); - if (num_devices == 0) - /*interactive =*/ serialize = doall = 1; + if ((num_devices == 1) || (serialize)) + interactive = 1; + + /* If -A was specified ("check all"), do that! */ if (doall) return check_all(); - status = 0; + if (num_devices == 0) { + serialize++; + interactive++; + return check_all(); + } for (i = 0; i < num_devices; i++) { - if (bb_got_signal) { - kill_all_if_got_signal(); + if (cancel_requested) { + if (!kill_sent) { + kill_all(SIGTERM); + kill_sent++; + } 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 (!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) - puts("----------------------------------"); + printf("----------------------------------\n"); } } status |= wait_many(FLAG_WAIT_ALL); + blkid_put_cache(cache); return status; } diff --git a/release/src/router/busybox/e2fsprogs/fsck.h b/release/src/router/busybox/e2fsprogs/fsck.h new file mode 100644 index 0000000000..2ca2af7da8 --- /dev/null +++ b/release/src/router/busybox/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/release/src/router/busybox/e2fsprogs/lsattr.c b/release/src/router/busybox/e2fsprogs/lsattr.c index 7d475a9691..9e0e4cb602 100644 --- a/release/src/router/busybox/e2fsprogs/lsattr.c +++ b/release/src/router/busybox/e2fsprogs/lsattr.c @@ -12,38 +12,49 @@ /* * 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) + * 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, -}; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) != 0) + if (fgetflags(name, &fsflags) == -1) goto read_err; - - if (option_mask32 & OPT_GENERATION) { - if (fgetversion(name, &generation) != 0) + if (flags & OPT_GENERATION) { + if (fgetversion(name, &generation) == -1) goto read_err; printf("%5lu ", generation); } - if (option_mask32 & OPT_PF_LONG) { + if (flags & OPT_PF_LONG) { printf("%-28s ", name); print_e2flags(stdout, fsflags, PFOPT_LONG); bb_putchar('\n'); @@ -53,58 +64,66 @@ static void list_attributes(const char *name) } return; - read_err: +read_err: bb_perror_msg("reading %s", name); } -static int FAST_FUNC lsattr_dir_proc(const char *dir_name, - struct dirent *de, - void *private UNUSED_PARAM) +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) != 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'); + 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; -} - -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); - } + return 0; } int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int lsattr_main(int argc UNUSED_PARAM, char **argv) +int lsattr_main(int argc, char **argv) { - getopt32(argv, "Radlv"); - argv += optind; + int i; + + flags = getopt32(argv, "Radlv"); - if (!*argv) - *--argv = (char*)"."; - do lsattr_args(*argv++); while (*argv); + if (optind > argc - 1) + lsattr_args("."); + else + for (i = optind; i < argc; i++) + lsattr_args(argv[i]); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/e2fsprogs/mke2fs.c b/release/src/router/busybox/e2fsprogs/mke2fs.c new file mode 100644 index 0000000000..6d726d8fa4 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/mke2fs.c @@ -0,0 +1,1372 @@ +/* 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. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +/* 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 :-). + */ + +//usage:#define mke2fs_trivial_usage +//usage: "[-c|-l filename] [-b block-size] [-f fragment-size] [-g blocks-per-group] " +//usage: "[-i bytes-per-inode] [-j] [-J journal-options] [-N number-of-inodes] [-n] " +//usage: "[-m reserved-blocks-percentage] [-o creator-os] [-O feature[,...]] [-q] " +//usage: "[r fs-revision-level] [-E extended-options] [-v] [-F] [-L volume-label] " +//usage: "[-M last-mounted-directory] [-S] [-T filesystem-type] " +//usage: "device [blocks-count]" +//usage: +//usage:#define mke2fs_full_usage "\n\n" +//usage: " -b size Block size in bytes" +//usage: "\n -c Check for bad blocks before creating" +//usage: "\n -E opts Set extended options" +//usage: "\n -f size Fragment size in bytes" +//usage: "\n -F Force (ignore sanity checks)" +//usage: "\n -g num Number of blocks in a block group" +//usage: "\n -i ratio The bytes/inode ratio" +//usage: "\n -j Create a journal (ext3)" +//usage: "\n -J opts Set journal options (size/device)" +//usage: "\n -l file Read bad blocks list from file" +//usage: "\n -L lbl Set the volume label" +//usage: "\n -m percent Percent of fs blocks to reserve for admin" +//usage: "\n -M dir Set last mounted directory" +//usage: "\n -n Do not actually create anything" +//usage: "\n -N num Number of inodes to create" +//usage: "\n -o os Set the 'creator os' field" +//usage: "\n -O features Dir_index/filetype/has_journal/journal_dev/sparse_super" +//usage: "\n -q Quiet" +//usage: "\n -r rev Set filesystem revision" +//usage: "\n -S Write superblock and group descriptors only" +//usage: "\n -T fs-type Set usage type (news/largefile/largefile4)" +//usage: "\n -v Verbose" +//usage: +//applet:IF_MKE2FS(APPLET(mke2fs, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_MKE2FS(APPLET_ODDNAME(mkfs.ext2, mke2fs, BB_DIR_SBIN, BB_SUID_DROP, mke2fs)) +//applet:IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, BB_DIR_SBIN, BB_SUID_DROP, mke2fs)) +//applet:IF_MKE2FS(APPLET(tune2fs, BB_DIR_SBIN, BB_SUID_DROP)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_for_read(bad_blocks_file); + 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("can't 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_INO; + + 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=\n" + "\tresize=\n"); + } +} + +static __u32 ok_features[3] = { + EXT3_FEATURE_COMPAT_HAS_JOURNAL | + EXT2_FEATURE_COMPAT_RESIZE_INO | + 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 = NULL; + const char * fs_type = NULL; + 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(¶m, 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_positive(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_positive(optarg); + break; +#endif + case 'N': + num_inodes = xatoi_positive(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, + ¶m.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(¶m), + &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(¶m)) + param.s_blocks_count &= ~((sys_page_size / + EXT2_BLOCK_SIZE(¶m))-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, §or_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, ¶m, blocksize, sector_size, &inode_ratio); + blocksize = EXT2_BLOCK_SIZE(¶m); + + if (extended_opts) + parse_extended_opts(¶m, 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_INO) && + !(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(¶m) || + 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) MAIN_EXTERNALLY_VISIBLE; +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, ¶m, + 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... + */ + generate_uuid(fs->super->s_uuid); + + /* + * Initialize the directory index variables + */ + fs->super->s_def_hash_version = EXT2_HASH_TEA; + generate_uuid((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, "can't 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_INO) { + 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/release/src/router/busybox/e2fsprogs/tune2fs.c b/release/src/router/busybox/e2fsprogs/tune2fs.c dissimilarity index 78% index 9daec542a2..464f18d612 100644 --- a/release/src/router/busybox/e2fsprogs/tune2fs.c +++ b/release/src/router/busybox/e2fsprogs/tune2fs.c @@ -1,100 +1,727 @@ -/* vi: set sw=4 ts=4: */ -/* - * tune2fs: utility to modify EXT2 filesystem - * - * Busybox'ed (2009) by Vladimir Dronnikov - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -#include "libbb.h" -#include -#include - -// storage helpers -char BUG_wrong_field_size(void); -#define STORE_LE(field, value) \ -do { \ - if (sizeof(field) == 4) \ - field = SWAP_LE32(value); \ - else if (sizeof(field) == 2) \ - field = SWAP_LE16(value); \ - else if (sizeof(field) == 1) \ - field = (value); \ - else \ - BUG_wrong_field_size(); \ -} while (0) - -#define FETCH_LE32(field) \ - (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size()) - -//usage:#define tune2fs_trivial_usage -//usage: "[-c MOUNT_CNT] " -////usage: "[-e errors-behavior] [-g group] " -//usage: "[-i DAYS] " -////usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] " -////usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " -////usage: "[-r reserved-blocks-count] [-u user] [-C mount-count] " -//usage: "[-L LABEL] " -////usage: "[-M last-mounted-dir] [-O [^]feature[,...]] " -////usage: "[-T last-check-time] [-U UUID] " -//usage: "BLOCKDEV" -//usage: -//usage:#define tune2fs_full_usage "\n\n" -//usage: "Adjust filesystem options on ext[23] filesystems" - -enum { - OPT_L = 1 << 0, // label - OPT_c = 1 << 1, // max mount count - OPT_i = 1 << 2, // check interval -}; - -int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int tune2fs_main(int argc UNUSED_PARAM, char **argv) -{ - unsigned opts; - const char *label, *str_c, *str_i; - struct ext2_super_block *sb; - int fd; - - opt_complementary = "=1"; - opts = getopt32(argv, "L:c:i:", &label, &str_c, &str_i); - if (!opts) - bb_show_usage(); - argv += optind; // argv[0] -- device - - // read superblock - fd = xopen(argv[0], O_RDWR); - xlseek(fd, 1024, SEEK_SET); - sb = xzalloc(1024); - xread(fd, sb, 1024); - - // mangle superblock - //STORE_LE(sb->s_wtime, time(NULL)); - why bother? - - // set the label - if (opts & OPT_L) - safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name)); - - if (opts & OPT_c) { - int n = xatoi_range(str_c, -1, 0xfffe); - if (n == 0) - n = -1; - STORE_LE(sb->s_max_mnt_count, (unsigned)n); - } - - if (opts & OPT_i) { - unsigned n = xatou_range(str_i, 0, (unsigned)0xffffffff / (24*60*60)) * 24*60*60; - STORE_LE(sb->s_checkinterval, n); - } - - // write superblock - xlseek(fd, 1024, SEEK_SET); - xwrite(fd, sb, 1024); - - if (ENABLE_FEATURE_CLEAN_UP) { - free(sb); - } - - xclose(fd); - return EXIT_SUCCESS; -} +/* 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 + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//usage:#define tune2fs_trivial_usage +//usage: "[-c MOUNT_CNT] " +//usage: "[-e errors-behavior] [-g group] " +//usage: "[-i DAYS] " +//usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] " +//usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " +//usage: "[-r reserved-blocks-count] [-u user] [-C mount-count] " +//usage: "[-L LABEL] " +//usage: "[-M last-mounted-dir] [-O [^]feature[,...]] " +//usage: "[-T last-check-time] [-U UUID] " +//usage: "BLOCKDEV" +//usage: +//usage:#define tune2fs_full_usage "\n\n" +//usage: "Adjust filesystem options on ext[23] filesystems" + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "e2fsbb.h" +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" +#include "e2fs_lib.h" +#include "e2p/e2p.h" +#include "ext2fs/kernel-jbd.h" +#include "util.h" +#include "volume_id.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 */ + + unparse_uuid(fs->super->s_journal_uuid, buf); + journal_path = get_devname_from_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; + const char *msg = "to read"; + const 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)) + generate_uuid((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 = (char *)token; + + if (resolve_mount_spec(&dev_name) != 1 || !dev_name) + 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("can't 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("can't 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) { + generate_uuid(sb->s_uuid); + } else if (parse_uuid(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/release/src/router/busybox/e2fsprogs/util.c b/release/src/router/busybox/e2fsprogs/util.c new file mode 100644 index 0000000000..ca1837bcb6 --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/util.c @@ -0,0 +1,264 @@ +/* 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. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include +#include +#include +#include +#include + +#include "e2fsbb.h" +#include "e2p/e2p.h" +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" +#include "volume_id.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("can't 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 UNUSED_PARAM) +{ + errcode_t retval; + int mount_flags; + + retval = ext2fs_check_if_mounted(device, &mount_flags); + if (retval) { + bb_error_msg("can't 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 = arg; + if (resolve_mount_spec(journal_device) < 0 || + !(*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=\n" + "\tdevice=\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("can't 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("can't 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 = (char *)PATH_SET; + putenv(oldpath); + return oldpath; +} diff --git a/release/src/router/busybox/e2fsprogs/util.h b/release/src/router/busybox/e2fsprogs/util.h new file mode 100644 index 0000000000..80d2417185 --- /dev/null +++ b/release/src/router/busybox/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/release/src/router/busybox/e2fsprogs/uuid/Kbuild.src b/release/src/router/busybox/e2fsprogs/uuid/Kbuild.src new file mode 100644 index 0000000000..b8c687d30c --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/uuid/Kbuild.src @@ -0,0 +1,16 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +NEEDED-$(CONFIG_E2FSCK) = y +NEEDED-$(CONFIG_FSCK) = y +NEEDED-$(CONFIG_MKE2FS) = y +NEEDED-$(CONFIG_TUNE2FS) = y + +lib-y:= + +INSERT +lib-$(NEEDED-y) += compare.o gen_uuid.o pack.o parse.o unpack.o unparse.o \ + uuid_time.o diff --git a/release/src/router/busybox/e2fsprogs/uuid/compare.c b/release/src/router/busybox/e2fsprogs/uuid/compare.c new file mode 100644 index 0000000000..348ea7c1f9 --- /dev/null +++ b/release/src/router/busybox/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 + +#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/release/src/router/busybox/e2fsprogs/uuid/gen_uuid.c b/release/src/router/busybox/e2fsprogs/uuid/gen_uuid.c new file mode 100644 index 0000000000..4310c17db9 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NET_IF_DL_H +#include +#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_IFNAMSIZ(ifr.ifr_name, ifrp->ifr_name); +#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/release/src/router/busybox/e2fsprogs/uuid/pack.c b/release/src/router/busybox/e2fsprogs/uuid/pack.c new file mode 100644 index 0000000000..217cfce5d7 --- /dev/null +++ b/release/src/router/busybox/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 +#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/release/src/router/busybox/e2fsprogs/uuid/parse.c b/release/src/router/busybox/e2fsprogs/uuid/parse.c new file mode 100644 index 0000000000..9a3f9cb921 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#include + +#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/release/src/router/busybox/e2fsprogs/uuid/unpack.c b/release/src/router/busybox/e2fsprogs/uuid/unpack.c new file mode 100644 index 0000000000..95d3aab4a2 --- /dev/null +++ b/release/src/router/busybox/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 +#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/release/src/router/busybox/e2fsprogs/uuid/unparse.c b/release/src/router/busybox/e2fsprogs/uuid/unparse.c new file mode 100644 index 0000000000..d2948fe6dc --- /dev/null +++ b/release/src/router/busybox/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 + +#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/release/src/router/busybox/e2fsprogs/uuid/uuid.h b/release/src/router/busybox/e2fsprogs/uuid/uuid.h new file mode 100644 index 0000000000..7a9706449b --- /dev/null +++ b/release/src/router/busybox/e2fsprogs/uuid/uuid.h @@ -0,0 +1,103 @@ +/* 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 1 + +#include +#include + +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 UNUSED_PARAM = {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/release/src/router/busybox/e2fsprogs/uuid/uuidP.h b/release/src/router/busybox/e2fsprogs/uuid/uuidP.h new file mode 100644 index 0000000000..87041ef0a2 --- /dev/null +++ b/release/src/router/busybox/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 +#include + +#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/release/src/router/busybox/e2fsprogs/uuid/uuid_time.c b/release/src/router/busybox/e2fsprogs/uuid/uuid_time.c new file mode 100644 index 0000000000..b6f73e6dc9 --- /dev/null +++ b/release/src/router/busybox/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 +#include +#include +#include +#include + +#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/release/src/router/busybox/editors/Config.src b/release/src/router/busybox/editors/Config.src dissimilarity index 65% index 201ee6eb9b..af1e1de5eb 100644 --- a/release/src/router/busybox/editors/Config.src +++ b/release/src/router/busybox/editors/Config.src @@ -1,195 +1,78 @@ -# -# For a description of the syntax of this configuration file, -# see scripts/kbuild/config-language.txt. -# - -menu "Editors" - -INSERT - -config AWK - bool "awk" - default y - help - Awk is used as a pattern scanning and processing language. This is - the BusyBox implementation of that programming language. - -config FEATURE_AWK_LIBM - 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 y - help - cmp is used to compare two files and returns the result - to standard output. - -config DIFF - bool "diff" - default y - 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_LONG_OPTIONS - bool "Enable long options" - default y - depends on DIFF && LONG_OPTS - help - Enable use of long options. - -config FEATURE_DIFF_DIR - bool "Enable directory support" - default y - depends on DIFF - help - This option enables support for directory and subdirectory - comparison. - -config ED - bool "ed" - default y - 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 SED - bool "sed" - default y - help - sed is used to perform text transformations on a file - or input from a pipeline. - -config VI - bool "vi" - default y - help - 'vi' is a text editor. More specifically, it is the One True - text editor . 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 n - 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_ASK_TERMINAL - bool "Use 'tell me cursor position' ESC sequence to measure window" - default y - depends on VI - help - If terminal size can't be retrieved and $LINES/$COLUMNS are not set, - this option makes vi perform a last-ditch effort to find it: - vi positions cursor to 999,999 and asks terminal to report real - cursor position using "ESC [ 6 n" escape sequence, then reads stdin. - - This is not clean but helps a lot on serial lines and such. - -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 +# +# For a description of the syntax of this configuration file, +# see scripts/kbuild/config-language.txt. +# + +menu "Editors" + +INSERT + +config AWK + bool "awk" + default y + help + Awk is used as a pattern scanning and processing language. This is + the BusyBox implementation of that programming language. + +config FEATURE_AWK_LIBM + 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 y + help + cmp is used to compare two files and returns the result + to standard output. + +config DIFF + bool "diff" + default y + 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_LONG_OPTIONS + bool "Enable long options" + default y + depends on DIFF && LONG_OPTS + help + Enable use of long options. + +config FEATURE_DIFF_DIR + bool "Enable directory support" + default y + depends on DIFF + help + This option enables support for directory and subdirectory + comparison. + +config ED + bool "ed" + default y + 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 SED + bool "sed" + default y + help + sed is used to perform text transformations on a file + or input from a pipeline. + +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/release/src/router/busybox/editors/Kbuild.src b/release/src/router/busybox/editors/Kbuild.src index 2f23ae12fa..8888cba126 100644 --- a/release/src/router/busybox/editors/Kbuild.src +++ b/release/src/router/busybox/editors/Kbuild.src @@ -12,4 +12,3 @@ lib-$(CONFIG_CMP) += cmp.o lib-$(CONFIG_DIFF) += diff.o lib-$(CONFIG_ED) += ed.o lib-$(CONFIG_SED) += sed.o -lib-$(CONFIG_VI) += vi.o diff --git a/release/src/router/busybox/editors/awk.c b/release/src/router/busybox/editors/awk.c index 2eeb9d77aa..71abca215a 100644 --- a/release/src/router/busybox/editors/awk.c +++ b/release/src/router/busybox/editors/awk.c @@ -7,6 +7,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define awk_trivial_usage +//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..." +//usage:#define awk_full_usage "\n\n" +//usage: " -v VAR=VAL Set variable" +//usage: "\n -F SEP Use SEP as field separator" +//usage: "\n -f FILE Read program from FILE" + #include "libbb.h" #include "xregex.h" #include @@ -18,6 +25,7 @@ * to perform debug printfs to stderr: */ #define debug_printf_walker(...) do {} while (0) #define debug_printf_eval(...) do {} while (0) +#define debug_printf_parse(...) do {} while (0) #ifndef debug_printf_walker # define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) @@ -25,6 +33,9 @@ #ifndef debug_printf_eval # define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) #endif +#ifndef debug_printf_parse +# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) +#endif @@ -231,6 +242,9 @@ typedef struct tsplitter_s { * 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 */ +#undef P +#undef PRIMASK +#undef PRIMASK2 #define P(x) (x << 24) #define PRIMASK 0x7F000000 #define PRIMASK2 0x7E000000 @@ -425,13 +439,13 @@ struct globals { smallint nextrec; smallint nextfile; smallint is_f0_split; + smallint t_rollback; }; 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 */ @@ -489,11 +503,11 @@ struct globals2 { #define nextrec (G1.nextrec ) #define nextfile (G1.nextfile ) #define is_f0_split (G1.is_f0_split ) +#define t_rollback (G1.t_rollback ) #define t_info (G.t_info ) #define t_tclass (G.t_tclass ) #define t_string (G.t_string ) #define t_lineno (G.t_lineno ) -#define t_rollback (G.t_rollback ) #define intvar (G.intvar ) #define fsplitter (G.fsplitter ) #define rsplitter (G.rsplitter ) @@ -1001,6 +1015,7 @@ static uint32_t next_token(uint32_t expected) if (*p == '\0') { tc = TC_EOF; + debug_printf_parse("%s: token found: TC_EOF\n", __func__); } else if (*p == '\"') { /* it's a string */ @@ -1016,6 +1031,7 @@ static uint32_t next_token(uint32_t expected) p++; *s = '\0'; tc = TC_STRING; + debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string); } else if ((expected & TC_REGEXP) && *p == '/') { /* it's regexp */ @@ -1038,6 +1054,7 @@ static uint32_t next_token(uint32_t expected) p++; *s = '\0'; tc = TC_REGEXP; + debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string); } else if (*p == '.' || isdigit(*p)) { /* it's a number */ @@ -1047,6 +1064,7 @@ static uint32_t next_token(uint32_t expected) if (*p == '.') syntax_error(EMSG_UNEXP_TOKEN); tc = TC_NUMBER; + debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double); } else { /* search for something known */ @@ -1069,6 +1087,7 @@ static uint32_t next_token(uint32_t expected) ) { /* then this is what we are looking for */ t_info = *ti; + debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info); p += l; goto token_found; } @@ -1092,14 +1111,17 @@ static uint32_t next_token(uint32_t expected) p = skip_spaces(p); if (*p == '(') { tc = TC_FUNCTION; + debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string); } else { if (*p == '[') { p++; tc = TC_ARRAY; - } + debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string); + } else + debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string); } - token_found: ; } + token_found: g_pos = p; /* skipping newlines in some cases */ @@ -1171,6 +1193,8 @@ static node *parse_expr(uint32_t iexp) uint32_t tc, xtc; var *v; + debug_printf_parse("%s(%x)\n", __func__, iexp); + sn.info = PRIMASK; sn.r.n = glptr = NULL; xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; @@ -1179,12 +1203,14 @@ static node *parse_expr(uint32_t iexp) if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { /* input redirection (<) attached to glptr node */ + debug_printf_parse("%s: input redir\n", __func__); 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)) { + debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); /* for binary and postfix-unary operators, jump back over * previous operators with higher priority */ vn = cn; @@ -1214,6 +1240,7 @@ static node *parse_expr(uint32_t iexp) vn->a.n = cn; } else { + debug_printf_parse("%s: other\n", __func__); /* for operands and prefix-unary operators, attach them * to last node */ vn = cn; @@ -1221,12 +1248,14 @@ static node *parse_expr(uint32_t iexp) cn->a.n = vn; xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; if (tc & (TC_OPERAND | TC_REGEXP)) { + debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); 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: + debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); cn->info = OC_VAR; v = hash_search(ahash, t_string); if (v != NULL) { @@ -1243,6 +1272,7 @@ static node *parse_expr(uint32_t iexp) case TC_NUMBER: case TC_STRING: + debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); cn->info = OC_VAR; v = cn->l.v = xzalloc(sizeof(var)); if (tc & TC_NUMBER) @@ -1252,32 +1282,41 @@ static node *parse_expr(uint32_t iexp) break; case TC_REGEXP: + debug_printf_parse("%s: TC_REGEXP\n", __func__); mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); break; case TC_FUNCTION: + debug_printf_parse("%s: TC_FUNCTION\n", __func__); cn->info = OC_FUNC; cn->r.f = newfunc(t_string); cn->l.n = condition(); break; case TC_SEQSTART: + debug_printf_parse("%s: TC_SEQSTART\n", __func__); cn = vn->r.n = parse_expr(TC_SEQTERM); + if (!cn) + syntax_error("Empty sequence"); cn->a.n = vn; break; case TC_GETLINE: + debug_printf_parse("%s: TC_GETLINE\n", __func__); glptr = cn; xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; break; case TC_BUILTIN: + debug_printf_parse("%s: TC_BUILTIN\n", __func__); cn->l.n = condition(); break; } } } } + + debug_printf_parse("%s() returns %p\n", __func__, sn.r.n); return sn.r.n; } @@ -1346,18 +1385,25 @@ static void chain_group(void) } while (c & TC_NEWLINE); if (c & TC_GRPSTART) { + debug_printf_parse("%s: TC_GRPSTART\n", __func__); while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { + debug_printf_parse("%s: !TC_GRPTERM\n", __func__); if (t_tclass & TC_NEWLINE) continue; rollback_token(); chain_group(); } + debug_printf_parse("%s: TC_GRPTERM\n", __func__); } else if (c & (TC_OPSEQ | TC_OPTERM)) { + debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__); rollback_token(); chain_expr(OC_EXEC | Vx); - } else { /* TC_STATEMNT */ + } else { + /* TC_STATEMNT */ + debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__); switch (t_info & OPCLSMASK) { case ST_IF: + debug_printf_parse("%s: ST_IF\n", __func__); n = chain_node(OC_BR | Vx); n->l.n = condition(); chain_group(); @@ -1372,12 +1418,14 @@ static void chain_group(void) break; case ST_WHILE: + debug_printf_parse("%s: ST_WHILE\n", __func__); n2 = condition(); n = chain_loop(NULL); n->l.n = n2; break; case ST_DO: + debug_printf_parse("%s: ST_DO\n", __func__); n2 = chain_node(OC_EXEC); n = chain_loop(NULL); n2->a.n = n->a.n; @@ -1386,6 +1434,7 @@ static void chain_group(void) break; case ST_FOR: + debug_printf_parse("%s: ST_FOR\n", __func__); next_token(TC_SEQSTART); n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); if (t_tclass & TC_SEQTERM) { /* for-in */ @@ -1411,6 +1460,7 @@ static void chain_group(void) case OC_PRINT: case OC_PRINTF: + debug_printf_parse("%s: OC_PRINT[F]\n", __func__); n = chain_node(t_info); n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); if (t_tclass & TC_OUTRDR) { @@ -1422,17 +1472,20 @@ static void chain_group(void) break; case OC_BREAK: + debug_printf_parse("%s: OC_BREAK\n", __func__); n = chain_node(OC_EXEC); n->a.n = break_ptr; break; case OC_CONTINUE: + debug_printf_parse("%s: OC_CONTINUE\n", __func__); n = chain_node(OC_EXEC); n->a.n = continue_ptr; break; /* delete, next, nextfile, return, exit */ default: + debug_printf_parse("%s: default\n", __func__); chain_expr(t_info); } } @@ -1450,19 +1503,24 @@ static void parse_program(char *p) while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { - if (tclass & TC_OPTERM) + if (tclass & TC_OPTERM) { + debug_printf_parse("%s: TC_OPTERM\n", __func__); continue; + } seq = &mainseq; if (tclass & TC_BEGIN) { + debug_printf_parse("%s: TC_BEGIN\n", __func__); seq = &beginseq; chain_group(); } else if (tclass & TC_END) { + debug_printf_parse("%s: TC_END\n", __func__); seq = &endseq; chain_group(); } else if (tclass & TC_FUNCDECL) { + debug_printf_parse("%s: TC_FUNCDECL\n", __func__); next_token(TC_FUNCTION); g_pos++; f = newfunc(t_string); @@ -1480,22 +1538,27 @@ static void parse_program(char *p) clear_array(ahash); } else if (tclass & TC_OPSEQ) { + debug_printf_parse("%s: TC_OPSEQ\n", __func__); rollback_token(); cn = chain_node(OC_TEST); cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); if (t_tclass & TC_GRPSTART) { + debug_printf_parse("%s: TC_GRPSTART\n", __func__); rollback_token(); chain_group(); } else { + debug_printf_parse("%s: !TC_GRPSTART\n", __func__); chain_node(OC_PRINT); } cn->r.n = mainseq.last; } else /* if (tclass & TC_GRPSTART) */ { + debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__); rollback_token(); chain_group(); } } + debug_printf_parse("%s: TC_EOF\n", __func__); } @@ -2620,7 +2683,7 @@ static var *evaluate(node *op, var *res) rsm = iF; } - if (!rsm->F) { + if (!rsm || !rsm->F) { setvar_i(intvar[ERRNO], errno); setvar_i(res, -1); break; @@ -2954,7 +3017,7 @@ 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; + FILE *F; const char *fname, *ind; if (rsm.F) @@ -2962,19 +3025,21 @@ static rstream *next_input_file(void) rsm.F = NULL; rsm.pos = rsm.adv = 0; - do { + for (;;) { 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); + break; } - } while (!F); + ind = getvar_s(incvar(intvar[ARGIND])); + fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); + if (fname && *fname && !is_assignment(fname)) { + F = xfopen_stdin(fname); + break; + } + } files_happen = TRUE; setvar_s(intvar[FILENAME], fname); @@ -2988,7 +3053,7 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int awk_main(int argc, char **argv) { unsigned opt; - char *opt_F, *opt_W; + char *opt_F; llist_t *list_v = NULL; llist_t *list_f = NULL; int i, j; @@ -3050,7 +3115,7 @@ int awk_main(int argc, char **argv) } } 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); + opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); argv += optind; argc -= optind; if (opt & 0x1) @@ -3084,7 +3149,7 @@ int awk_main(int argc, char **argv) parse_program(*argv++); } if (opt & 0x8) // -W - bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); + bb_error_msg("warning: option -W is ignored"); /* fill in ARGV array */ setvar_i(intvar[ARGC], argc); diff --git a/release/src/router/busybox/editors/cmp.c b/release/src/router/busybox/editors/cmp.c index f84a56e3e6..fbe6b97538 100644 --- a/release/src/router/busybox/editors/cmp.c +++ b/release/src/router/busybox/editors/cmp.c @@ -10,6 +10,14 @@ /* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ +//usage:#define cmp_trivial_usage +//usage: "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" +//usage:#define cmp_full_usage "\n\n" +//usage: "Compare FILE1 with FILE2 (or stdin)\n" +//usage: "\n -l Write the byte numbers (decimal) and values (octal)" +//usage: "\n for all differing bytes" +//usage: "\n -s Quiet" + #include "libbb.h" static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n"; diff --git a/release/src/router/busybox/editors/diff.c b/release/src/router/busybox/editors/diff.c index cc7ba472e0..3a33346402 100644 --- a/release/src/router/busybox/editors/diff.c +++ b/release/src/router/busybox/editors/diff.c @@ -76,12 +76,33 @@ * 6n words for files of length n. */ +//usage:#define diff_trivial_usage +//usage: "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" +//usage:#define diff_full_usage "\n\n" +//usage: "Compare files line by line and output the differences between them.\n" +//usage: "This implementation supports unified diffs only.\n" +//usage: "\n -a Treat all files as text" +//usage: "\n -b Ignore changes in the amount of whitespace" +//usage: "\n -B Ignore changes whose lines are all blank" +//usage: "\n -d Try hard to find a smaller set of changes" +//usage: "\n -i Ignore case differences" +//usage: "\n -L Use LABEL instead of the filename in the unified header" +//usage: "\n -N Treat absent files as empty" +//usage: "\n -q Output only whether files differ" +//usage: "\n -r Recurse" +//usage: "\n -S Start with FILE when comparing directories" +//usage: "\n -T Make tabs line up by prefixing a tab when necessary" +//usage: "\n -s Report when two files are the same" +//usage: "\n -t Expand tabs to spaces in output" +//usage: "\n -U Output LINES lines of context" +//usage: "\n -w Ignore all whitespace" + #include "libbb.h" #if 0 -//#define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) #else -#define dbg_error_msg(...) ((void)0) +# define dbg_error_msg(...) ((void)0) #endif enum { /* print_status() and diffreg() return values */ @@ -672,10 +693,12 @@ static bool diff(FILE* fp[2], char *file[2]) static int diffreg(char *file[2]) { - FILE *fp[2] = { stdin, stdin }; + FILE *fp[2]; bool binary = false, differ = false; int status = STATUS_SAME, i; + fp[0] = stdin; + fp[1] = stdin; for (i = 0; i < 2; i++) { int fd = open_or_warn_stdin(file[i]); if (fd == -1) @@ -794,7 +817,9 @@ static int FAST_FUNC skip_dir(const char *filename, free(othername); if (r != 0 || !S_ISDIR(osb.st_mode)) { /* other dir doesn't have similarly named - * directory, don't recurse */ + * directory, don't recurse; return 1 upon + * exit, just like diffutils' diff */ + exit_status |= 1; return SKIP; } } @@ -846,9 +871,10 @@ static void diffdir(char *p[2], const char *s_start) break; pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1])); k = pos > 0; - if (pos && !(option_mask32 & FLAG(N))) + if (pos && !(option_mask32 & FLAG(N))) { printf("Only in %s: %s\n", p[k], dp[k]); - else { + exit_status |= 1; + } else { char *fullpath[2], *path[2]; /* if -N */ for (i = 0; i < 2; i++) { @@ -949,6 +975,31 @@ int diff_main(int argc UNUSED_PARAM, char **argv) if (gotstdin && (S_ISDIR(stb[0].st_mode) || S_ISDIR(stb[1].st_mode))) bb_error_msg_and_die("can't compare stdin to a directory"); + /* Compare metadata to check if the files are the same physical file. + * + * Comment from diffutils source says: + * POSIX says that two files are identical if st_ino and st_dev are + * the same, but many file systems incorrectly assign the same (device, + * inode) pair to two distinct files, including: + * GNU/Linux NFS servers that export all local file systems as a + * single NFS file system, if a local device number (st_dev) exceeds + * 255, or if a local inode number (st_ino) exceeds 16777215. + */ + if (ENABLE_DESKTOP + && stb[0].st_ino == stb[1].st_ino + && stb[0].st_dev == stb[1].st_dev + && stb[0].st_size == stb[1].st_size + && stb[0].st_mtime == stb[1].st_mtime + && stb[0].st_ctime == stb[1].st_ctime + && stb[0].st_mode == stb[1].st_mode + && stb[0].st_nlink == stb[1].st_nlink + && stb[0].st_uid == stb[1].st_uid + && stb[0].st_gid == stb[1].st_gid + ) { + /* files are physically the same; no need to compare them */ + return STATUS_SAME; + } + if (S_ISDIR(stb[0].st_mode) && S_ISDIR(stb[1].st_mode)) { #if ENABLE_FEATURE_DIFF_DIR diffdir(file, s_start); diff --git a/release/src/router/busybox/editors/ed.c b/release/src/router/busybox/editors/ed.c index 859668406f..dbb51306cc 100644 --- a/release/src/router/busybox/editors/ed.c +++ b/release/src/router/busybox/editors/ed.c @@ -7,6 +7,9 @@ * The "ed" built-in command (much simplified) */ +//usage:#define ed_trivial_usage "" +//usage:#define ed_full_usage "" + #include "libbb.h" typedef struct LINE { @@ -129,7 +132,7 @@ static void doCommands(void) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(": ", buf, sizeof(buf), NULL); + len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) return; endbuf = &buf[len - 1]; @@ -227,7 +230,7 @@ static void doCommands(void) } if (!dirty) return; - len = read_line_input("Really quit? ", buf, 16, NULL); + len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); /* read error/EOF - no way to continue */ if (len < 0) return; @@ -451,7 +454,7 @@ static void subCommand(const char *cmd, int num1, int num2) /* * The new string is larger, so allocate a new line - * structure and use that. Link it in in place of + * structure and use that. Link it in place of * the old line structure. */ nlp = xmalloc(sizeof(LINE) + lp->len + deltaLen); @@ -541,7 +544,7 @@ static void addLines(int num) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input("", buf, sizeof(buf), NULL); + len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) { /* Previously, ctrl-C was exiting to shell. * Now we exit to ed prompt. Is in important? */ diff --git a/release/src/router/busybox/editors/patch.c b/release/src/router/busybox/editors/patch.c index 1d4a2554e6..13785ef460 100644 --- a/release/src/router/busybox/editors/patch.c +++ b/release/src/router/busybox/editors/patch.c @@ -15,22 +15,23 @@ * -D define wrap #ifdef and #ifndef around changes * -o outfile output here instead of in place * -r rejectfile write rejected hunks to this file + * --dry-run (regression!) * * -f force (no questions asked) * -F fuzz (number, default 2) * [file] which file to patch */ -//applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - -//kbuild:lib-$(CONFIG_PATCH) += patch.o - //config:config PATCH //config: bool "patch" //config: default y //config: help //config: Apply a unified diff formatted patch. +//applet:IF_PATCH(APPLET(patch, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PATCH) += patch.o + //usage:#define patch_trivial_usage //usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" //usage:#define patch_full_usage "\n\n" @@ -39,7 +40,7 @@ //usage: "\n -i,--input DIFF Read DIFF instead of stdin" //usage: "\n -R,--reverse Reverse patch" //usage: "\n -N,--forward Ignore already applied patches" -//usage: "\n --dry-run Don't actually change files" +/*usage: "\n --dry-run Don't actually change files" - TODO */ //usage: "\n -E,--remove-empty-files Remove output files if they become empty" //usage: ) //usage: IF_NOT_LONG_OPTS( @@ -49,6 +50,8 @@ //usage: "\n -N Ignore already applied patches" //usage: "\n -E Remove output files if they become empty" //usage: ) +/* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ +/* -x "debug" is supported but does nothing */ //usage: //usage:#define patch_example_usage //usage: "$ patch -p1 < example.diff\n" @@ -67,8 +70,7 @@ struct double_list { // Free all the elements of a linked list // Call freeit() on each element before freeing it. -static -void dlist_free(struct double_list *list, void (*freeit)(void *data)) +static void dlist_free(struct double_list *list, void (*freeit)(void *data)) { while (list) { void *pop = list; @@ -80,8 +82,7 @@ void dlist_free(struct double_list *list, void (*freeit)(void *data)) } // Add an entry before "list" element in (circular) doubly linked list -static -struct double_list *dlist_add(struct double_list **list, char *data) +static struct double_list *dlist_add(struct double_list **list, char *data) { struct double_list *llist; struct double_list *line = xmalloc(sizeof(*line)); @@ -130,8 +131,8 @@ struct globals { #define FLAG_INPUT (1 << 3) #define FLAG_IGNORE (1 << 4) #define FLAG_RMEMPTY (1 << 5) -//non-standard: -#define FLAG_DEBUG (1 << 6) +/* Enable this bit and use -x for debug output: */ +#define FLAG_DEBUG (0 << 6) // Dispose of a line of input, either by writing it out or discarding it. @@ -229,7 +230,7 @@ static int apply_one_hunk(void) else matcheof = 0; if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); } - matcheof = matcheof < TT.context; + matcheof = !matcheof || matcheof < TT.context; if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); @@ -238,8 +239,8 @@ static int apply_one_hunk(void) // complete hunk. plist = TT.current_hunk; buf = NULL; - if (TT.context) for (;;) { - char *data = xmalloc_reads(TT.filein, NULL, NULL); + if (reverse ? TT.oldlen : TT.newlen) for (;;) { + char *data = xmalloc_reads(TT.filein, NULL); TT.linenum++; @@ -352,6 +353,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int reverse, state = 0; char *oldname = NULL, *newname = NULL; char *opt_p, *opt_i; + long oldlen = oldlen; /* for compiler */ + long newlen = newlen; /* for compiler */ INIT_TT(); @@ -391,8 +394,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) if (*patchline==' ' || *patchline=='+' || *patchline=='-') { dlist_add(&TT.current_hunk, patchline); - if (*patchline != '+') TT.oldlen--; - if (*patchline != '-') TT.newlen--; + if (*patchline != '+') oldlen--; + if (*patchline != '-') newlen--; // Context line? if (*patchline==' ' && state==2) TT.context++; @@ -400,7 +403,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // If we've consumed all expected hunk lines, apply the hunk. - if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); + if (!oldlen && !newlen) state = apply_one_hunk(); continue; } fail_hunk(); @@ -447,11 +450,14 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // Read oldline[,oldlen] +newline[,newlen] - TT.oldlen = TT.newlen = 1; + TT.oldlen = oldlen = TT.newlen = newlen = 1; TT.oldline = strtol(s, &s, 10); - if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); + if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); TT.newline = strtol(s+2, &s, 10); - if (*s == ',') TT.newlen = strtol(s+1, &s, 10); + if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); + + if (oldlen < 1 && newlen < 1) + bb_error_msg_and_die("Really? %s", patchline); TT.context = 0; state = 2; @@ -461,26 +467,28 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int oldsum, newsum, empty = 0; char *name; - oldsum = TT.oldline + TT.oldlen; - newsum = TT.newline + TT.newlen; + oldsum = TT.oldline + oldlen; + newsum = TT.newline + newlen; name = reverse ? oldname : newname; // We're deleting oldname if new file is /dev/null (before -p) // or if new hunk is empty (zero context) after patching - if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) - { + if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { name = reverse ? newname : oldname; empty++; } // handle -p path truncation. - for (i=0, s = name; *s;) { - if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; - if (*(s++)=='/') { - name = s; - i++; - } + for (i = 0, s = name; *s;) { + if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) + break; + if (*s++ != '/') + continue; + while (*s == '/') + s++; + i++; + name = s; } if (empty) { diff --git a/release/src/router/busybox/editors/sed.c b/release/src/router/busybox/editors/sed.c index b91acfb7f4..3ee8edc433 100644 --- a/release/src/router/busybox/editors/sed.c +++ b/release/src/router/busybox/editors/sed.c @@ -14,53 +14,75 @@ */ /* 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. + */ - 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 +/* 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 + */ - Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html -*/ +//usage:#define sed_trivial_usage +//usage: "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n" +//usage: "or: sed [-inr] CMD [FILE]..." +//usage:#define sed_full_usage "\n\n" +//usage: " -e CMD Add CMD to sed commands to be executed" +//usage: "\n -f FILE Add FILE contents to sed commands to be executed" +//usage: "\n -i Edit files in-place (else sends result to stdout)" +//usage: "\n -n Suppress automatic printing of pattern space" +//usage: "\n -r Use extended regex syntax" +//usage: "\n" +//usage: "\nIf no -e or -f, the first non-option argument is the sed command string." +//usage: "\nRemaining arguments are input files (stdin if none)." +//usage: +//usage:#define sed_example_usage +//usage: "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" +//usage: "bar\n" #include "libbb.h" #include "xregex.h" +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + + enum { OPT_in_place = 1 << 0, }; @@ -75,6 +97,7 @@ typedef struct sed_cmd_s { 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 beg_line_orig; /* copy of the above, needed for -i */ int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ FILE *sw_file; /* File (sw) command writes to, -1 for none. */ @@ -109,7 +132,7 @@ struct globals { regex_t *previous_regex_ptr; /* linked list of sed commands */ - sed_cmd_t sed_cmd_head, *sed_cmd_tail; + sed_cmd_t *sed_cmd_head, **sed_cmd_tail; /* Linked list of append lines */ llist_t *append_head; @@ -124,7 +147,7 @@ struct globals { } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; #define INIT_G() do { \ G.sed_cmd_tail = &G.sed_cmd_head; \ @@ -134,7 +157,7 @@ struct BUG_G_too_big { #if ENABLE_FEATURE_CLEAN_UP static void sed_free_and_close_stuff(void) { - sed_cmd_t *sed_cmd = G.sed_cmd_head.next; + sed_cmd_t *sed_cmd = G.sed_cmd_head; llist_free(G.append_head, free); @@ -200,11 +223,16 @@ static void parse_escapes(char *dest, const char *string, int len, char from, ch static char *copy_parsing_escapes(const char *string, int len) { + const char *s; 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'); + /* sed recognizes \n */ + /* GNU sed also recognizes \t and \r */ + for (s = "\nn\tt\rr"; *s; s += 2) { + parse_escapes(dest, string, len, s[1], s[0]); + string = dest; + len = strlen(dest); + } return dest; } @@ -227,11 +255,13 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) delimiter = -delimiter; } - for (; (ch = str[idx]); idx++) { + for (; (ch = str[idx]) != '\0'; idx++) { if (bracket >= 0) { - if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2 - && str[idx - 1] == '^'))) + if (ch == ']' + && !(bracket == idx - 1 || (bracket == idx - 2 && str[idx - 1] == '^')) + ) { bracket = -1; + } } else if (escaped) escaped = 0; else if (ch == '\\') @@ -252,7 +282,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) static int parse_regex_delim(const char *cmdstr, char **match, char **replace) { const char *cmdstr_ptr = cmdstr; - char delimiter; + unsigned char delimiter; int idx = 0; /* verify that the 's' or 'y' is followed by something. That something @@ -267,7 +297,7 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) /* save the replacement string */ cmdstr_ptr += idx + 1; - idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); + idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); *replace = copy_parsing_escapes(cmdstr_ptr, idx); return ((cmdstr_ptr - cmdstr) + idx); @@ -292,10 +322,11 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) char *temp; delimiter = '/'; - if (*my_str == '\\') delimiter = *++pos; + 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)); + *regex = xzalloc(sizeof(regex_t)); xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); free(temp); /* Move position to next character after last delimiter */ @@ -404,8 +435,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) /* 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)); + sed_cmd->sub_match = xzalloc(sizeof(regex_t)); + dbg("xregcomp('%s',%x)", match, cflags); xregcomp(sed_cmd->sub_match, match, cflags); + dbg("regcomp ok"); } free(match); @@ -417,11 +450,47 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) */ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) { + static const char cmd_letters[] = "saicrw:btTydDgGhHlnNpPqx={}"; + enum { + IDX_s = 0, + IDX_a, + IDX_i, + IDX_c, + IDX_r, + IDX_w, + IDX_colon, + IDX_b, + IDX_t, + IDX_T, + IDX_y, + IDX_d, + IDX_D, + IDX_g, + IDX_G, + IDX_h, + IDX_H, + IDX_l, + IDX_n, + IDX_N, + IDX_p, + IDX_P, + IDX_q, + IDX_x, + IDX_equal, + IDX_lbrace, + IDX_rbrace, + IDX_nul + }; + struct chk { char chk[sizeof(cmd_letters)-1 == IDX_nul ? 1 : -1]; }; + + unsigned idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters; + /* handle (s)ubstitution command */ - if (sed_cmd->cmd == 's') + if (idx == IDX_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)) { + else if (idx <= IDX_c) { /* a,i,c */ 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 (;;) { @@ -437,8 +506,9 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *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)) { + else if (idx <= IDX_w) { /* r,w */ 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); @@ -446,8 +516,9 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); sed_cmd->sw_last_char = '\n'; } + } /* handle branch commands */ - } else if (strchr(":btT", sed_cmd->cmd)) { + else if (idx <= IDX_T) { /* :,b,t,T */ int length; cmdstr = skip_whitespace(cmdstr); @@ -458,7 +529,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) } } /* translation command */ - else if (sed_cmd->cmd == 'y') { + else if (idx == IDX_y) { char *match, *replace; int i = cmdstr[0]; @@ -478,7 +549,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) /* 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) { + else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */ bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd); } @@ -540,6 +611,7 @@ static void add_cmd(const char *cmdstr) /* 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); + sed_cmd->beg_line_orig = sed_cmd->beg_line; /* second part (if present) will begin with a comma */ if (*cmdstr == ',') { @@ -571,8 +643,8 @@ static void add_cmd(const char *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; + *G.sed_cmd_tail = sed_cmd; + G.sed_cmd_tail = &sed_cmd->next; } /* If we glued multiple lines together, free the memory. */ @@ -648,8 +720,12 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) G.previous_regex_ptr = current_regex; /* Find the first match */ - if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) + dbg("matching '%s'", line); + if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { + dbg("no match"); return 0; + } + dbg("match"); /* Initialize temporary output buffer. */ G.pipeline.buf = xmalloc(PIPE_GROW); @@ -661,12 +737,13 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) 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' */ + * 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(*line++); - continue; + goto next; } match_count++; @@ -678,7 +755,7 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) ) { for (i = 0; i < G.regmatch[0].rm_eo; i++) pipe_putc(*line++); - continue; + goto next; } /* print everything before the match */ @@ -694,11 +771,14 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) altered++; /* if we're not doing this globally, get out now */ - if (sed_cmd->which_match) + if (sed_cmd->which_match != 0) + break; + next: + if (*line == '\0') break; //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? - } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); + } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); /* Copy rest of string into output pipeline */ while (1) { @@ -718,7 +798,7 @@ 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) { + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) { return sed_cmd; } @@ -894,24 +974,24 @@ static void process_files(void) /* For every line, go through all the commands */ restart: - for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { int old_matched, matched; old_matched = sed_cmd->in_match; /* Determine if this command matches this line: */ - //bb_error_msg("match1:%d", sed_cmd->in_match); - //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line - // && !sed_cmd->beg_match && !sed_cmd->end_match)); - //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 - // && (sed_cmd->end_line || sed_cmd->end_match - // ? (sed_cmd->beg_line <= linenum) - // : (sed_cmd->beg_line == linenum) - // ) - // ) - //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); - //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); + dbg("match1:%d", sed_cmd->in_match); + dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line + && !sed_cmd->beg_match && !sed_cmd->end_match)); + dbg("match3:%d", (sed_cmd->beg_line > 0 + && (sed_cmd->end_line || sed_cmd->end_match + ? (sed_cmd->beg_line <= linenum) + : (sed_cmd->beg_line == linenum) + ) + )); + dbg("match4:%d", (beg_match(sed_cmd, pattern_space))); + dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); /* Are we continuing a previous multi-line match? */ sed_cmd->in_match = sed_cmd->in_match @@ -922,7 +1002,14 @@ static void process_files(void) || (sed_cmd->beg_line > 0 && (sed_cmd->end_line || sed_cmd->end_match /* note: even if end is numeric and is < linenum too, - * GNU sed matches! We match too */ + * GNU sed matches! We match too, therefore we don't + * check here that linenum <= end. + * Example: + * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p' + * first three input lines are deleted; + * 4th line is matched and printed + * by "2,3" (!) and by "4" ranges + */ ? (sed_cmd->beg_line <= linenum) /* N,end */ : (sed_cmd->beg_line == linenum) /* N */ ) @@ -935,30 +1022,29 @@ static void process_files(void) /* Snapshot the value */ matched = sed_cmd->in_match; - //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", - //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); + dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", + sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); /* Is this line the end of the current match? */ if (matched) { /* once matched, "n,xxx" range is dead, disabling it */ - if (sed_cmd->beg_line > 0 - && !(option_mask32 & OPT_in_place) /* but not for -i */ - ) { + if (sed_cmd->beg_line > 0) { sed_cmd->beg_line = -2; } 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 + ? 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)) + pattern_space, 0, NULL, 0) == 0) + ) ); } @@ -992,8 +1078,8 @@ static void process_files(void) } /* actual sedding */ - //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", - //pattern_space, next_line, sed_cmd->cmd); + dbg("pattern_space:'%s' next_line:'%s' cmd:%c", + pattern_space, next_line, sed_cmd->cmd); switch (sed_cmd->cmd) { /* Print line number */ @@ -1040,6 +1126,7 @@ static void process_files(void) case 's': if (!do_subst_command(sed_cmd, &pattern_space)) break; + dbg("do_subst_command succeeeded:'%s'", pattern_space); substituted |= 1; /* handle p option */ @@ -1348,11 +1435,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv) add_input_file(stdin); } else { int i; - FILE *file; for (i = 0; argv[i]; i++) { struct stat statbuf; int nonstdoutfd; + FILE *file; + sed_cmd_t *sed_cmd; if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { add_input_file(stdin); @@ -1364,11 +1452,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv) status = EXIT_FAILURE; continue; } + add_input_file(file); if (!(opt & OPT_in_place)) { - add_input_file(file); continue; } + /* -i: process each FILE separately: */ + G.outname = xasprintf("%sXXXXXX", argv[i]); nonstdoutfd = xmkstemp(G.outname); G.nonstdout = xfdopen_for_write(nonstdoutfd); @@ -1379,15 +1469,20 @@ int sed_main(int argc UNUSED_PARAM, char **argv) * but GNU sed 4.2.1 does not preserve them either */ fchmod(nonstdoutfd, statbuf.st_mode); fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); - 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; + + /* Re-enable disabled range matches */ + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { + sed_cmd->beg_line = sed_cmd->beg_line_orig; + } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: * if (G.current_input_file >= G.input_file_count) diff --git a/release/src/router/busybox/editors/vi.c b/release/src/router/busybox/editors/vi.c index eebf6946f4..b4ad12e5c9 100644 --- a/release/src/router/busybox/editors/vi.c +++ b/release/src/router/busybox/editors/vi.c @@ -21,7 +21,151 @@ * An "ex" line oriented mode- maybe using "cmdedit" */ +//config:config VI +//config: bool "vi" +//config: default y +//config: help +//config: 'vi' is a text editor. More specifically, it is the One True +//config: text editor . It does, however, have a rather steep +//config: learning curve. If you are not already comfortable with 'vi' +//config: you may wish to use something else. +//config: +//config:config FEATURE_VI_MAX_LEN +//config: int "Maximum screen width in vi" +//config: range 256 16384 +//config: default 4096 +//config: depends on VI +//config: help +//config: Contrary to what you may think, this is not eating much. +//config: Make it smaller than 4k only if you are very limited on memory. +//config: +//config:config FEATURE_VI_8BIT +//config: bool "Allow vi to display 8-bit chars (otherwise shows dots)" +//config: default n +//config: depends on VI +//config: help +//config: If your terminal can display characters with high bit set, +//config: you may want to enable this. Note: vi is not Unicode-capable. +//config: If your terminal combines several 8-bit bytes into one character +//config: (as in Unicode mode), this will not work properly. +//config: +//config:config FEATURE_VI_COLON +//config: bool "Enable \":\" colon commands (no \"ex\" mode)" +//config: default y +//config: depends on VI +//config: help +//config: Enable a limited set of colon commands for vi. This does not +//config: provide an "ex" mode. +//config: +//config:config FEATURE_VI_YANKMARK +//config: bool "Enable yank/put commands and mark cmds" +//config: default y +//config: depends on VI +//config: help +//config: This will enable you to use yank and put, as well as mark in +//config: busybox vi. +//config: +//config:config FEATURE_VI_SEARCH +//config: bool "Enable search and replace cmds" +//config: default y +//config: depends on VI +//config: help +//config: Select this if you wish to be able to do search and replace in +//config: busybox vi. +//config: +//config:config FEATURE_VI_REGEX_SEARCH +//config: bool "Enable regex in search and replace" +//config: default n # Uses GNU regex, which may be unavailable. FIXME +//config: depends on FEATURE_VI_SEARCH +//config: help +//config: Use extended regex search. +//config: +//config:config FEATURE_VI_USE_SIGNALS +//config: bool "Catch signals" +//config: default y +//config: depends on VI +//config: help +//config: Selecting this option will make busybox vi signal aware. This will +//config: make busybox vi support SIGWINCH to deal with Window Changes, catch +//config: Ctrl-Z and Ctrl-C and alarms. +//config: +//config:config FEATURE_VI_DOT_CMD +//config: bool "Remember previous cmd and \".\" cmd" +//config: default y +//config: depends on VI +//config: help +//config: Make busybox vi remember the last command and be able to repeat it. +//config: +//config:config FEATURE_VI_READONLY +//config: bool "Enable -R option and \"view\" mode" +//config: default y +//config: depends on VI +//config: help +//config: Enable the read-only command line option, which allows the user to +//config: open a file in read-only mode. +//config: +//config:config FEATURE_VI_SETOPTS +//config: bool "Enable set-able options, ai ic showmatch" +//config: default y +//config: depends on VI +//config: help +//config: Enable the editor to set some (ai, ic, showmatch) options. +//config: +//config:config FEATURE_VI_SET +//config: bool "Support for :set" +//config: default y +//config: depends on VI +//config: help +//config: Support for ":set". +//config: +//config:config FEATURE_VI_WIN_RESIZE +//config: bool "Handle window resize" +//config: default y +//config: depends on VI +//config: help +//config: Make busybox vi behave nicely with terminals that get resized. +//config: +//config:config FEATURE_VI_ASK_TERMINAL +//config: bool "Use 'tell me cursor position' ESC sequence to measure window" +//config: default y +//config: depends on VI +//config: help +//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, +//config: this option makes vi perform a last-ditch effort to find it: +//config: position cursor to 999,999 and ask terminal to report real +//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. +//config: +//config: This is not clean but helps a lot on serial lines and such. +//config: +//config:config FEATURE_VI_OPTIMIZE_CURSOR +//config: bool "Optimize cursor movement" +//config: default y +//config: depends on VI +//config: help +//config: This will make the cursor movement faster, but requires more memory +//config: and it makes the applet a tiny bit larger. + +//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_VI) += vi.o + +//usage:#define vi_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define vi_full_usage "\n\n" +//usage: "Edit FILE\n" +//usage: IF_FEATURE_VI_COLON( +//usage: "\n -c Initial command to run ($EXINIT also available)" +//usage: ) +//usage: IF_FEATURE_VI_READONLY( +//usage: "\n -R Read-only" +//usage: ) +//usage: "\n -H Short help regarding available features" + #include "libbb.h" +/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ +#if ENABLE_FEATURE_VI_REGEX_SEARCH +# include +#endif /* the CRASHME code is unmaintained, and doesn't currently build */ #define ENABLE_FEATURE_VI_CRASHME 0 @@ -40,9 +184,9 @@ /* 0x9b is Meta-ESC */ #if ENABLE_FEATURE_VI_8BIT -#define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) +# define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) #else -#define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) +# define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) #endif #endif @@ -134,7 +278,6 @@ struct globals { 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 @@ -219,7 +362,6 @@ struct globals { #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 ) @@ -354,7 +496,6 @@ 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 @@ -456,9 +597,10 @@ int vi_main(int argc, char **argv) } // 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 + argv += optind; + argc -= optind; save_argc = argc; + optind = 0; //----- This is the main file handling loop -------------- while (1) { @@ -523,7 +665,6 @@ static void edit_file(char *fn) #define cur_line edit_file__cur_line #endif int c; - int size; #if ENABLE_FEATURE_VI_USE_SIGNALS int sig; #endif @@ -532,7 +673,6 @@ static void edit_file(char *fn) rawmode(); rows = 24; columns = 80; - size = 0; IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); #if ENABLE_FEATURE_VI_ASK_TERMINAL if (G.get_rowcol_error /* TODO? && no input on stdin */) { @@ -880,7 +1020,7 @@ static void colon(char *buf) } else if (strncmp(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)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } if (args[0]) { @@ -899,13 +1039,13 @@ static void colon(char *buf) goto ret; #if ENABLE_FEATURE_VI_YANKMARK - if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { + if (Ureg >= 0 && Ureg < 28) { free(reg[Ureg]); // free orig line reg- for 'U' - reg[Ureg]= 0; + reg[Ureg] = NULL; } - if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { + if (YDreg >= 0 && YDreg < 28) { free(reg[YDreg]); // free default yank/delete register - reg[YDreg]= 0; + reg[YDreg] = NULL; } #endif // how many lines in text[]? @@ -970,11 +1110,12 @@ static void colon(char *buf) Hit_Return(); } else if (strncmp(cmd, "quit", i) == 0 // quit || strncmp(cmd, "next", i) == 0 // edit next file + || strncmp(cmd, "prev", i) == 0 // edit previous file ) { int n; if (useforce) { - // force end of argv list if (*cmd == 'q') { + // force end of argv list optind = save_argc; } editing = 0; @@ -982,8 +1123,7 @@ static void colon(char *buf) } // 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")); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } // are there other file to edit @@ -996,6 +1136,14 @@ static void colon(char *buf) status_line_bold("No more files to edit"); goto ret; } + if (*cmd == 'p') { + // are there previous files to edit + if (optind < 1) { + status_line_bold("No previous files to edit"); + goto ret; + } + optind -= 2; + } editing = 0; } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] fn = args; @@ -1031,10 +1179,10 @@ static void colon(char *buf) } } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args if (file_modified && !useforce) { - status_line_bold("No write since last change (:rewind! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); } else { // reset the filenames to edit - optind = fn_start - 1; + optind = -1; /* start from 0th file */ editing = 0; } #if ENABLE_FEATURE_VI_SET @@ -1084,51 +1232,53 @@ static void colon(char *buf) #endif /* FEATURE_VI_SET */ #if ENABLE_FEATURE_VI_SEARCH } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern - char *ls, *F, *R; - int gflag; + char *F, *R, *flags; + size_t len_F, len_R; + int gflag; // global replace flag // F points to the "find" pattern // R points to the "replace" pattern - // replace the cmd line delimiters "/" with NULLs - gflag = 0; // global replace flag + // replace the cmd line delimiters "/" with NULs 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; + len_F = R - F; *R++ = '\0'; // terminate "find" - buf1 = strchr(R, c); - if (!buf1) + flags = strchr(R, c); + if (!flags) goto colon_s_fail; - *buf1++ = '\0'; // terminate "replace" - if (*buf1 == 'g') { // :s/foo/bar/g - buf1++; - gflag++; // turn on gflag - } + len_R = flags - R; + *flags++ = '\0'; // terminate "replace" + gflag = *flags; + 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 + 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 + char *ls = q; // orig line start + char *found; vc4: - buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" - if (buf1) { + found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" + if (found) { uintptr_t bias; // we found the "find" pattern - delete it - text_hole_delete(buf1, buf1 + strlen(F) - 1); + text_hole_delete(found, found + len_F - 1); // inset the "replace" patern - bias = string_insert(buf1, R); // insert the string - buf1 += bias; + bias = string_insert(found, R); // insert the string + found += bias; ls += bias; /*q += bias; - recalculated anyway */ // check for "global" :s/foo/bar/g - if (gflag == 1) { - if ((buf1 + strlen(R)) < end_line(ls)) { - q = buf1 + strlen(R); + if (gflag == 'g') { + if ((found + len_R) < end_line(ls)) { + q = found + len_R; goto vc4; // don't let q move past cur line } } @@ -1551,48 +1701,16 @@ static char *new_screen(int ro, int co) } #if ENABLE_FEATURE_VI_SEARCH -static int mycmp(const char *s1, const char *s2, int len) -{ - if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { - return strncasecmp(s1, s2, len); - } - return strncmp(s1, s2, len); -} + +# if ENABLE_FEATURE_VI_REGEX_SEARCH // 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; + int size; re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; preg.translate = 0; @@ -1615,7 +1733,7 @@ static char *char_search(char *p, const char *pat, int dir, int range) // RANGE could be negative if we are searching backwards range = q - p; - q = re_compile_pattern(pat, strlen(pat), &preg); + q = (char *)re_compile_pattern(pat, strlen(pat), (struct re_pattern_buffer *)&preg); if (q != 0) { // The pattern was not compiled status_line_bold("bad search pattern: \"%s\": %s", pat, q); @@ -1649,8 +1767,53 @@ static char *char_search(char *p, const char *pat, int dir, int range) p = p - i; } return p; -#endif /* REGEX_SEARCH */ } + +# else + +# if ENABLE_FEATURE_VI_SETOPTS +static int mycmp(const char *s1, const char *s2, int len) +{ + if (ignorecase) { + return strncasecmp(s1, s2, len); + } + return strncmp(s1, s2, len); +} +# else +# define mycmp strncmp +# endif + +static char *char_search(char *p, const char *pat, int dir, int range) +{ + 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; +} + +# endif + #endif /* FEATURE_VI_SEARCH */ static char *char_insert(char *p, char c) // insert the char c at 'p' @@ -1677,12 +1840,16 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' p = text_hole_delete(p, p); // shrink buffer 1 char } } else { +#if ENABLE_FEATURE_VI_SETOPTS // insert a char into text[] char *sp; // "save p" +#endif if (c == 13) c = '\n'; // translate \r to \n +#if ENABLE_FEATURE_VI_SETOPTS sp = p; // remember addr of insert +#endif p += 1 + stupid_insert(p, c); // insert the char #if ENABLE_FEATURE_VI_SETOPTS if (showmatch && strchr(")]}", *sp) != NULL) { @@ -1915,6 +2082,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte dot += bias; end += bias; p += bias; +#if ENABLE_FEATURE_VI_YANKMARK + { + int i; + for (i = 0; i < ARRAY_SIZE(mark); i++) + if (mark[i]) + mark[i] += bias; + } +#endif text = new_text; } memmove(p + size, p, end - size - p); @@ -2008,8 +2183,8 @@ static void show_help(void) "\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" + //not implemented: "\n\tReadonly if vi is called as \"view\"" + //redundant: usage text says this too: "\n\tReadonly with -R command line arg" #endif #if ENABLE_FEATURE_VI_SET "\n\tSome colon mode commands with \':\'" @@ -2146,7 +2321,7 @@ 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_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; @@ -2389,12 +2564,12 @@ static int file_write(char *fn, char *first, char *last) * but instead ftruncate() it _after_ successful write. * Might reduce amount of data lost on power fail etc. */ - fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0666); // zzz + 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); buggy for us - zzz */ + ftruncate(fd, charcnt); if (charcnt == cnt) { // good write //file_modified = FALSE; @@ -2905,7 +3080,6 @@ static void refresh(int full_screen) //----- Execute a Vi Command ----------------------------------- static void do_cmd(int c) { - const char *msg = msg; // for compiler char *p, *q, *save_dot; char buf[12]; int dir; @@ -2914,8 +3088,8 @@ static void do_cmd(int c) // c1 = c; // quiet the compiler // cnt = yf = 0; // quiet the compiler -// msg = p = q = save_dot = buf; // quiet the compiler - memset(buf, '\0', 12); +// p = q = save_dot = buf; // quiet the compiler + memset(buf, '\0', sizeof(buf)); show_status_line(); @@ -3031,19 +3205,18 @@ static void do_cmd(int c) case KEYCODE_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 > 0) { - do_cmd(c); - } - dot_left(); + do { + dot_left(); + } while (--cmdcnt > 0); break; case 10: // Newline ^J case 'j': // j- goto next line, same col case KEYCODE_DOWN: // cursor key Down - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); // go to next B-o-l - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_next(); // go to next B-o-l + // try stay in same col + dot = move_to_col(dot, ccol + offset); + } while (--cmdcnt > 0); break; case 12: // ctrl-L force redraw whole screen case 18: // ctrl-R force redraw @@ -3056,11 +3229,10 @@ static void do_cmd(int c) break; case 13: // Carriage Return ^M case '+': // +- goto next line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); - dot_skip_over_ws(); + do { + dot_next(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; case 21: // ctrl-U scroll up half screen dot_scroll((rows - 2) / 2, -1); @@ -3078,10 +3250,9 @@ static void do_cmd(int c) case ' ': // move right case 'l': // move right case KEYCODE_RIGHT: // Cursor Key Right - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_right(); + do { + dot_right(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_YANKMARK case '"': // "- name a register to use for Delete/Yank @@ -3151,7 +3322,7 @@ static void do_cmd(int c) end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version - if (reg[Ureg] != 0) { + if (reg[Ureg] != NULL) { p = begin_line(dot); q = end_line(dot); p = text_hole_delete(p, q); // delete cur line @@ -3163,11 +3334,12 @@ static void do_cmd(int c) #endif /* FEATURE_VI_YANKMARK */ case '$': // $- goto end of line case KEYCODE_END: // Cursor Key End - if (--cmdcnt > 0) { + for (;;) { + dot = end_line(dot); + if (--cmdcnt <= 0) + break; dot_next(); - do_cmd(c); } - dot = end_line(dot); break; case '%': // %- find matching char of pair () [] {} for (q = dot; q < end && *q != '\n'; q++) { @@ -3192,38 +3364,35 @@ static void do_cmd(int c) // //**** fall through to ... ';' case ';': // ;- look at rest of line for last forward char - if (--cmdcnt > 0) { - do_cmd(';'); - } - 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; + do { + 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; + } while (--cmdcnt > 0); break; case ',': // repeat latest 'f' in opposite direction - if (--cmdcnt > 0) { - do_cmd(','); - } 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; + do { + q = dot - 1; + while (q >= text && *q != '\n' && *q != last_forward_char) { + q--; + } + if (q >= text && *q == last_forward_char) + dot = q; + } while (--cmdcnt > 0); break; case '-': // -- goto prev line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot_skip_over_ws(); + do { + dot_prev(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_DOT_CMD case '.': // .- repeat the last modifying command @@ -3242,7 +3411,7 @@ static void do_cmd(int c) buf[1] = '\0'; q = get_input_line(buf); // get input line- use "status line" if (q[0] && !q[1]) { - if (last_search_pattern) + if (last_search_pattern[0]) last_search_pattern[0] = c; goto dc3; // if no pat re-use old pat } @@ -3255,13 +3424,6 @@ static void do_cmd(int c) // user changed mind and erased the "/"- do nothing break; case 'N': // N- backward search for last pattern - if (--cmdcnt > 0) { - do_cmd(c); - } - if (last_search_pattern == 0) { - msg = "No previous regular expression"; - goto dc2; - } dir = BACK; // assume BACKWARD search p = dot - 1; if (last_search_pattern[0] == '?') { @@ -3273,41 +3435,41 @@ static void do_cmd(int c) 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 > 0) { - do_cmd(c); - } + do { + const char *msg; dc3: - dir = FORWARD; // assume FORWARD search - p = dot + 1; - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } + 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"; + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { + dot = q; // good search, update "dot" + msg = NULL; + goto dc2; + } + // no pattern found between "dot" and "end"- continue at top + p = text; if (dir == BACK) { - msg = "search hit TOP, continuing at BOTTOM"; + 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"; } - } else { - msg = "Pattern not found"; - } dc2: - if (*msg) - status_line_bold("%s", msg); + if (msg) + status_line_bold("%s", msg); + } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph q = char_search(dot, "\n\n", BACK, FULL); @@ -3352,7 +3514,7 @@ static void do_cmd(int c) || strncmp(p, "q!", cnt) == 0 // delete lines ) { if (file_modified && p[1] != '!') { - status_line_bold("No write since last change (:quit! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", p); } else { editing = 0; } @@ -3426,18 +3588,17 @@ static void do_cmd(int c) 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 > 0) { - do_cmd(c); - } 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); + do { + 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); + } while (--cmdcnt > 0); break; case 'C': // C- Change to e-o-l case 'D': // D- delete to e-o-l @@ -3488,20 +3649,19 @@ static void do_cmd(int c) case 'i': // i- insert before current char case KEYCODE_INSERT: // Cursor Key Insert dc_i: - cmd_mode = 1; // start insrting + cmd_mode = 1; // start inserting break; case 'J': // J- join current and next lines together - if (--cmdcnt > 1) { - do_cmd(c); - } - 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(); + do { + 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(); + } } - } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; case 'L': // L- goto bottom line on screen @@ -3545,20 +3705,19 @@ static void do_cmd(int c) case 'X': // X- delete char before dot case 'x': // x- delete the current char case 's': // s- substitute the current char - if (--cmdcnt > 0) { - do_cmd(c); - } 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 + do { + if (dot[dir] != '\n') { + if (c == 'X') + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q + if (c == 's') + goto dc_i; // start inserting break; case 'Z': // Z- if modified, {write}; exit // ZZ means to save file (if necessary), then exit @@ -3589,23 +3748,22 @@ static void do_cmd(int c) break; case 'b': // b- back a word case 'e': // e- end of word - if (--cmdcnt > 0) { - do_cmd(c); - } 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); - } + do { + 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); + } + } while (--cmdcnt > 0); break; case 'c': // c- change something case 'd': // d- delete something @@ -3690,11 +3848,10 @@ static void do_cmd(int c) } case 'k': // k- goto prev line, same col case KEYCODE_UP: // cursor key Up - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_prev(); + dot = move_to_col(dot, ccol + offset); // try stay in same col + } while (--cmdcnt > 0); break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char @@ -3712,19 +3869,18 @@ static void do_cmd(int c) last_forward_char = 0; break; case 'w': // w- forward a word - if (--cmdcnt > 0) { - do_cmd(c); - } - 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); - } + do { + 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); + } + } while (--cmdcnt > 0); break; case 'z': // z- c1 = get_one_char(); // get the replacement char @@ -3740,17 +3896,16 @@ static void do_cmd(int c) 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 > 0) { - do_cmd(c); - } - if (islower(*dot)) { - *dot = toupper(*dot); - file_modified++; - } else if (isupper(*dot)) { - *dot = tolower(*dot); - file_modified++; - } - dot_right(); + do { + if (islower(*dot)) { + *dot = toupper(*dot); + file_modified++; + } else if (isupper(*dot)) { + *dot = tolower(*dot); + file_modified++; + } + dot_right(); + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; //----- The Cursor and Function Keys ----------------------------- diff --git a/release/src/router/busybox/examples/android-build b/release/src/router/busybox/examples/android-build new file mode 100644 index 0000000000..89f3b637ab --- /dev/null +++ b/release/src/router/busybox/examples/android-build @@ -0,0 +1,32 @@ +#!/bin/sh +# Build Busybox against Android's bionic +# Originally by Dan Fandrich +# +# Configure with "make android_defconfig" +# +# This file has been tested on Android Froyo (the lack of ttyname_r in +# the android libc must be patched around) and Gingerbread. + +# Point this to the Android root directory; it's used in the defconfig CFLAGS +export A="$HOME/android" + +# Android product being built +P=zoom2 + +# Toolchain version in use by this version of Android +GCCVER=4.4.3 + +export PATH="$A/prebuilt/linux-x86/toolchain/arm-eabi-$GCCVER/bin:$PATH" + +# Set the linker flags; compiler flags are in the defconfig file +if grep "^CONFIG_STATIC=y" .config >/dev/null ; then + # Static linking + LDFLAGS="-static -Xlinker -z -Xlinker muldefs -nostdlib $A/out/target/product/$P/obj/lib/crtbegin_static.o $A/out/target/product/$P/obj/lib/crtend_android.o -L$A/out/target/product/$P/obj/lib -L$A/out/target/product/$P/obj/STATIC_LIBRARIES/libm_intermediates -L$A/out/target/product/$P/obj/STATIC_LIBRARIES/libc_intermediates" + LDLIBS="m c gcc" +else + # Dynamic linking + LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -T$A/build/core/armelf.x -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined $A/out/target/product/$P/obj/lib/crtbegin_dynamic.o $A/out/target/product/$P/obj/lib/crtend_android.o -L$A/out/target/product/$P/obj/lib" + LDLIBS="dl m c gcc" +fi + +make EXTRA_LDFLAGS="$LDFLAGS" LDLIBS="$LDLIBS" "$@" diff --git a/release/src/router/busybox/examples/depmod.pl b/release/src/router/busybox/examples/depmod.pl index 1e1f3451f0..6a3e8822ac 100755 --- a/release/src/router/busybox/examples/depmod.pl +++ b/release/src/router/busybox/examples/depmod.pl @@ -199,7 +199,7 @@ 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'; +my $kseries = $basedir =~ m,/2\.4\.[^/]*, ? '2.4' : 'others'; foreach my $module ( keys %$mod ) { if($kseries eq '2.4') { diff --git a/release/src/router/busybox/examples/udhcp/udhcpd.conf b/release/src/router/busybox/examples/udhcp/udhcpd.conf index 23fc834b70..eca44c0ab4 100644 --- a/release/src/router/busybox/examples/udhcp/udhcpd.conf +++ b/release/src/router/busybox/examples/udhcp/udhcpd.conf @@ -14,11 +14,6 @@ interface eth0 # smaller than lease block. #max_leases 254 -# 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 - # The amount of time that an IP will be reserved (leased to nobody) # if a DHCP decline message is received (seconds) #decline_time 3600 @@ -34,11 +29,16 @@ interface eth0 # to this value (seconds) #min_lease 60 +# The location of the pid file +#pidfile /var/run/udhcpd.pid + # The location of the leases file #lease_file /var/lib/misc/udhcpd.leases -# The location of the pid file -#pidfile /var/run/udhcpd.pid +# The time period at which udhcpd will write out leases file. +# If this is 0, udhcpd will never automatically write leases file. +# Specified in seconds. +#auto_time 7200 # Every time udhcpd writes a leases file, the below script will be called #notify_file # default: no script @@ -68,6 +68,8 @@ opt wins 192.168.10.10 option dns 129.219.13.81 # appended to above DNS servers for a total of 3 option domain local option lease 864000 # default: 10 days +option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route +option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 # Arbitrary option in hex form: option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" @@ -90,6 +92,8 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" #opt wpad STRING #opt serverid IP # default: server's IP #opt message STRING # error message (udhcpd sends it on success too) +#opt vlanid NUM # 802.1P VLAN ID +#opt vlanpriority NUM # 802.1Q VLAN priority # Options specifying server(s) #opt dns IP_LIST #opt wins IP_LIST @@ -97,8 +101,15 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" #opt ntpsrv IP_LIST #opt lprsrv IP_LIST #opt swapsrv IP +# Options specifying routes +#opt routes IP_PAIR_LIST +#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option +#opt msstaticroutes STATIC_ROUTES # same, using MS option number # Obsolete options, no longer supported #opt logsrv IP_LIST # 704/UDP log server (not syslog!) #opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) #opt cookiesrv IP_LIST # RFC 865 "quote of the day" server, rarely (never?) used #opt timesrv IP_LIST # RFC 868 time server, rarely (never?) used +# TODO: in development +#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc +#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs diff --git a/release/src/router/busybox/examples/var_service/README b/release/src/router/busybox/examples/var_service/README new file mode 100644 index 0000000000..06817c8bcd --- /dev/null +++ b/release/src/router/busybox/examples/var_service/README @@ -0,0 +1,59 @@ +In many cases, network configuration makes it necessary to run several daemons: +dhcp, zeroconf, ppp, openvpn and such. They need to be controlled, +and in many cases you also want to babysit them. runsvdir is a good tool for this. +examples/var_service directory provides a few examples. It is meant to be used +this way: copy it somewhere (say, /var/service) and run something like + +env - PATH=... runsvdir /var/service & + +from one of system startup scripts. (Google "man runsvdir" and "man runsv" +for more info about these tools). + +Some existing examples: + +var_service/dhcp_if - +controls a udhcpc instance which provides dhpc-assigned IP +address on interface named "if". Copy/rename this directory as needed to run +udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix +of the parent directory as interface name). When IP address is obtained or lost, +var_service/dhcp_if/dhcp_handler is run. It saves new config data to +/var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. +This example can be used as a template for other dynamic network link services +(ppp/vpn/zcip). + +var_service/ifplugd_if - +watches link status of interface if. Downs and ups /var/service/dhcp_if +service accordingly. In effect, it allows you to unplug/plug-to-different-network +and have your IP properly re-negotiated at once. + +var_service/dhcp_if_pinger - +Uses var_service/dhcp_if's data (/var/service/dhcp_if/dhcp_if.out file) +to determine router IP. Pings it. If ping fails, restarts /var/service/dhcp_if +service. Basically, an example of watchdog service for networks +which are not reliable and need babysitting. + +var_service/fw - +A *one-shot* service which reconfigures network based on current known state +of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf +(dynamic config from dhcp/ppp/vpn/etc) to determine what to do. +One-shot-ness of this service means that it shuts itself off after single run. +IOW: it is not a constantly running daemon sort of thing. +It starts, it configures the network, it shuts down, all done +(unlike infamous NetworkManagers which sit in RAM forever, doing hell knows what). + +However, any dhcp/ppp/vpn or similar service can restart it anytime +when it senses the change in network configuration. +This even works while fw service runs: if dhcp signals fw to (re)start +while fw runs, fw will not stop after its execution, but will re-execute once, +picking up dhcp's new configuration. +This is achieved very simply by having +# Make ourself one-shot +sv o . +at the very beginning of fw/run script, not at the end. +Therefore, any "sv u /var/run/service/fw" command by any other +script "undoes" o(ne-shot) command if fw still runs, thus +runsv will rerun it; or start it in a normal way if fw is not running. + +System administrators are expected to edit fw/run script, since +network configuration needs are likely to be very complex and different +for non-trivial installations. diff --git a/release/src/router/busybox/examples/zcip.script b/release/src/router/busybox/examples/zcip.script index 988e542a4c..e543c304e8 100755 --- a/release/src/router/busybox/examples/zcip.script +++ b/release/src/router/busybox/examples/zcip.script @@ -20,9 +20,9 @@ config) exit 1 fi # remember $ip for $interface, to use on restart - if [ "x$IP" != x -a -w "$IP.$interface" ] + if [ "x$ip" != x -a -w "$ip.$interface" ] then - echo $ip > "$IP.$interface" + echo $ip > "$ip.$interface" fi exec ip address add dev $interface \ scope link local "$ip/16" broadcast + diff --git a/release/src/router/busybox/findutils/find.c b/release/src/router/busybox/findutils/find.c index dd00f37ea6..0ec5bdfeaa 100644 --- a/release/src/router/busybox/findutils/find.c +++ b/release/src/router/busybox/findutils/find.c @@ -53,10 +53,6 @@ * diff -u /tmp/std_find /tmp/bb_find && echo Identical */ -//applet:IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_DROP, find)) - -//kbuild:lib-$(CONFIG_FIND) += find.o - //config:config FIND //config: bool "find" //config: default y @@ -112,11 +108,11 @@ //config: This option allows find to restrict searches to a single filesystem. //config: //config:config FEATURE_FIND_MAXDEPTH -//config: bool "Enable -maxdepth N" +//config: bool "Enable -mindepth N and -maxdepth N" //config: default y //config: depends on FIND //config: help -//config: This option enables -maxdepth N option. +//config: This option enables -mindepth N and -maxdepth N option. //config: //config:config FEATURE_FIND_NEWER //config: bool "Enable -newer: compare file modification times" @@ -124,7 +120,7 @@ //config: depends on FIND //config: help //config: Support the 'find -newer' option for finding any files which have -//config: a modified time that is more recent than the specified FILE. +//config: modification time that is more recent than the specified FILE. //config: //config:config FEATURE_FIND_INUM //config: bool "Enable -inum: inode number matching" @@ -230,11 +226,118 @@ //config: help //config: Support the 'find -links' option for matching number of links. +//applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) + +//kbuild:lib-$(CONFIG_FIND) += find.o + +//usage:#define find_trivial_usage +//usage: "[PATH]... [OPTIONS] [ACTIONS]" +//usage:#define find_full_usage "\n\n" +//usage: "Search for files and perform actions on them.\n" +//usage: "First failed action stops processing of current file.\n" +//usage: "Defaults: PATH is current directory, action is '-print'\n" +//usage: "\n -follow Follow symlinks" +//usage: IF_FEATURE_FIND_XDEV( +//usage: "\n -xdev Don't descend directories on other filesystems" +//usage: ) +//usage: IF_FEATURE_FIND_MAXDEPTH( +//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" +//usage: "\n actions to command line arguments only" +//usage: "\n -mindepth N Don't act on first N levels" +//usage: ) +//usage: IF_FEATURE_FIND_DEPTH( +//usage: "\n -depth Act on directory *after* traversing it" +//usage: ) +//usage: "\n" +//usage: "\nActions:" +//usage: IF_FEATURE_FIND_PAREN( +//usage: "\n ( ACTIONS ) Group actions for -o / -a" +//usage: ) +//usage: IF_FEATURE_FIND_NOT( +//usage: "\n ! ACT Invert ACT's success/failure" +//usage: ) +//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" +//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" +//usage: "\n Note: -a has higher priority than -o" +//usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" +//usage: "\n -iname PATTERN Case insensitive -name" +//usage: IF_FEATURE_FIND_PATH( +//usage: "\n -path PATTERN Match path to PATTERN" +//usage: "\n -ipath PATTERN Case insensitive -path" +//usage: ) +//usage: IF_FEATURE_FIND_REGEX( +//usage: "\n -regex PATTERN Match path to regex PATTERN" +//usage: ) +//usage: IF_FEATURE_FIND_TYPE( +//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" +//usage: ) +//usage: IF_FEATURE_FIND_PERM( +//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," +//usage: "\n or exactly MASK bits are set in file's mode" +//usage: ) +//usage: IF_FEATURE_FIND_MTIME( +//usage: "\n -mtime DAYS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N days in the past" +//usage: ) +//usage: IF_FEATURE_FIND_MMIN( +//usage: "\n -mmin MINS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N minutes in the past" +//usage: ) +//usage: IF_FEATURE_FIND_NEWER( +//usage: "\n -newer FILE mtime is more recent than FILE's" +//usage: ) +//usage: IF_FEATURE_FIND_INUM( +//usage: "\n -inum N File has inode number N" +//usage: ) +//usage: IF_FEATURE_FIND_USER( +//usage: "\n -user NAME/ID File is owned by given user" +//usage: ) +//usage: IF_FEATURE_FIND_GROUP( +//usage: "\n -group NAME/ID File is owned by given group" +//usage: ) +//usage: IF_FEATURE_FIND_SIZE( +//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" +//usage: "\n +/-N: file size is bigger/smaller than N" +//usage: ) +//usage: IF_FEATURE_FIND_LINKS( +//usage: "\n -links N Number of links is greater than (+N), less than (-N)," +//usage: "\n or exactly N" +//usage: ) +//usage: IF_FEATURE_FIND_CONTEXT( +//usage: "\n -context CTX File has specified security context" +//usage: ) +//usage: IF_FEATURE_FIND_PRUNE( +//usage: "\n -prune If current file is directory, don't descend into it" +//usage: ) +//usage: "\nIf none of the following actions is specified, -print is assumed" +//usage: "\n -print Print file name" +//usage: IF_FEATURE_FIND_PRINT0( +//usage: "\n -print0 Print file name, NUL terminated" +//usage: ) +//usage: IF_FEATURE_FIND_EXEC( +//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" +//usage: "\n file name. Fails if CMD exits with nonzero" +//usage: ) +//usage: IF_FEATURE_FIND_DELETE( +//usage: "\n -delete Delete current file/directory. Turns on -depth option" +//usage: ) +//usage: +//usage:#define find_example_usage +//usage: "$ find / -name passwd\n" +//usage: "/etc/passwd\n" + #include #include "libbb.h" #if ENABLE_FEATURE_FIND_REGEX -#include "xregex.h" +# include "xregex.h" #endif +/* GNUism: */ +#ifndef FNM_CASEFOLD +# define FNM_CASEFOLD 0 +#endif + +#define dbg(...) ((void)0) +/* #define dbg(...) bb_error_msg(__VA_ARGS__) */ /* This is a NOEXEC applet. Be very careful! */ @@ -256,7 +359,7 @@ typedef struct { ACTS(print) ACTS(name, const char *pattern; bool iname;) -IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern;)) +IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern; bool ipath;)) IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) IF_FEATURE_FIND_PRINT0( ACTS(print0)) IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) @@ -278,8 +381,12 @@ IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) struct globals { IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) IF_FEATURE_FIND_XDEV(int xdev_count;) +#if ENABLE_FEATURE_FIND_MAXDEPTH + int minmaxdepth[2]; +#endif action ***actions; - bool need_print; + smallint need_print; + smallint xdev_on; recurse_flags_t recurse_flags; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) @@ -288,7 +395,8 @@ struct globals { char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ }; \ /* we have to zero it out because of NOEXEC */ \ - memset(&G, 0, offsetof(struct globals, need_print)); \ + memset(&G, 0, sizeof(G)); \ + IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ G.need_print = 1; \ G.recurse_flags = ACTION_RECURSE; \ } while (0) @@ -364,14 +472,32 @@ static int exec_actions(action ***appp, const char *fileName, const struct stat #if ENABLE_FEATURE_FIND_NOT if (ap->invert) rc ^= TRUE; #endif + dbg("grp %d action %d rc:0x%x", cur_group, cur_action, rc); if (rc & TRUE) /* current group failed, try next */ break; } } + dbg("returning:0x%x", rc ^ TRUE); return rc ^ TRUE; /* restore TRUE bit */ } +#if !FNM_CASEFOLD +static char *strcpy_upcase(char *dst, const char *src) +{ + char *d = dst; + while (1) { + unsigned char ch = *src++; + if (ch >= 'a' && ch <= 'z') + ch -= ('a' - 'A'); + *d++ = ch; + if (ch == '\0') + break; + } + return dst; +} +#endif + ACTF(name) { const char *tmp = bb_basename(fileName); @@ -387,13 +513,25 @@ ACTF(name) * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. * find -name '*foo' should match .foo too: */ +#if FNM_CASEFOLD return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; +#else + if (ap->iname) + tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); + return fnmatch(ap->pattern, tmp, 0) == 0; +#endif } #if ENABLE_FEATURE_FIND_PATH ACTF(path) { +# if FNM_CASEFOLD + return fnmatch(ap->pattern, fileName, (ap->ipath ? FNM_CASEFOLD : 0)) == 0; +# else + if (ap->ipath) + fileName = strcpy_upcase(alloca(strlen(fileName) + 1), fileName); return fnmatch(ap->pattern, fileName, 0) == 0; +# endif } #endif #if ENABLE_FEATURE_FIND_REGEX @@ -586,16 +724,15 @@ ACTF(links) static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, - void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), + void *userData UNUSED_PARAM, int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) { int r; -#if ENABLE_FEATURE_FIND_MAXDEPTH -#define minmaxdepth ((int*)userData) - if (depth < minmaxdepth[0]) +#if ENABLE_FEATURE_FIND_MAXDEPTH + if (depth < G.minmaxdepth[0]) return TRUE; /* skip this, continue recursing */ - if (depth > minmaxdepth[1]) + if (depth > G.minmaxdepth[1]) return SKIP; /* stop recursing */ #endif @@ -606,7 +743,7 @@ static int FAST_FUNC fileAction(const char *fileName, #if ENABLE_FEATURE_FIND_MAXDEPTH if (S_ISDIR(statbuf->st_mode)) { - if (depth == minmaxdepth[1]) + if (depth == G.minmaxdepth[1]) return SKIP; } #endif @@ -629,7 +766,6 @@ static int FAST_FUNC fileAction(const char *fileName, /* Cannot return 0: our caller, recursive_action(), * will perror() and skip dirs (if called on dir) */ return (r & SKIP) ? SKIP : TRUE; -#undef minmaxdepth } @@ -674,6 +810,9 @@ static const char* plus_minus_num(const char* str) static action*** parse_params(char **argv) { enum { + OPT_FOLLOW , + IF_FEATURE_FIND_XDEV( OPT_XDEV ,) + IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) PARM_a , PARM_o , IF_FEATURE_FIND_NOT( PARM_char_not ,) @@ -684,15 +823,20 @@ static action*** parse_params(char **argv) #endif PARM_print , IF_FEATURE_FIND_PRINT0( PARM_print0 ,) - IF_FEATURE_FIND_DEPTH( PARM_depth ,) IF_FEATURE_FIND_PRUNE( PARM_prune ,) IF_FEATURE_FIND_DELETE( PARM_delete ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) IF_FEATURE_FIND_PAREN( PARM_char_brace,) - /* All options starting from here require argument */ + /* All options/actions starting from here require argument */ PARM_name , PARM_iname , IF_FEATURE_FIND_PATH( PARM_path ,) +#if ENABLE_DESKTOP + /* -wholename is a synonym for -path */ + /* We support it because Linux kernel's "make tags" uses it */ + IF_FEATURE_FIND_PATH( PARM_wholename ,) +#endif + IF_FEATURE_FIND_PATH( PARM_ipath ,) IF_FEATURE_FIND_REGEX( PARM_regex ,) IF_FEATURE_FIND_TYPE( PARM_type ,) IF_FEATURE_FIND_PERM( PARM_perm ,) @@ -705,28 +849,35 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( PARM_size ,) IF_FEATURE_FIND_CONTEXT(PARM_context ,) IF_FEATURE_FIND_LINKS( PARM_links ,) + IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,OPT_MAXDEPTH,) }; static const char params[] ALIGN1 = - "-a\0" - "-o\0" + "-follow\0" + IF_FEATURE_FIND_XDEV( "-xdev\0" ) + IF_FEATURE_FIND_DEPTH( "-depth\0" ) + "-a\0" + "-o\0" IF_FEATURE_FIND_NOT( "!\0" ) #if ENABLE_DESKTOP - "-and\0" - "-or\0" - IF_FEATURE_FIND_NOT( "-not\0" ) + "-and\0" + "-or\0" + IF_FEATURE_FIND_NOT( "-not\0" ) #endif - "-print\0" + "-print\0" IF_FEATURE_FIND_PRINT0( "-print0\0" ) - IF_FEATURE_FIND_DEPTH( "-depth\0" ) IF_FEATURE_FIND_PRUNE( "-prune\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) IF_FEATURE_FIND_PAREN( "(\0" ) - /* All options starting from here require argument */ + /* All options/actions starting from here require argument */ "-name\0" "-iname\0" IF_FEATURE_FIND_PATH( "-path\0" ) +#if ENABLE_DESKTOP + IF_FEATURE_FIND_PATH( "-wholename\0") +#endif + IF_FEATURE_FIND_PATH( "-ipath\0" ) IF_FEATURE_FIND_REGEX( "-regex\0" ) IF_FEATURE_FIND_TYPE( "-type\0" ) IF_FEATURE_FIND_PERM( "-perm\0" ) @@ -739,7 +890,8 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( "-size\0" ) IF_FEATURE_FIND_CONTEXT("-context\0") IF_FEATURE_FIND_LINKS( "-links\0" ) - ; + IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") + ; action*** appp; unsigned cur_group = 0; @@ -766,27 +918,15 @@ static action*** parse_params(char **argv) 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]; + dbg("arg:'%s' arg1:'%s' parm:%d PARM_type:%d", arg, arg1, parm, PARM_type); + if (parm >= PARM_name) { - /* All options starting from -name require argument */ + /* All options/actions starting from -name require argument */ if (!arg1) bb_error_msg_and_die(bb_msg_requires_arg, arg); argv++; @@ -795,11 +935,49 @@ static action*** parse_params(char **argv) /* We can use big switch() here, but on i386 * it doesn't give smaller code. Other arches? */ - /* --- Operators --- */ - if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { +/* Options always return true. They always take effect + * rather than being processed only when their place in the + * expression is reached. + */ + /* Options */ + if (parm == OPT_FOLLOW) { + dbg("follow enabled: %d", __LINE__); + G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; + } +#if ENABLE_FEATURE_FIND_XDEV + else if (parm == OPT_XDEV) { + dbg("%d", __LINE__); + G.xdev_on = 1; + } +#endif +#if ENABLE_FEATURE_FIND_MAXDEPTH + else if (parm == OPT_MINDEPTH || parm == OPT_MINDEPTH + 1) { + dbg("%d", __LINE__); + G.minmaxdepth[parm - OPT_MINDEPTH] = xatoi_positive(arg1); + } +#endif +#if ENABLE_FEATURE_FIND_DEPTH + else if (parm == OPT_DEPTH) { + dbg("%d", __LINE__); + G.recurse_flags |= ACTION_DEPTHFIRST; + } +#endif +/* 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 + */ + /* Operators */ + else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { + dbg("%d", __LINE__); /* no further special handling required */ } else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { + dbg("%d", __LINE__); /* start new OR group */ cur_group++; appp = xrealloc(appp, (cur_group+2) * sizeof(*appp)); @@ -811,36 +989,31 @@ static action*** parse_params(char **argv) else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) { /* also handles "find ! ! -name 'foo*'" */ invert_flag ^= 1; + dbg("invert_flag:%d", invert_flag); } #endif - - /* --- Tests and actions --- */ + /* Actions */ else if (parm == PARM_print) { + dbg("%d", __LINE__); G.need_print = 0; - /* GNU find ignores '!' here: "find ! -print" */ - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print); } #if ENABLE_FEATURE_FIND_PRINT0 else if (parm == PARM_print0) { + dbg("%d", __LINE__); G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print0); } #endif -#if ENABLE_FEATURE_FIND_DEPTH - else if (parm == PARM_depth) { - G.recurse_flags |= ACTION_DEPTHFIRST; - } -#endif #if ENABLE_FEATURE_FIND_PRUNE else if (parm == PARM_prune) { - IF_FEATURE_FIND_NOT( invert_flag = 0; ) + dbg("%d", __LINE__); (void) ALLOC_ACTION(prune); } #endif #if ENABLE_FEATURE_FIND_DELETE else if (parm == PARM_delete) { + dbg("%d", __LINE__); G.need_print = 0; G.recurse_flags |= ACTION_DEPTHFIRST; (void) ALLOC_ACTION(delete); @@ -850,8 +1023,8 @@ static action*** parse_params(char **argv) else if (parm == PARM_exec) { int i; action_exec *ap; + dbg("%d", __LINE__); G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) ap = ALLOC_ACTION(exec); ap->exec_argv = ++argv; /* first arg after -exec */ /*ap->exec_argc = 0; - ALLOC_ACTION did it */ @@ -859,9 +1032,9 @@ static action*** parse_params(char **argv) if (!*argv) /* did not see ';' or '+' until end */ bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); // find -exec echo Foo ">{}<" ";" - // executes "echo Foo ", + // executes "echo Foo >FILENAME<", // find -exec echo Foo ">{}<" "+" - // executes "echo Foo ...". + // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". // TODO (so far we treat "+" just like ";") if ((argv[0][0] == ';' || argv[0][0] == '+') && argv[0][1] == '\0' @@ -885,6 +1058,7 @@ static action*** parse_params(char **argv) char **endarg; unsigned nested = 1; + dbg("%d", __LINE__); endarg = argv; while (1) { if (!*++endarg) @@ -904,20 +1078,24 @@ static action*** parse_params(char **argv) #endif else if (parm == PARM_name || parm == PARM_iname) { action_name *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(name); ap->pattern = arg1; ap->iname = (parm == PARM_iname); } #if ENABLE_FEATURE_FIND_PATH - else if (parm == PARM_path) { + else if (parm == PARM_path IF_DESKTOP(|| parm == PARM_wholename) || parm == PARM_ipath) { action_path *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(path); ap->pattern = arg1; + ap->ipath = (parm == PARM_ipath); } #endif #if ENABLE_FEATURE_FIND_REGEX else if (parm == PARM_regex) { action_regex *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(regex); xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/); } @@ -927,16 +1105,18 @@ static action*** parse_params(char **argv) action_type *ap; ap = ALLOC_ACTION(type); ap->type_mask = find_type(arg1); + dbg("created:type mask:%x", ap->type_mask); } #endif #if ENABLE_FEATURE_FIND_PERM -/* -perm mode File's permission bits are exactly mode (octal or symbolic). +/* -perm BITS File's mode bits are exactly BITS (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. + * -perm -BITS All of the BITS are set in file's mode. + * -perm +BITS At least one of the BITS is set in file's mode. */ else if (parm == PARM_perm) { action_perm *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(perm); ap->perm_char = arg1[0]; arg1 = plus_minus_num(arg1); @@ -948,6 +1128,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_MTIME else if (parm == PARM_mtime) { action_mtime *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(mtime); ap->mtime_char = arg1[0]; ap->mtime_days = xatoul(plus_minus_num(arg1)); @@ -956,6 +1137,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_MMIN else if (parm == PARM_mmin) { action_mmin *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(mmin); ap->mmin_char = arg1[0]; ap->mmin_mins = xatoul(plus_minus_num(arg1)); @@ -965,6 +1147,7 @@ static action*** parse_params(char **argv) else if (parm == PARM_newer) { struct stat stat_newer; action_newer *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(newer); xstat(arg1, &stat_newer); ap->newer_mtime = stat_newer.st_mtime; @@ -973,6 +1156,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_INUM else if (parm == PARM_inum) { action_inum *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(inum); ap->inode_num = xatoul(arg1); } @@ -980,6 +1164,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_USER else if (parm == PARM_user) { action_user *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(user); ap->uid = bb_strtou(arg1, NULL, 10); if (errno) @@ -989,6 +1174,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_GROUP else if (parm == PARM_group) { action_group *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(group); ap->gid = bb_strtou(arg1, NULL, 10); if (errno) @@ -1017,6 +1203,7 @@ static action*** parse_params(char **argv) { "", 0 } }; action_size *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(size); ap->size_char = arg1[0]; ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes); @@ -1025,6 +1212,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_CONTEXT else if (parm == PARM_context) { action_context *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(context); /*ap->context = NULL; - ALLOC_ACTION did it */ /* SELinux headers erroneously declare non-const parameter */ @@ -1035,6 +1223,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_LINKS else if (parm == PARM_links) { action_links *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(links); ap->links_char = arg1[0]; ap->links_count = xatoul(plus_minus_num(arg1)); @@ -1046,197 +1235,64 @@ static action*** parse_params(char **argv) } argv++; } + dbg("exiting %s", __func__); return appp; #undef ALLOC_ACTION } -//usage:#define find_trivial_usage -//usage: "[PATH]... [EXPRESSION]" -//usage:#define find_full_usage "\n\n" -//usage: "Search for files. The default PATH is the current directory,\n" -//usage: "default EXPRESSION is '-print'\n" -//usage: "\nEXPRESSION may consist of:" -//usage: "\n -follow Follow symlinks" -//usage: IF_FEATURE_FIND_XDEV( -//usage: "\n -xdev Don't descend directories on other filesystems" -//usage: ) -//usage: IF_FEATURE_FIND_MAXDEPTH( -//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" -//usage: "\n tests/actions to command line arguments only" -//usage: ) -//usage: "\n -mindepth N Don't act on first N levels" -//usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" -//usage: "\n -iname PATTERN Case insensitive -name" -//usage: IF_FEATURE_FIND_PATH( -//usage: "\n -path PATTERN Path matches PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_REGEX( -//usage: "\n -regex PATTERN Path matches regex PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_TYPE( -//usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" -//usage: ) -//usage: IF_FEATURE_FIND_PERM( -//usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," -//usage: "\n or exactly NNN" -//usage: ) -//usage: IF_FEATURE_FIND_MTIME( -//usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N days" -//usage: ) -//usage: IF_FEATURE_FIND_MMIN( -//usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N minutes" -//usage: ) -//usage: IF_FEATURE_FIND_NEWER( -//usage: "\n -newer FILE Modified time is more recent than FILE's" -//usage: ) -//usage: IF_FEATURE_FIND_INUM( -//usage: "\n -inum N File has inode number N" -//usage: ) -//usage: IF_FEATURE_FIND_USER( -//usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_GROUP( -//usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_DEPTH( -//usage: "\n -depth Process directory name after traversing it" -//usage: ) -//usage: IF_FEATURE_FIND_SIZE( -//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" -//usage: "\n +/-N: file size is bigger/smaller than N" -//usage: ) -//usage: IF_FEATURE_FIND_LINKS( -//usage: "\n -links N Number of links is greater than (+N), less than (-N)," -//usage: "\n or exactly N" -//usage: ) -//usage: "\n -print Print (default and assumed)" -//usage: IF_FEATURE_FIND_PRINT0( -//usage: "\n -print0 Delimit output with null characters rather than" -//usage: "\n newlines" -//usage: ) -//usage: IF_FEATURE_FIND_CONTEXT( -//usage: "\n -context File has specified security context" -//usage: ) -//usage: IF_FEATURE_FIND_EXEC( -//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" -//usage: "\n matching files" -//usage: ) -//usage: IF_FEATURE_FIND_PRUNE( -//usage: "\n -prune Stop traversing current subtree" -//usage: ) -//usage: IF_FEATURE_FIND_DELETE( -//usage: "\n -delete Delete files, turns on -depth option" -//usage: ) -//usage: IF_FEATURE_FIND_PAREN( -//usage: "\n (EXPR) Group an expression" -//usage: ) -//usage: -//usage:#define find_example_usage -//usage: "$ find / -name passwd\n" -//usage: "/etc/passwd\n" - int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { - static const char options[] ALIGN1 = - "-follow\0" -IF_FEATURE_FIND_XDEV( "-xdev\0" ) -IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") - ; - enum { - OPT_FOLLOW, -IF_FEATURE_FIND_XDEV( OPT_XDEV ,) -IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) - }; - - char *arg; - char **argp; int i, firstopt, status = EXIT_SUCCESS; -#if ENABLE_FEATURE_FIND_MAXDEPTH - int minmaxdepth[2] = { 0, INT_MAX }; -#else -#define minmaxdepth NULL -#endif INIT_G(); - for (firstopt = 1; argv[firstopt]; firstopt++) { + argv++; + for (firstopt = 0; argv[firstopt]; 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], '(')) + if (ENABLE_FEATURE_FIND_PAREN && LONE_CHAR(argv[firstopt], '(')) break; -#endif } - if (firstopt == 1) { - argv[0] = (char*)"."; - argv--; + if (firstopt == 0) { + *--argv = (char*)"."; 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) { - G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; - argp[0] = (char*)"-a"; - } + G.actions = parse_params(&argv[firstopt]); + argv[firstopt] = NULL; + #if ENABLE_FEATURE_FIND_XDEV - if (opt == OPT_XDEV) { - struct stat stbuf; - if (!G.xdev_count) { - G.xdev_count = firstopt - 1; - G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); - for (i = 1; i < firstopt; i++) { - /* not xstat(): shouldn't bomb out on - * "find not_exist exist -xdev" */ - if (stat(argv[i], &stbuf) == 0) - G.xdev_dev[i-1] = stbuf.st_dev; - /* else G.xdev_dev[i-1] stays 0 and - * won't match any real device dev_t */ - } - } - argp[0] = (char*)"-a"; - } -#endif -#if ENABLE_FEATURE_FIND_MAXDEPTH - if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) { - if (!argp[1]) - bb_show_usage(); - minmaxdepth[opt - OPT_MINDEPTH] = xatoi_positive(argp[1]); - argp[0] = (char*)"-a"; - argp[1] = (char*)"-a"; - argp++; + if (G.xdev_on) { + struct stat stbuf; + + G.xdev_count = firstopt; + G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); + for (i = 0; argv[i]; i++) { + /* not xstat(): shouldn't bomb out on + * "find not_exist exist -xdev" */ + if (stat(argv[i], &stbuf) == 0) + G.xdev_dev[i] = stbuf.st_dev; + /* else G.xdev_dev[i] stays 0 and + * won't match any real device dev_t + */ } -#endif - argp++; } +#endif - G.actions = parse_params(&argv[firstopt]); - - for (i = 1; i < firstopt; i++) { + for (i = 0; argv[i]; i++) { if (!recursive_action(argv[i], G.recurse_flags,/* flags */ fileAction, /* file action */ fileAction, /* dir action */ -#if ENABLE_FEATURE_FIND_MAXDEPTH - minmaxdepth, /* user data */ -#else NULL, /* user data */ -#endif - 0)) /* depth */ + 0) /* depth */ + ) { status = EXIT_FAILURE; + } } + return status; } diff --git a/release/src/router/busybox/findutils/grep.c b/release/src/router/busybox/findutils/grep.c index ff6742a690..f14d6e6c1c 100644 --- a/release/src/router/busybox/findutils/grep.c +++ b/release/src/router/busybox/findutils/grep.c @@ -18,9 +18,9 @@ * (C) 2006 Jac Goudsmit added -o option */ -//applet:IF_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_DROP)) -//applet:IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, egrep)) -//applet:IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, fgrep)) +//applet:IF_GREP(APPLET(grep, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, BB_DIR_BIN, BB_SUID_DROP, egrep)) +//applet:IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, BB_DIR_BIN, BB_SUID_DROP, fgrep)) //kbuild:lib-$(CONFIG_GREP) += grep.o @@ -72,7 +72,6 @@ //usage: "PATTERN/-e PATTERN.../-f FILE [FILE]..." //usage:#define grep_full_usage "\n\n" //usage: "Search for PATTERN in FILEs (or stdin)\n" -//usage: "\nOptions:" //usage: "\n -H Add 'filename:' prefix" //usage: "\n -h Do not add 'filename:' prefix" //usage: "\n -n Add 'line_no:' prefix" @@ -86,6 +85,7 @@ //usage: "\n -r Recurse" //usage: "\n -i Ignore case" //usage: "\n -w Match whole words only" +//usage: "\n -x Match whole lines only" //usage: "\n -F PATTERN is a literal (not regexp)" //usage: IF_FEATURE_GREP_EGREP_ALIAS( //usage: "\n -E PATTERN is an extended regexp" @@ -114,7 +114,7 @@ //usage:#define fgrep_full_usage "" #define OPTSTR_GREP \ - "lnqvscFiHhe:f:Lorm:w" \ + "lnqvscFiHhe:f:Lorm:wx" \ IF_FEATURE_GREP_CONTEXT("A:B:C:") \ IF_FEATURE_GREP_EGREP_ALIAS("E") \ IF_EXTRA_COMPAT("z") \ @@ -139,6 +139,7 @@ enum { OPTBIT_r, /* recurse dirs */ OPTBIT_m, /* -m MAX_MATCHES */ OPTBIT_w, /* -w whole word match */ + OPTBIT_x, /* -x whole line match */ IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ @@ -161,6 +162,7 @@ enum { OPT_r = 1 << OPTBIT_r, OPT_m = 1 << OPTBIT_m, OPT_w = 1 << OPTBIT_w, + OPT_x = 1 << OPTBIT_x, OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, @@ -371,9 +373,12 @@ static int grep_file(FILE *file) &gl->matched_range) >= 0 #endif ) { - if (!(option_mask32 & OPT_w)) + if (option_mask32 & OPT_x) { + found = (gl->matched_range.rm_so == 0 + && line[gl->matched_range.rm_eo] == '\0'); + } else if (!(option_mask32 & OPT_w)) { found = 1; - else { + } else { char c = ' '; if (gl->matched_range.rm_so) c = line[gl->matched_range.rm_so - 1]; @@ -563,20 +568,20 @@ static char *add_grep_list_data(char *pattern) static void load_regexes_from_file(llist_t *fopt) { - char *line; - FILE *f; - while (fopt) { + char *line; + FILE *fp; llist_t *cur = fopt; char *ffile = cur->data; fopt = cur->link; free(cur); - f = xfopen_stdin(ffile); - while ((line = xmalloc_fgetline(f)) != NULL) { + fp = xfopen_stdin(ffile); + while ((line = xmalloc_fgetline(fp)) != NULL) { llist_add_to(&pattern_head, new_grep_list_data(line, ALLOCATED)); } + fclose_if_not_stdin(fp); } } @@ -660,15 +665,19 @@ int grep_main(int argc UNUSED_PARAM, char **argv) #endif invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ - if (pattern_head != NULL) { - /* convert char **argv to grep_list_data_t */ + { /* 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) + if (option_mask32 & OPT_f) { load_regexes_from_file(fopt); + if (!pattern_head) { /* -f EMPTY_FILE? */ + /* GNU grep treats it as "nothing matches" */ + llist_add_to(&pattern_head, new_grep_list_data((char*) "", 0)); + invert_search ^= 1; + } + } if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f') option_mask32 |= OPT_F; diff --git a/release/src/router/busybox/findutils/xargs.c b/release/src/router/busybox/findutils/xargs.c index d73fad9de6..0d1bb43fc8 100644 --- a/release/src/router/busybox/findutils/xargs.c +++ b/release/src/router/busybox/findutils/xargs.c @@ -15,10 +15,6 @@ * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html */ -//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs)) - -//kbuild:lib-$(CONFIG_XARGS) += xargs.o - //config:config XARGS //config: bool "xargs" //config: default y @@ -58,6 +54,10 @@ //config: instead of whitespace, and the quotes and backslash //config: are not special. +//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs)) + +//kbuild:lib-$(CONFIG_XARGS) += xargs.o + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -89,7 +89,9 @@ struct globals { int idx; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) +#define INIT_G() do { \ + G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ +} while (0) /* @@ -347,7 +349,6 @@ static int xargs_ask_confirmation(void) //usage: "[OPTIONS] [PROG ARGS]" //usage:#define xargs_full_usage "\n\n" //usage: "Run PROG on every item given by stdin\n" -//usage: "\nOptions:" //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( //usage: "\n -p Ask user whether to run each command" //usage: ) @@ -412,7 +413,12 @@ int xargs_main(int argc, char **argv) INIT_G(); - G.eof_str = NULL; +#if ENABLE_DESKTOP && ENABLE_LONG_OPTS + /* For example, Fedora's build system uses --no-run-if-empty */ + applet_long_options = + "no-run-if-empty\0" No_argument "r" + ; +#endif opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); /* -E ""? You may wonder why not just omit -E? diff --git a/release/src/router/busybox/include/.gitignore b/release/src/router/busybox/include/.gitignore index f0ce546cf1..9d9b6c4996 100644 --- a/release/src/router/busybox/include/.gitignore +++ b/release/src/router/busybox/include/.gitignore @@ -1,6 +1,10 @@ /config +/applets.h /applet_tables.h /autoconf.h +/bbconfigopts_bz2.h /bbconfigopts.h +/NUM_APPLETS.h /usage_compressed.h +/usage.h diff --git a/release/src/router/busybox/include/applet_metadata.h b/release/src/router/busybox/include/applet_metadata.h new file mode 100644 index 0000000000..566ef3517d --- /dev/null +++ b/release/src/router/busybox/include/applet_metadata.h @@ -0,0 +1,30 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#ifndef APPLET_METADATA_H +#define APPLET_METADATA_H 1 + +/* Note: can be included by both host and target builds! */ + +/* 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, +#if ENABLE_INSTALL_NO_USR + BB_DIR_USR_BIN = BB_DIR_BIN, + BB_DIR_USR_SBIN = BB_DIR_SBIN, +#else + BB_DIR_USR_BIN, + BB_DIR_USR_SBIN, +#endif +} bb_install_loc_t; + +typedef enum bb_suid_t { + BB_SUID_DROP = 0, + BB_SUID_MAYBE, + BB_SUID_REQUIRE +} bb_suid_t; + +#endif diff --git a/release/src/router/busybox/include/applets.src.h b/release/src/router/busybox/include/applets.src.h dissimilarity index 85% index f4fab53eef..252a060fb1 100644 --- a/release/src/router/busybox/include/applets.src.h +++ b/release/src/router/busybox/include/applets.src.h @@ -1,417 +1,424 @@ -/* 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. - */ - -/* -name - applet name as it is typed on command line -name2 - applet name, converted to C (ether-wake: name2 = ether_wake) -main - corresponding _main to call (bzcat: main = bunzip2) -l - location to install link to: [/usr]/[s]bin -s - suid type: - _BB_SUID_REQUIRE: will complain if busybox isn't suid - and is run by non-root (applet_main() will not be called at all) - _BB_SUID_DROP: 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) MAKE_USAGE(#name, name##_trivial_usage name##_full_usage) -# define APPLET_ODDNAME(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) -# define APPLET_NOEXEC(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) -# define APPLET_NOFORK(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) - -#elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE -# define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage) -# define APPLET_ODDNAME(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) -# define APPLET_NOEXEC(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) -# define APPLET_NOFORK(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) - -#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 - - -INSERT -IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -IF_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -IF_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) -IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) -IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CAT(APPLET_NOFORK(cat, cat, _BB_DIR_BIN, _BB_SUID_DROP, cat)) -IF_CATV(APPLET(catv, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CHAT(APPLET(chat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHATTR(APPLET(chattr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CHCON(APPLET(chcon, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, _BB_DIR_BIN, _BB_SUID_DROP, chgrp)) -IF_CHMOD(APPLET_NOEXEC(chmod, chmod, _BB_DIR_BIN, _BB_SUID_DROP, chmod)) -IF_CHOWN(APPLET_NOEXEC(chown, chown, _BB_DIR_BIN, _BB_SUID_DROP, chown)) -IF_CHPASSWD(APPLET(chpasswd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CKSUM(APPLET_NOEXEC(cksum, cksum, _BB_DIR_USR_BIN, _BB_SUID_DROP, cksum)) -IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp)) -IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut)) -IF_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_DROP, dd)) -IF_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_DROP, delgroup)) -IF_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirname)) -IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE)) -IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname)) -IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, dos2unix)) -IF_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_DROP, dpkg_deb)) -IF_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//IF_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP)) -//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP, e2label)) -IF_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_DROP, echo)) -IF_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_ENV(APPLET_NOEXEC(env, env, _BB_DIR_USR_BIN, _BB_SUID_DROP, env)) -IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, envdir)) -IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, envuidgid)) -IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_DROP, ether_wake)) -IF_EXPAND(APPLET(expand, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_EXPR(APPLET(expr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FAKEIDENTD(APPLET(fakeidentd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FALSE(APPLET_NOFORK(false, false, _BB_DIR_BIN, _BB_SUID_DROP, false)) -IF_FBSET(APPLET(fbset, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_DROP, fdflush)) -IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FGCONSOLE(APPLET(fgconsole, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) -IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_lock)) -IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_unlock)) -IF_FLASHCP(APPLET(flashcp, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FLOCK(APPLET(flock, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FOLD(APPLET_NOEXEC(fold, fold, _BB_DIR_USR_BIN, _BB_SUID_DROP, fold)) -IF_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_DROP)) -//IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_ext2)) -//IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_ext3)) -IF_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_minix)) -IF_FSYNC(APPLET_NOFORK(fsync, fsync, _BB_DIR_BIN, _BB_SUID_DROP, fsync)) -IF_FTPD(APPLET(ftpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_DROP, ftpget)) -IF_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_DROP, ftpput)) -IF_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hd)) -IF_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_HEAD(APPLET_NOEXEC(head, head, _BB_DIR_USR_BIN, _BB_SUID_DROP, head)) -IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdump)) -IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) -IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ID(APPLET_NOEXEC(id, id, _BB_DIR_USR_BIN, _BB_SUID_DROP, id)) -IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifdown)) -IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_IFPLUGD(APPLET(ifplugd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifup)) -IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_DROP)) -#if ENABLE_FEATURE_IP_ADDRESS \ - || ENABLE_FEATURE_IP_ROUTE \ - || ENABLE_FEATURE_IP_LINK \ - || ENABLE_FEATURE_IP_TUNNEL \ - || ENABLE_FEATURE_IP_RULE -IF_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_DROP)) -#endif -IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_KBD_MODE(APPLET(kbd_mode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) -IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) -IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) -IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32)) -IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64)) -IF_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_DROP, ln)) -IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_REQUIRE)) -IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_DROP, logname)) -IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LPD(APPLET(lpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpq)) -IF_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpr)) -IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_DROP, ls)) -IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat)) -IF_LZMA(APPLET_ODDNAME(lzma, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzma)) -IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat)) -IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, md5sum)) -IF_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_DROP, mkdir)) -IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) -IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) -IF_MKFIFO(APPLET_NOEXEC(mkfifo, mkfifo, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkfifo)) -IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) -//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext3)) -IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_minix)) -IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_reiser)) -IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) -IF_MKNOD(APPLET_NOEXEC(mknod, mknod, _BB_DIR_BIN, _BB_SUID_DROP, mknod)) -IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkpasswd)) -IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) -IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) -IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE)) -IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill)) -IF_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_PRINTENV(APPLET_NOFORK(printenv, printenv, _BB_DIR_BIN, _BB_SUID_DROP, printenv)) -IF_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_DROP, printf)) -IF_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_DROP, pwd)) -IF_RAIDAUTORUN(APPLET(raidautorun, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RDATE(APPLET(rdate, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_RDEV(APPLET(rdev, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_DROP, restorecon)) -IF_RFKILL(APPLET(rfkill, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm)) -IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir)) -IF_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_DROP, run_parts)) -IF_RUNCON(APPLET(runcon, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SCRIPTREPLAY(APPLET(scriptreplay, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_DROP, seq)) -IF_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SETFONT(APPLET(setfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) -IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) -IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) -IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) -IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) -/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ -IF_SLEEP(APPLET(sleep, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) -IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) -IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DIR_SBIN, _BB_SUID_DROP, start_stop_daemon)) -IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_REQUIRE)) -IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapoff)) -IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapon)) -IF_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_DROP, sync)) -IF_BB_SYSCTL(APPLET(sysctl, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_DROP, tac)) -IF_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -/* IF_TC(APPLET(tc, _BB_DIR_SBIN, _BB_SUID_DROP)) */ -IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, tcpsvd)) -IF_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_TEST(APPLET_NOFORK(test, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT -IF_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -#endif -IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) -IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) -IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) -IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) -IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, udpsvd)) -IF_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_DROP, unexpand)) -IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, unix2dos)) -IF_UNXZ(APPLET(unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, unlzop)) -IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_DROP, usleep)) -IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_VOLNAME(APPLET(volname, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WALL(APPLET(wall, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_WC(APPLET(wc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WGET(APPLET(wget, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_DROP, whoami)) -IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xzcat)) -IF_XZ(APPLET_ODDNAME(xz, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xz)) -IF_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_DROP, yes)) -IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_DROP, zcat)) -IF_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_DROP)) - -#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) -}; -#endif - -#undef APPLET -#undef APPLET_ODDNAME -#undef APPLET_NOEXEC -#undef APPLET_NOFORK +/* 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. + */ + +/* +name - applet name as it is typed on command line +name2 - applet name, converted to C (ether-wake: name2 = ether_wake) +main - corresponding _main to call (bzcat: main = bunzip2) +l - location to install link to: [/usr]/[s]bin +s - suid type: + BB_SUID_REQUIRE: will complain if busybox isn't suid + and is run by non-root (applet_main() will not be called at all) + BB_SUID_DROP: will drop suid prior to applet_main() + BB_SUID_MAYBE: neither of the above + (every instance of BB_SUID_REQUIRE and BB_SUID_MAYBE + needs to be justified in comment) + NB: please update FEATURE_SUID help text whenever you add/remove + BB_SUID_REQUIRE or BB_SUID_MAYBE applet. +*/ + +#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) MAKE_USAGE(#name, name##_trivial_usage name##_full_usage) +# define APPLET_ODDNAME(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) +# define APPLET_NOEXEC(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) +# define APPLET_NOFORK(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage name2##_full_usage) + +#elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE +# define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage) +# define APPLET_ODDNAME(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) +# define APPLET_NOEXEC(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) +# define APPLET_NOFORK(name,main,l,s,name2) MAKE_USAGE(#name, name2##_trivial_usage) + +#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 + + +INSERT +IF_TEST(APPLET_NOFORK([, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +IF_TEST(APPLET_NOFORK([[, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP)) +IF_ADDGROUP(APPLET(addgroup, BB_DIR_BIN, BB_SUID_DROP)) +IF_ADDUSER(APPLET(adduser, BB_DIR_BIN, BB_SUID_DROP)) +IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) +IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP)) +IF_ARPING(APPLET(arping, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk)) +IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename)) +IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP)) +IF_BEEP(APPLET(beep, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP)) +IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) +IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP)) +IF_CHAT(APPLET(chat, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP)) +IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, BB_DIR_BIN, BB_SUID_DROP, chgrp)) +IF_CHMOD(APPLET_NOEXEC(chmod, chmod, BB_DIR_BIN, BB_SUID_DROP, chmod)) +IF_CHOWN(APPLET_NOEXEC(chown, chown, BB_DIR_BIN, BB_SUID_DROP, chown)) +IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CHPST(APPLET(chpst, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHROOT(APPLET(chroot, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) +IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) +IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP)) +IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */ +IF_CRONTAB(APPLET(crontab, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_CRYPTPW(APPLET(cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CUT(APPLET_NOEXEC(cut, cut, BB_DIR_USR_BIN, BB_SUID_DROP, cut)) +IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DD(APPLET_NOEXEC(dd, dd, BB_DIR_BIN, BB_SUID_DROP, dd)) +IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_BIN, BB_SUID_DROP, delgroup)) +IF_DELUSER(APPLET(deluser, BB_DIR_BIN, BB_SUID_DROP)) +IF_DEVFSD(APPLET(devfsd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP)) +IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) +IF_DHCPRELAY(APPLET(dhcprelay, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DIRNAME(APPLET_NOFORK(dirname, dirname, BB_DIR_USR_BIN, BB_SUID_DROP, dirname)) +IF_DMESG(APPLET(dmesg, BB_DIR_BIN, BB_SUID_DROP)) +IF_DNSD(APPLET(dnsd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) +IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, dos2unix)) +IF_DPKG(APPLET(dpkg, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, BB_DIR_USR_BIN, BB_SUID_DROP, dpkg_deb)) +IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP)) +IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_E2FSCK(APPLET(e2fsck, BB_DIR_SBIN, BB_SUID_DROP)) +//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) +IF_ECHO(APPLET_NOFORK(echo, echo, BB_DIR_BIN, BB_SUID_DROP, echo)) +IF_ED(APPLET(ed, BB_DIR_BIN, BB_SUID_DROP)) +IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) +IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) +IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) +IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, BB_DIR_USR_BIN, BB_SUID_DROP, ether_wake)) +IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FAKEIDENTD(APPLET(fakeidentd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FALSE(APPLET_NOFORK(false, false, BB_DIR_BIN, BB_SUID_DROP, false)) +IF_FBSET(APPLET(fbset, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FBSPLASH(APPLET(fbsplash, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush)) +IF_FDFORMAT(APPLET(fdformat, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FDISK(APPLET(fdisk, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Benefits from suid root: better access to /dev/BLOCKDEVs: */ +IF_FINDFS(APPLET(findfs, BB_DIR_SBIN, BB_SUID_MAYBE)) +IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) +IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) +IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FLOCK(APPLET(flock, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FOLD(APPLET_NOEXEC(fold, fold, BB_DIR_USR_BIN, BB_SUID_DROP, fold)) +IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FREERAMDISK(APPLET(freeramdisk, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FSCK(APPLET(fsck, BB_DIR_SBIN, BB_SUID_DROP)) +//IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, fsck_ext2)) +//IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, fsck_ext3)) +IF_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, BB_DIR_SBIN, BB_SUID_DROP, fsck_minix)) +IF_FSYNC(APPLET_NOFORK(fsync, fsync, BB_DIR_BIN, BB_SUID_DROP, fsync)) +IF_FTPD(APPLET(ftpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, BB_DIR_USR_BIN, BB_SUID_DROP, ftpget)) +IF_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, BB_DIR_USR_BIN, BB_SUID_DROP, ftpput)) +IF_FUSER(APPLET(fuser, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_GETENFORCE(APPLET(getenforce, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP)) +IF_GETSEBOOL(APPLET(getsebool, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP)) +IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP)) +IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP)) +IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd)) +IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP)) +IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) +IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump)) +IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP)) +IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_HWCLOCK(APPLET(hwclock, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFCONFIG(APPLET(ifconfig, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifdown)) +IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFPLUGD(APPLET(ifplugd, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifup)) +IF_INETD(APPLET(inetd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_INOTIFYD(APPLET(inotifyd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_INSTALL(APPLET(install, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP)) +#if ENABLE_FEATURE_IP_ADDRESS \ + || ENABLE_FEATURE_IP_ROUTE \ + || ENABLE_FEATURE_IP_LINK \ + || ENABLE_FEATURE_IP_TUNNEL \ + || ENABLE_FEATURE_IP_RULE +IF_IP(APPLET(ip, BB_DIR_BIN, BB_SUID_DROP)) +#endif +IF_IPADDR(APPLET(ipaddr, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IPCS(APPLET(ipcs, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IPLINK(APPLET(iplink, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPROUTE(APPLET(iproute, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPRULE(APPLET(iprule, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPTUNNEL(APPLET(iptunnel, BB_DIR_BIN, BB_SUID_DROP)) +IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) +IF_KILLALL(APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) +IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall5)) +IF_KLOGD(APPLET(klogd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length)) +IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETARCH(APPLET_ODDNAME(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) +IF_SETARCH(APPLET_ODDNAME(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) +IF_LN(APPLET_NOEXEC(ln, ln, BB_DIR_BIN, BB_SUID_DROP, ln)) +IF_LOAD_POLICY(APPLET(load_policy, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LOADFONT(APPLET(loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LOADKMAP(APPLET(loadkmap, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LOGGER(APPLET(logger, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_LOGIN(APPLET(login, BB_DIR_BIN, BB_SUID_REQUIRE)) +IF_LOGNAME(APPLET_NOFORK(logname, logname, BB_DIR_USR_BIN, BB_SUID_DROP, logname)) +IF_LOGREAD(APPLET(logread, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LPD(APPLET(lpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LPQ(APPLET_ODDNAME(lpq, lpqr, BB_DIR_USR_BIN, BB_SUID_DROP, lpq)) +IF_LPR(APPLET_ODDNAME(lpr, lpqr, BB_DIR_USR_BIN, BB_SUID_DROP, lpr)) +IF_LS(APPLET_NOEXEC(ls, ls, BB_DIR_BIN, BB_SUID_DROP, ls)) +IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP)) +IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat)) +IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma)) +IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP)) +IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat)) +IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP)) +IF_MAKEMIME(APPLET(makemime, BB_DIR_BIN, BB_SUID_DROP)) +IF_MAN(APPLET(man, BB_DIR_SBIN, BB_SUID_DROP)) +IF_MATCHPATHCON(APPLET(matchpathcon, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum)) +IF_MICROCOM(APPLET(microcom, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) +IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat)) +IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext2)) +IF_MKFIFO(APPLET_NOEXEC(mkfifo, mkfifo, BB_DIR_USR_BIN, BB_SUID_DROP, mkfifo)) +IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext2)) +//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext3)) +IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, BB_DIR_SBIN, BB_SUID_DROP, mkfs_minix)) +IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, BB_DIR_SBIN, BB_SUID_DROP, mkfs_reiser)) +IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat)) +IF_MKNOD(APPLET_NOEXEC(mknod, mknod, BB_DIR_BIN, BB_SUID_DROP, mknod)) +IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, mkpasswd)) +IF_MKSWAP(APPLET(mkswap, BB_DIR_SBIN, BB_SUID_DROP)) +IF_MKTEMP(APPLET(mktemp, BB_DIR_BIN, BB_SUID_DROP)) +IF_MORE(APPLET(more, BB_DIR_BIN, BB_SUID_DROP)) +/* On full-blown systems, requires suid for user mounts. + * But it's not unthinkable to have it available in non-suid flavor on some systems, + * for viewing mount table. + * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */ +IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP))) +IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP)) +IF_MT(APPLET(mt, BB_DIR_BIN, BB_SUID_DROP)) +IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) +IF_NAMEIF(APPLET(nameif, BB_DIR_SBIN, BB_SUID_DROP)) +IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NETSTAT(APPLET(netstat, BB_DIR_BIN, BB_SUID_DROP)) +IF_NICE(APPLET(nice, BB_DIR_BIN, BB_SUID_DROP)) +IF_NOHUP(APPLET(nohup, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NTPD(APPLET(ntpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_OD(APPLET(od, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_OPENVT(APPLET(openvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */ +IF_PASSWD(APPLET(passwd, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) +IF_PIPE_PROGRESS(APPLET(pipe_progress, BB_DIR_BIN, BB_SUID_DROP)) +IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP)) +IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) +IF_POPMAILDIR(APPLET(popmaildir, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_PRINTENV(APPLET_NOFORK(printenv, printenv, BB_DIR_BIN, BB_SUID_DROP, printenv)) +IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) +IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP)) +IF_PSCAN(APPLET(pscan, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_PWD(APPLET_NOFORK(pwd, pwd, BB_DIR_BIN, BB_SUID_DROP, pwd)) +IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RDATE(APPLET(rdate, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_READAHEAD(APPLET(readahead, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_READPROFILE(APPLET(readprofile, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_REFORMIME(APPLET(reformime, BB_DIR_BIN, BB_SUID_DROP)) +IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, BB_DIR_SBIN, BB_SUID_DROP, restorecon)) +IF_RFKILL(APPLET(rfkill, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) +IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) +IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) +IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts)) +IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RUNSV(APPLET(runsv, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RUNSVDIR(APPLET(runsvdir, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RX(APPLET(rx, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SCRIPT(APPLET(script, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SCRIPTREPLAY(APPLET(scriptreplay, BB_DIR_BIN, BB_SUID_DROP)) +IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP)) +IF_SELINUXENABLED(APPLET(selinuxenabled, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SENDMAIL(APPLET(sendmail, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) +IF_SESTATUS(APPLET(sestatus, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETARCH(APPLET(setarch, BB_DIR_BIN, BB_SUID_DROP)) +IF_SETCONSOLE(APPLET(setconsole, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SETENFORCE(APPLET(setenforce, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETFILES(APPLET(setfiles, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SETFONT(APPLET(setfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETKEYCODES(APPLET(setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETLOGCONS(APPLET(setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETSEBOOL(APPLET(setsebool, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) +IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) +IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) +IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) +IF_SHOWKEY(APPLET(showkey, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) +/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells: */ +IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) +IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) +IF_SORT(APPLET_NOEXEC(sort, sort, BB_DIR_USR_BIN, BB_SUID_DROP, sort)) +IF_SPLIT(APPLET(split, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) +IF_STAT(APPLET(stat, BB_DIR_BIN, BB_SUID_DROP)) +IF_STRINGS(APPLET(strings, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_STTY(APPLET(stty, BB_DIR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_SU(APPLET(su, BB_DIR_BIN, BB_SUID_REQUIRE)) +IF_SULOGIN(APPLET(sulogin, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SUM(APPLET(sum, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SV(APPLET(sv, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SVLOGD(APPLET(svlogd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, BB_DIR_SBIN, BB_SUID_DROP, swapoff)) +IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, BB_DIR_SBIN, BB_SUID_DROP, swapon)) +IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SYNC(APPLET_NOFORK(sync, sync, BB_DIR_BIN, BB_SUID_DROP, sync)) +IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) +IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP)) +IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */ +IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) +IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TELNET(APPLET(telnet, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TELNETD(APPLET(telnetd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_TEST(APPLET_NOFORK(test, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT +IF_TFTP(APPLET(tftp, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TFTPD(APPLET(tftpd, BB_DIR_USR_BIN, BB_SUID_DROP)) +#endif +IF_TIME(APPLET(time, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TOP(APPLET(top, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TR(APPLET(tr, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore BB_SUID_MAYBE: */ +IF_TRACEROUTE(APPLET(traceroute, BB_DIR_USR_BIN, BB_SUID_MAYBE)) +IF_TRACEROUTE6(APPLET(traceroute6, BB_DIR_USR_BIN, BB_SUID_MAYBE)) +IF_TRUE(APPLET_NOFORK(true, true, BB_DIR_BIN, BB_SUID_DROP, true)) +IF_TTY(APPLET(tty, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TTYSIZE(APPLET(ttysize, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TUNCTL(APPLET(tunctl, BB_DIR_SBIN, BB_SUID_DROP)) +IF_TUNE2FS(APPLET(tune2fs, BB_DIR_SBIN, BB_SUID_DROP)) +IF_UDHCPC(APPLET(udhcpc, BB_DIR_SBIN, BB_SUID_DROP)) +IF_UDHCPD(APPLET(udhcpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, udpsvd)) +IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP)) +IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP)) +IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP)) +IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, BB_DIR_USR_BIN, BB_SUID_DROP, unexpand)) +IF_UNIQ(APPLET(uniq, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, unix2dos)) +IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_LZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop)) +IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_USLEEP(APPLET_NOFORK(usleep, usleep, BB_DIR_BIN, BB_SUID_DROP, usleep)) +IF_UUDECODE(APPLET(uudecode, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UUENCODE(APPLET(uuencode, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_VCONFIG(APPLET(vconfig, BB_DIR_SBIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_VOLNAME(APPLET(volname, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */ +IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP)) +IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) +IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami)) +IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat)) +IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz)) +IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) +IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat)) +IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP)) + +#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/release/src/router/busybox/include/bb_archive.h b/release/src/router/busybox/include/bb_archive.h new file mode 100644 index 0000000000..2043d8570d --- /dev/null +++ b/release/src/router/busybox/include/bb_archive.h @@ -0,0 +1,244 @@ +/* vi: set sw=4 ts=4: */ +#ifndef UNARCHIVE_H +#define UNARCHIVE_H 1 + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +enum { +#if BB_BIG_ENDIAN + COMPRESS_MAGIC = 0x1f9d, + GZIP_MAGIC = 0x1f8b, + BZIP2_MAGIC = 256 * 'B' + 'Z', + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ + XZ_MAGIC1 = 256 * 0xfd + '7', + XZ_MAGIC2 = 256 * (unsigned)(256 * (256 * 'z' + 'X') + 'Z') + 0, + /* Different form: 32 bits, then 16 bits: */ + /* (unsigned) cast suppresses "integer overflow in expression" warning */ + XZ_MAGIC1a = 256 * (unsigned)(256 * (256 * 0xfd + '7') + 'z') + 'X', + XZ_MAGIC2a = 256 * 'Z' + 0, +#else + COMPRESS_MAGIC = 0x9d1f, + GZIP_MAGIC = 0x8b1f, + BZIP2_MAGIC = 'B' + 'Z' * 256, + XZ_MAGIC1 = 0xfd + '7' * 256, + XZ_MAGIC2 = 'z' + ('X' + ('Z' + 0 * 256) * 256) * 256, + XZ_MAGIC1a = 0xfd + ('7' + ('z' + 'X' * 256) * 256) * 256, + XZ_MAGIC2a = 'Z' + 0 * 256, +#endif +}; + +typedef struct file_header_t { + char *name; + char *link_target; +#if ENABLE_FEATURE_TAR_UNAME_GNAME + char *tar__uname; + char *tar__gname; +#endif + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; + +struct hardlinks_t; + +typedef struct archive_handle_t { + /* Flags. 1st since it is most used member */ + unsigned ah_flags; + + /* The raw stream as read from disk or stdin */ + int src_fd; + + /* Define if the header and data component should be processed */ + char FAST_FUNC (*filter)(struct archive_handle_t *); + /* List of files that have been accepted */ + 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; + + /* Currently processed file's header */ + file_header_t *file_header; + + /* Process the header component, e.g. tar -t */ + void FAST_FUNC (*action_header)(const file_header_t *); + + /* Process the data component, e.g. extract to filesystem */ + void FAST_FUNC (*action_data)(struct archive_handle_t *); + + /* Function that skips data */ + void FAST_FUNC (*seek)(int fd, off_t amount); + + /* Count processed bytes */ + off_t offset; + + /* Archiver specific. Can make it a union if it ever gets big */ +#define PAX_NEXT_FILE 0 +#define PAX_GLOBAL 1 +#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB + smallint tar__end; +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + char* tar__longname; + char* tar__linkname; +# endif +# if ENABLE_FEATURE_TAR_TO_COMMAND + char* tar__to_command; + const char* tar__to_command_shell; +# endif +# if ENABLE_FEATURE_TAR_SELINUX + char* tar__sctx[2]; +# endif +#endif +#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM + uoff_t cpio__blocks; + struct hardlinks_t *cpio__hardlinks_to_create; + struct hardlinks_t *cpio__created_hardlinks; +#endif +#if ENABLE_DPKG || ENABLE_DPKG_DEB + /* Temporary storage */ + char *dpkg__buffer; + /* How to process any sub archive, e.g. get_header_tar_gz */ + char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *); + /* Contains the handle to a sub archive */ + struct archive_handle_t *dpkg__sub_archive; +#endif +#if ENABLE_FEATURE_AR_CREATE + const char *ar__name; + struct archive_handle_t *ar__out; +#endif +} archive_handle_t; +/* bits in ah_flags */ +#define ARCHIVE_RESTORE_DATE (1 << 0) +#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) +#define ARCHIVE_UNLINK_OLD (1 << 2) +#define ARCHIVE_EXTRACT_QUIET (1 << 3) +#define ARCHIVE_EXTRACT_NEWER (1 << 4) +#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) +#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) +#define ARCHIVE_NUMERIC_OWNER (1 << 7) +#define ARCHIVE_O_TRUNC (1 << 8) + + +/* POSIX tar Header Block, from POSIX 1003.1-1990 */ +#define TAR_BLOCK_SIZE 512 +#define NAME_SIZE 100 +#define NAME_SIZE_STR "100" +typedef struct tar_header_t { /* 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) */ +} tar_header_t; +struct BUG_tar_header { + char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; +}; + + + +archive_handle_t *init_handle(void) FAST_FUNC; + +char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_reject_list(archive_handle_t *archive_handle) FAST_FUNC; + +void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; + +void data_skip(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; + +void header_skip(const file_header_t *file_header) FAST_FUNC; +void header_list(const file_header_t *file_header) FAST_FUNC; +void header_verbose_list(const file_header_t *file_header) FAST_FUNC; + +char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_gz(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_bz2(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_lzma(archive_handle_t *archive_handle) FAST_FUNC; + +void seek_by_jump(int fd, off_t amount) FAST_FUNC; +void seek_by_read(int fd, off_t amount) FAST_FUNC; + +const char *strip_unsafe_prefix(const char *str) FAST_FUNC; + +void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; +const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; +const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; + +/* 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 void *inbuf, int len) FAST_FUNC; +/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes + * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */ +int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; +void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; + +/* Meaning and direction (input/output) of the fields are transformer-specific */ +typedef struct transformer_aux_data_t { + smallint check_signature; /* most often referenced member */ + off_t bytes_out; + off_t bytes_in; /* used in unzip code only: needs to know packed size */ + uint32_t crc32; + time_t mtime; /* gunzip code may set this on exit */ +} transformer_aux_data_t; + +void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC; +int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC; + +IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; + +char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; +int bbunpack(char **argv, + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), + char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), + const char *expected_ext +) FAST_FUNC; + +void check_errors_in_children(int signo); +#if BB_MMU +void open_transformer(int fd, + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) +) FAST_FUNC; +#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer)) +#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer)) +#else +void open_transformer(int fd, const char *transform_prog) FAST_FUNC; +#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog)) +/* open_transformer_with_no_sig() does not exist on NOMMU */ +#endif + + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/release/src/router/busybox/include/bb_e2fs_defs.h b/release/src/router/busybox/include/bb_e2fs_defs.h new file mode 100644 index 0000000000..3edff8377c --- /dev/null +++ b/release/src/router/busybox/include/bb_e2fs_defs.h @@ -0,0 +1,579 @@ +/* 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 1 + +/* + * 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 */ + /* ext3 additions */ + uint32_t s_mkfs_time; /* When the filesystem was created */ + uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */ + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ +/*150*/ uint32_t s_blocks_count_hi; /* Blocks count */ + uint32_t s_r_blocks_count_hi; /* Reserved blocks count */ + uint32_t s_free_blocks_count_hi; /* Free blocks count */ + uint16_t s_min_extra_isize; /* All inodes have at least # bytes */ + uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */ + uint32_t s_flags; /* Miscellaneous flags */ + uint16_t s_raid_stride; /* RAID stride */ + uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */ + uint64_t s_mmp_block; /* Block for multi-mount protection */ + uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + uint8_t s_log_groups_per_flex; /* FLEX_BG group size */ + uint8_t s_reserved_char_pad2; + uint16_t s_reserved_pad; + uint32_t s_reserved[162]; /* Padding to the end of the block */ +}; +struct BUG_ext2_super_block { + char bug[sizeof(struct ext2_super_block) == 1024 ? 1 : -1]; +}; + +/* + * 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_INO 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 diff --git a/release/src/router/busybox/include/busybox.h b/release/src/router/busybox/include/busybox.h index 757317fc70..315ef8f266 100644 --- a/release/src/router/busybox/include/busybox.h +++ b/release/src/router/busybox/include/busybox.h @@ -1,37 +1,16 @@ /* vi: set sw=4 ts=4: */ /* - * Busybox main internal header file - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef BUSYBOX_H #define BUSYBOX_H 1 #include "libbb.h" +/* BB_DIR_foo and BB_SUID_bar constants: */ +#include "applet_metadata.h" PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -/* 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, -#if ENABLE_INSTALL_NO_USR - _BB_DIR_USR_BIN = _BB_DIR_BIN, - _BB_DIR_USR_SBIN = _BB_DIR_SBIN, -#else - _BB_DIR_USR_BIN, - _BB_DIR_USR_SBIN, -#endif -} bb_install_loc_t; - -typedef enum bb_suid_t { - _BB_SUID_DROP = 0, - _BB_SUID_MAYBE, - _BB_SUID_REQUIRE -} 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[]; diff --git a/release/src/router/busybox/include/grp_.h b/release/src/router/busybox/include/grp_.h index 5c24d558ad..82ad904921 100644 --- a/release/src/router/busybox/include/grp_.h +++ b/release/src/router/busybox/include/grp_.h @@ -29,7 +29,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endgrent #define setgrent bb_internal_setgrent #define endgrent bb_internal_endgrent #define getgrent bb_internal_getgrent diff --git a/release/src/router/busybox/include/libbb.h b/release/src/router/busybox/include/libbb.h index d2425a3001..6ae8c504fa 100644 --- a/release/src/router/busybox/include/libbb.h +++ b/release/src/router/busybox/include/libbb.h @@ -20,12 +20,23 @@ #include #include #include +#if defined __UCLIBC__ /* TODO: and glibc? */ +/* use inlined versions of these: */ +# define sigfillset(s) __sigfillset(s) +# define sigemptyset(s) __sigemptyset(s) +# define sigisemptyset(s) __sigisemptyset(s) +#endif #include #include #include #include #include #include +/* There are two incompatible basename's, let not use them! */ +/* See the dirname/basename man page for details */ +#include /* dirname,basename */ +#undef basename +#define basename dont_use_basename #include #include #include @@ -33,23 +44,48 @@ #include #include #include +#ifndef major +# include +#endif #include #include #include -#include #include +#include +#include +#if ENABLE_FEATURE_SHADOWPASSWDS +# if !ENABLE_USE_BB_SHADOW +/* If using busybox's shadow implementation, do not include the shadow.h + * header as the toolchain may not provide it at all. + */ +# include +# endif +#endif +#if defined(ANDROID) || defined(__ANDROID__) +# define endpwent() ((void)0) +# define endgrent() ((void)0) +#endif #ifdef HAVE_MNTENT_H # include #endif #ifdef HAVE_SYS_STATFS_H # include #endif +/* Don't do this here: + * #include + * Some linux/ includes pull in conflicting definition + * of struct sysinfo (only in some toolchanins), which breaks build. + * Include sys/sysinfo.h only in those files which need it. + */ #if ENABLE_SELINUX # include # include # include # include #endif +#if ENABLE_FEATURE_UTMP +# include +#endif #if ENABLE_LOCALE_SUPPORT # include #else @@ -58,15 +94,18 @@ #ifdef DMALLOC # include #endif -#include -#include -#if ENABLE_FEATURE_SHADOWPASSWDS -# if !ENABLE_USE_BB_SHADOW -/* If using busybox's shadow implementation, do not include the shadow.h - * header as the toolchain may not provide it at all. - */ -# include -# endif +/* Just in case libc doesn't define some of these... */ +#ifndef _PATH_PASSWD +#define _PATH_PASSWD "/etc/passwd" +#endif +#ifndef _PATH_GROUP +#define _PATH_GROUP "/etc/group" +#endif +#ifndef _PATH_SHADOW +#define _PATH_SHADOW "/etc/shadow" +#endif +#ifndef _PATH_GSHADOW +#define _PATH_GSHADOW "/etc/gshadow" #endif #if defined __FreeBSD__ || defined __OpenBSD__ # include @@ -84,6 +123,15 @@ typedef unsigned socklen_t; # endif #endif +#ifndef HAVE_CLEARENV +# define clearenv() do { if (environ) environ[0] = NULL; } while (0) +#endif +#ifndef HAVE_FDATASYNC +# define fdatasync fsync +#endif +#ifndef HAVE_XTABS +# define XTABS TAB3 +#endif /* Some libc's forget to declare these, do it ourself */ @@ -94,31 +142,6 @@ 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 in order to avoid - * confusing the two versions of basename. See the dirname/basename man page - * for details. */ -#if !defined __FreeBSD__ -char *dirname(char *path); -#endif -/* 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); #ifndef PATH_MAX # define PATH_MAX 256 #endif @@ -127,6 +150,30 @@ int sysinfo(struct sysinfo* info); #endif +/* Busybox does not use threads, we can speed up stdio. */ +#ifdef HAVE_UNLOCKED_STDIO +# undef getc +# define getc(stream) getc_unlocked(stream) +# undef getchar +# define getchar() getchar_unlocked() +# undef putc +# define putc(c, stream) putc_unlocked(c, stream) +# undef putchar +# define putchar(c) putchar_unlocked(c) +# undef fgetc +# define fgetc(stream) getc_unlocked(stream) +# undef fputc +# define fputc(c, stream) putc_unlocked(c, stream) +#endif +/* Above functions are required by POSIX.1-2008, below ones are extensions */ +#ifdef HAVE_UNLOCKED_LINE_OPS +# undef fgets +# define fgets(s, n, stream) fgets_unlocked(s, n, stream) +# undef fputs +# define fputs(s, stream) fputs_unlocked(s, stream) +#endif + + /* Make all declarations hidden (-fvisibility flag only affects definitions) */ /* (don't include system headers after this until corresponding pop!) */ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN @@ -168,7 +215,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN # if ULONG_MAX > 0xffffffff /* "long" is long enough on this system */ typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# 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 @@ -177,7 +224,7 @@ typedef unsigned long uoff_t; # else /* "long" is too short, need "long long" */ typedef unsigned long long uoff_t; -# define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX) +# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) # define BB_STRTOOFF bb_strtoull # define STRTOOFF strtoull # define OFF_FMT "ll" @@ -194,7 +241,7 @@ typedef unsigned long uoff_t; # define OFF_FMT "l" # else typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX) # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtol # define OFF_FMT "l" @@ -202,6 +249,12 @@ typedef unsigned long uoff_t; #endif /* scary. better ideas? (but do *test* them first!) */ #define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) +/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested. + * We misdetected that. Don't let it build: + */ +struct BUG_off_t_size_is_misdetected { + char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1]; +}; /* Some useful definitions */ #undef FALSE @@ -211,13 +264,6 @@ typedef unsigned long uoff_t; #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)) @@ -272,7 +318,7 @@ extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC; //TODO: supply a pointer to char[11] buffer (avoid statics)? extern const char *bb_mode_string(mode_t mode) FAST_FUNC; -extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; +extern int is_directory(const char *name, int followLinks) FAST_FUNC; enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */ @@ -323,6 +369,7 @@ extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size) FAST_FUNC; /* "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) NORETURN FAST_FUNC; + extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC; /* xxxx_strip version can modify its parameter: @@ -331,13 +378,17 @@ char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC; * "abc/def" -> "def" * "abc/def/" -> "def" !! */ -extern char *bb_get_last_path_component_strip(char *path) FAST_FUNC; +char *bb_get_last_path_component_strip(char *path) FAST_FUNC; /* "abc/def/" -> "" and it never modifies 'path' */ -extern char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; +char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; +/* Simpler version: does not special case "/" string */ +const char *bb_basename(const char *name) FAST_FUNC; +/* NB: can violate const-ness (similarly to strchr) */ +char *last_char_is(const char *s, int c) FAST_FUNC; -int ndelay_on(int fd) FAST_FUNC; -int ndelay_off(int fd) FAST_FUNC; -int close_on_exec_on(int fd) FAST_FUNC; +void ndelay_on(int fd) FAST_FUNC; +void ndelay_off(int fd) FAST_FUNC; +void close_on_exec_on(int fd) FAST_FUNC; void xdup2(int, int) FAST_FUNC; void xmove_fd(int, int) FAST_FUNC; @@ -517,12 +568,7 @@ enum { * and if kernel doesn't support it, fall back to IPv4. * This is useful if you plan to bind to resulting local lsa. */ -#if ENABLE_FEATURE_IPV6 int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; -#else -int xsocket_type(len_and_sockaddr **lsap, int sock_type) FAST_FUNC; -#define xsocket_type(lsap, af, sock_type) xsocket_type((lsap), (sock_type)) -#endif int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; /* Create server socket bound to bindaddr:port. bindaddr can be NULL, * numeric IP ("N.N.N.N") or numeric IPv6 address, @@ -562,7 +608,7 @@ len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t /* 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) FAST_FUNC; +void set_nport(struct sockaddr *sa, unsigned port) FAST_FUNC; /* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */ int get_nport(const struct sockaddr *sa) FAST_FUNC; /* Reverse DNS. Returns NULL on failure. */ @@ -591,6 +637,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t sa_size) FAST_FUNC; +uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC; char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; @@ -635,17 +682,20 @@ void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC; void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC; void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC; void *xrealloc(void *old, size_t size) FAST_FUNC; -/* After xrealloc_vector(v, 4, idx) it's ok to use +/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use * at least v[idx] and v[idx+1], for all idx values. - * shift specifies how many new elements are added (1: 2, 2: 4... 8: 256...) - * when all elements are used up. New elements are zeroed out. */ + * SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...) + * when all elements are used up. New elements are zeroed out. + * xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs - + * skipping an index is a bad bug - it may miss a realloc! + */ #define xrealloc_vector(vector, shift, idx) \ xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx)) void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC; extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC; -extern ssize_t nonblock_safe_read(int fd, void *buf, size_t count) FAST_FUNC; +extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) FAST_FUNC; // 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) FAST_FUNC; @@ -656,25 +706,31 @@ extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FA // 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) FAST_FUNC; +extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC; /* Reads block up to *maxsz_p (default: INT_MAX - 4095) */ extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; /* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; -/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ -#if ENABLE_FEATURE_SEAMLESS_LZMA \ +/* Never returns NULL */ +extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; + +#define SEAMLESS_COMPRESSION (0 \ + || ENABLE_FEATURE_SEAMLESS_XZ \ + || ENABLE_FEATURE_SEAMLESS_LZMA \ || ENABLE_FEATURE_SEAMLESS_BZ2 \ || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ -extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; -#else -# define setup_unzip_on_fd(...) ((void)0) -#endif + || ENABLE_FEATURE_SEAMLESS_Z) + +#if SEAMLESS_COMPRESSION +/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ +extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; +#else +# define setup_unzip_on_fd(...) (0) +# define open_zipped(fname) open((fname), O_RDONLY); +#endif extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; -/* Never returns NULL */ -extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; // NB: will return short write on error, not -1, @@ -692,8 +748,12 @@ extern void xclose(int fd) FAST_FUNC; /* Reads and prints to stdout till eof, then closes FILE. Exits on error: */ extern void xprint_and_close_file(FILE *file) FAST_FUNC; +/* Reads a line from a text file, up to a newline or NUL byte, inclusive. + * Returns malloc'ed char*. If end is NULL '\n' isn't considered + * end of line. If end isn't NULL, length of the chunk is stored in it. + * Returns NULL if EOF/error. + */ extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC; -extern char *bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) FAST_FUNC; /* Reads up to (and including) TERMINATING_STRING: */ extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC; /* Same, with limited max size, and returns the length (excluding NUL): */ @@ -758,9 +818,9 @@ void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_F const char *make_human_readable_str(unsigned long long size, unsigned long block_size, unsigned long display_unit) FAST_FUNC; /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ -char *bin2hex(char *buf, const char *cp, int count) FAST_FUNC; +char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; /* Reverse */ -char* hex2bin(char *dst, const char *str, int count) FAST_FUNC; +char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; /* Generate a UUID */ void generate_uuid(uint8_t *buf) FAST_FUNC; @@ -816,14 +876,14 @@ char* xuid2uname(uid_t uid) FAST_FUNC; char* xgid2group(gid_t gid) FAST_FUNC; char* uid2uname(uid_t uid) FAST_FUNC; char* gid2group(gid_t gid) FAST_FUNC; -char* uid2uname_utoa(long uid) FAST_FUNC; -char* gid2group_utoa(long gid) FAST_FUNC; +char* uid2uname_utoa(uid_t uid) FAST_FUNC; +char* gid2group_utoa(gid_t gid) FAST_FUNC; /* versions which cache results (useful for ps, ls etc) */ const char* get_cached_username(uid_t uid) FAST_FUNC; const char* get_cached_groupname(gid_t gid) FAST_FUNC; void clear_username_cache(void) FAST_FUNC; /* internally usernames are saved in fixed-sized char[] buffers */ -enum { USERNAME_MAX_SIZE = 16 - sizeof(int) }; +enum { USERNAME_MAX_SIZE = 32 - sizeof(uid_t) }; #if ENABLE_FEATURE_CHECK_NAMES void die_if_bad_username(const char* name) FAST_FUNC; #else @@ -838,6 +898,7 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const # define update_utmp(pid, new_type, tty_name, username, hostname) ((void)0) #endif + int execable_file(const char *name) FAST_FUNC; char *find_execable(const char *filename, char **PATHp) FAST_FUNC; int exists_execable(const char *filename) FAST_FUNC; @@ -846,14 +907,16 @@ int exists_execable(const char *filename) FAST_FUNC; * 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[]) FAST_FUNC; -#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) +int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC; #define BB_EXECLP(prog,cmd,...) \ - execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \ - cmd, __VA_ARGS__) + do { \ + if (find_applet_by_name(prog) >= 0) \ + execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \ + execlp(prog, cmd, __VA_ARGS__); \ + } while (0) #else #define BB_EXECVP(prog,cmd) execvp(prog,cmd) -#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) +#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__) #endif int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; @@ -887,19 +950,8 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC; int wait4pid(pid_t pid) FAST_FUNC; /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */ int spawn_and_wait(char **argv) FAST_FUNC; -struct nofork_save_area { - jmp_buf die_jmp; - const char *applet_name; - uint32_t option_mask32; - int die_sleep; - uint8_t xfunc_error_retval; - smallint saved; -}; -void save_nofork_data(struct nofork_save_area *save) FAST_FUNC; -void restore_nofork_data(struct nofork_save_area *save) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; -int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) FAST_FUNC; /* Helpers for daemonization. * @@ -929,6 +981,7 @@ enum { DAEMON_DEVNULL_STDIO = 2, DAEMON_CLOSE_EXTRA_FDS = 4, DAEMON_ONLY_SANITIZE = 8, /* internal use */ + DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ }; #if BB_MMU enum { re_execed = 0 }; @@ -937,6 +990,9 @@ enum { # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else extern bool re_execed; + /* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU! + * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled. + */ void re_exec(char **argv) NORETURN FAST_FUNC; pid_t fork_or_rexec(char **argv) FAST_FUNC; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; @@ -966,9 +1022,13 @@ extern uint32_t option_mask32; extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* Having next pointer as a first member allows easy creation + * of "llist-compatible" structs, and using llist_FOO functions + * on them. + */ typedef struct llist_t { - char *data; struct llist_t *link; + char *data; } llist_t; void llist_add_to(llist_t **old_head, void *data) FAST_FUNC; void llist_add_to_end(llist_t **list_head, void *data) FAST_FUNC; @@ -1119,7 +1179,7 @@ extern int del_loop(const char *device) FAST_FUNC; /* 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) FAST_FUNC; +extern int set_loop(char **devname, const char *file, unsigned long long offset, int ro) FAST_FUNC; /* Like bb_ask below, but asks on stdin with no timeout. */ char *bb_ask_stdin(const char * prompt) FAST_FUNC; @@ -1140,18 +1200,20 @@ enum { PARSE_MIN_DIE = 0x00100000, // die if < min tokens found // keep a copy of current line PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, -// PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens + PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char // NORMAL is: // * remove leading and trailing delimiters and collapse // multiple delimiters into one // * warn and continue if less than mintokens delimiters found // * grab everything into last token - PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY, + // * comments are recognized even if they aren't the first char + PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY | PARSE_EOL_COMMENTS, }; typedef struct parser_t { FILE *fp; - char *line; char *data; + char *line, *nline; + size_t line_alloc, nline_alloc; int lineno; } parser_t; parser_t* config_open(const char *filename) FAST_FUNC; @@ -1167,10 +1229,8 @@ void config_close(parser_t *parser) FAST_FUNC; * If path is NULL, it is assumed to be "/". * filename should not be NULL. */ char *concat_path_file(const char *path, const char *filename) FAST_FUNC; +/* Returns NULL on . and .. */ char *concat_subpath_file(const char *path, const char *filename) FAST_FUNC; -const char *bb_basename(const char *name) FAST_FUNC; -/* NB: can violate const-ness (similarly to strchr) */ -char *last_char_is(const char *s, int c) FAST_FUNC; int bb_make_directory(char *path, long mode, int flags) FAST_FUNC; @@ -1183,10 +1243,17 @@ char *bb_simplify_path(const char *path) FAST_FUNC; /* Returns ptr to NUL */ char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; -#define FAIL_DELAY 3 +#define LOGIN_FAIL_DELAY 3 extern void bb_do_delay(int seconds) FAST_FUNC; extern void change_identity(const struct passwd *pw) FAST_FUNC; extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; + +/* Returns $SHELL, getpwuid(getuid())->pw_shell, or DEFAULT_SHELL. + * Note that getpwuid result might need xstrdup'ing + * if there is a possibility of intervening getpwxxx() calls. + */ +const char *get_shell_name(void); + #if ENABLE_SELINUX extern void renew_current_security_context(void) FAST_FUNC; extern void set_current_security_context(security_context_t sid) FAST_FUNC; @@ -1199,6 +1266,12 @@ extern void selinux_preserve_fcontext(int fdesc) FAST_FUNC; #endif extern void selinux_or_die(void) FAST_FUNC; + +/* systemd support */ +#define SD_LISTEN_FDS_START 3 +int sd_listen_fds(void); + + /* setup_environment: * if chdir pw->pw_dir: ok: else if to_tmp == 1: goto /tmp else: goto / or die * if clear_env = 1: cd(pw->pw_dir), clear environment, then set @@ -1225,14 +1298,19 @@ extern int correct_password(const struct passwd *pw) FAST_FUNC; #endif extern char *pw_encrypt(const char *clear, const char *salt, int cleanup) FAST_FUNC; extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; -/* rnd is additional random input. New one is returned. +/* + * 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) FAST_FUNC; +extern int crypt_make_salt(char *p, int cnt /*, int rnd*/) FAST_FUNC; +/* "$N$" + sha_salt_16_bytes + NUL */ +#define MAX_PW_SALT_LEN (3 + 16 + 1) +extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; + /* Returns number of lines changed, or -1 on error */ #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) @@ -1279,7 +1357,7 @@ void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST void reset_ino_dev_hashtable(void) FAST_FUNC; #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) FAST_FUNC; +unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC; #undef makedev #define makedev(a,b) bb_makedev(a,b) #endif @@ -1300,25 +1378,37 @@ enum { KEYCODE_DELETE = -9, KEYCODE_PAGEUP = -10, KEYCODE_PAGEDOWN = -11, - - KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40, - KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40, - KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40, - KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40, + // -12 is reserved for Alt/Ctrl/Shift-TAB #if 0 - KEYCODE_FUN1 = -12, - KEYCODE_FUN2 = -13, - KEYCODE_FUN3 = -14, - KEYCODE_FUN4 = -15, - KEYCODE_FUN5 = -16, - KEYCODE_FUN6 = -17, - KEYCODE_FUN7 = -18, - KEYCODE_FUN8 = -19, - KEYCODE_FUN9 = -20, - KEYCODE_FUN10 = -21, - KEYCODE_FUN11 = -22, - KEYCODE_FUN12 = -23, + KEYCODE_FUN1 = -13, + KEYCODE_FUN2 = -14, + KEYCODE_FUN3 = -15, + KEYCODE_FUN4 = -16, + KEYCODE_FUN5 = -17, + KEYCODE_FUN6 = -18, + KEYCODE_FUN7 = -19, + KEYCODE_FUN8 = -20, + KEYCODE_FUN9 = -21, + KEYCODE_FUN10 = -22, + KEYCODE_FUN11 = -23, + KEYCODE_FUN12 = -24, #endif + /* Be sure that last defined value is small enough + * to not interfere with Alt/Ctrl/Shift bits. + * So far we do not exceed -31 (0xfff..fffe1), + * which gives us three upper bits in LSB to play with. + */ + //KEYCODE_SHIFT_TAB = (-12) & ~0x80, + //KEYCODE_SHIFT_... = KEYCODE_... & ~0x80, + //KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40, + //KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40, + KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40, + KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40, + //KEYCODE_ALT_UP = KEYCODE_UP & ~0x20, + //KEYCODE_ALT_DOWN = KEYCODE_DOWN & ~0x20, + KEYCODE_ALT_RIGHT = KEYCODE_RIGHT & ~0x20, + KEYCODE_ALT_LEFT = KEYCODE_LEFT & ~0x20, + KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */ /* How long is the longest ESC sequence we know? * We want it big enough to be able to contain @@ -1345,8 +1435,9 @@ void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; #if ENABLE_FEATURE_EDITING /* It's NOT just ENABLEd or disabled. It's a number: */ -# ifdef CONFIG_FEATURE_EDITING_HISTORY +# if defined CONFIG_FEATURE_EDITING_HISTORY && CONFIG_FEATURE_EDITING_HISTORY > 0 # define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0) +unsigned size_from_HISTFILESIZE(const char *hp); # else # define MAX_HISTORY 0 # endif @@ -1356,7 +1447,14 @@ typedef struct line_input_t { # if MAX_HISTORY int cnt_history; int cur_history; + int max_history; /* must never be <= 0 */ # if ENABLE_FEATURE_EDITING_SAVEHISTORY + /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: + * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are + * in on-disk history" + * if FEATURE_EDITING_SAVE_ON_EXIT: "how many in-memory lines are + * also in on-disk history (and thus need to be skipped on save)" + */ unsigned cnt_history_in_file; const char *hist_file; # endif @@ -1364,27 +1462,30 @@ typedef struct line_input_t { # 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, + DO_HISTORY = 1 * (MAX_HISTORY > 0), + TAB_COMPLETION = 2 * ENABLE_FEATURE_TAB_COMPLETION, + USERNAME_COMPLETION = 4 * ENABLE_FEATURE_USERNAME_COMPLETION, + VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, + WITH_PATH_LOOKUP = 0x10, + FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION, }; line_input_t *new_line_input_t(int flags) FAST_FUNC; /* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */ -/* maxsize must be >= 2. +/* + * maxsize must be >= 2. * 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) FAST_FUNC; +int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +void save_history(line_input_t *st); +# endif #else #define MAX_HISTORY 0 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; -#define read_line_input(prompt, command, maxsize, state) \ +#define read_line_input(state, prompt, command, maxsize, timeout) \ read_line_input(prompt, command, maxsize) #endif @@ -1430,6 +1531,7 @@ typedef struct procps_status_t { char *argv0; char *exe; IF_SELINUX(char *context;) + IF_FEATURE_SHOW_THREADS(unsigned main_thread_pid;) /* 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 */ @@ -1491,13 +1593,6 @@ enum { PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, PSSCAN_RUIDGID = (1 << 21) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, PSSCAN_TASKS = (1 << 22) * ENABLE_FEATURE_SHOW_THREADS, - /* 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 | PSSCAN_NICE - /**/ | PSSCAN_CPU }; //procps_status_t* alloc_procps_scan(void) FAST_FUNC; void free_procps_scan(procps_status_t* sp) FAST_FUNC; @@ -1511,6 +1606,15 @@ int starts_with_cpu(const char *str) FAST_FUNC; unsigned get_cpu_count(void) FAST_FUNC; +/* Use strict=1 if you process input from untrusted source: + * it will return NULL on invalid %xx (bad hex chars) + * and str + 1 if decoded char is / or NUL. + * In non-strict mode, it always succeeds (returns str), + * and also it additionally decoded '+' to space. + */ +char *percent_decode_in_place(char *str, int strict) FAST_FUNC; + + 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) FAST_FUNC; @@ -1519,7 +1623,8 @@ enum { /* Sign-extends to a value which never matches fgetc result: */ BASE64_FLAG_NO_STOP_CHAR = 0x80, }; -void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags); +const char *decode_base64(char **pp_dst, const char *src) FAST_FUNC; +void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; typedef struct md5_ctx_t { uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ @@ -1561,16 +1666,24 @@ int print_flags_separated(const int *masks, const char *labels, int print_flags(const masks_labels_t *ml, int flags) FAST_FUNC; typedef struct bb_progress_t { - off_t lastsize; - unsigned lastupdate_sec; + unsigned last_size; + unsigned last_update_sec; + unsigned last_change_sec; unsigned start_sec; - smallint inited; + const char *curfile; } bb_progress_t; -void bb_progress_init(bb_progress_t *p) FAST_FUNC; -void bb_progress_update(bb_progress_t *p, const char *curfile, - off_t beg_range, off_t transferred, - off_t totalsize) FAST_FUNC; +#define is_bb_progress_inited(p) ((p)->curfile != NULL) +#define bb_progress_free(p) do { \ + if (ENABLE_UNICODE_SUPPORT) free((char*)((p)->curfile)); \ + (p)->curfile = NULL; \ +} while (0) +void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC; +void bb_progress_update(bb_progress_t *p, + uoff_t beg_range, + uoff_t transferred, + uoff_t totalsize) FAST_FUNC; + extern const char *applet_name; @@ -1607,10 +1720,10 @@ extern const char bb_path_wtmp_file[]; * get the list of currently mounted filesystems */ #define bb_path_mtab_file IF_FEATURE_MTAB_SUPPORT("/etc/mtab")IF_NOT_FEATURE_MTAB_SUPPORT("/proc/mounts") -#define bb_path_passwd_file "/etc/passwd" -#define bb_path_shadow_file "/etc/shadow" -#define bb_path_gshadow_file "/etc/gshadow" -#define bb_path_group_file "/etc/group" +#define bb_path_passwd_file _PATH_PASSWD +#define bb_path_group_file _PATH_GROUP +#define bb_path_shadow_file _PATH_SHADOW +#define bb_path_gshadow_file _PATH_GSHADOW #define bb_path_motd_file "/etc/motd" diff --git a/release/src/router/busybox/include/platform.h b/release/src/router/busybox/include/platform.h index 2666eebeea..d79cc97e5a 100644 --- a/release/src/router/busybox/include/platform.h +++ b/release/src/router/busybox/include/platform.h @@ -7,18 +7,6 @@ #ifndef BB_PLATFORM_H #define BB_PLATFORM_H 1 -/* Assume all these functions exist by default. Platforms where it is not - * true will #undef them below. - */ -#define HAVE_FDPRINTF 1 -#define HAVE_MEMRCHR 1 -#define HAVE_MKDTEMP 1 -#define HAVE_SETBIT 1 -#define HAVE_STRCASESTR 1 -#define HAVE_STRCHRNUL 1 -#define HAVE_STRSEP 1 -#define HAVE_STRSIGNAL 1 -#define HAVE_VASPRINTF 1 /* Convenience macros to test the version of gcc. */ #undef __GNUC_PREREQ @@ -36,10 +24,6 @@ # 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) @@ -93,7 +77,7 @@ #endif /* -fwhole-program makes all symbols local. The attribute externally_visible - forces a symbol global. */ + * forces a symbol global. */ #if __GNUC_PREREQ(4,1) # define EXTERNALLY_VISIBLE __attribute__(( visibility("default") )) //__attribute__ ((__externally_visible__)) @@ -109,22 +93,14 @@ #endif /* We use __extension__ in some places to suppress -pedantic warnings - about GCC extensions. This feature didn't work properly before - gcc 2.8. */ + * 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 -# if !defined va_copy && defined __va_copy -# define va_copy(d,s) __va_copy((d),(s)) -# endif -#endif - /* FAST_FUNC is a qualifier which (possibly) makes function call faster * and/or smaller by using modified ABI. It is usually only needed * on non-static, busybox internal functions. Recent versions of gcc @@ -140,7 +116,7 @@ /* Make all declarations hidden (-fvisibility flag only affects definitions) */ /* (don't include system headers after this until corresponding pop!) */ -#if __GNUC_PREREQ(4,1) +#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) # define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") # define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") #else @@ -148,6 +124,15 @@ # define POP_SAVED_FUNCTION_VISIBILITY #endif +/* gcc-2.95 had no va_copy but only __va_copy. */ +#if !__GNUC_PREREQ(3,0) +# include +# if !defined va_copy && defined __va_copy +# define va_copy(d,s) __va_copy((d),(s)) +# endif +#endif + + /* ---- Endian Detection ------------------------------------ */ #include @@ -215,16 +200,18 @@ # define IF_LITTLE_ENDIAN(...) __VA_ARGS__ #endif + /* ---- Unaligned access ------------------------------------ */ +#include +typedef int bb__aliased_int FIX_ALIASING; +typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; +typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; + /* NB: unaligned parameter should be a pointer, aligned one - * a lvalue. This makes it more likely to not swap them by mistake */ #if defined(i386) || defined(__x86_64__) || defined(__powerpc__) -# include -typedef int bb__aliased_int FIX_ALIASING; -typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; -typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; # define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp)) # define move_from_unaligned16(v, u16p) ((v) = *(bb__aliased_uint16_t*)(u16p)) # define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p)) @@ -246,30 +233,9 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; } while (0) #endif -/* ---- Compiler dependent settings ------------------------- */ -#if (defined __digital__ && defined __unix__) \ - || defined __APPLE__ \ - || defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ -# undef HAVE_MNTENT_H -# undef HAVE_SYS_STATFS_H -#else -# define HAVE_MNTENT_H 1 -# define HAVE_SYS_STATFS_H 1 -#endif - -/*----- Kernel versioning ------------------------------------*/ +/* ---- Size-saving "small" ints (arch-dependent) ----------- */ -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -/* ---- Miscellaneous --------------------------------------- */ - -#if defined __GLIBC__ || defined __UCLIBC__ \ - || defined __dietlibc__ || defined _NEWLIB_VERSION -# include -#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; @@ -289,7 +255,35 @@ typedef unsigned smalluint; # include #endif -/* Try to defeat gcc's alignment of "char message[]"-like data */ + +/*----- Kernel versioning ------------------------------------*/ + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + + +/* ---- Miscellaneous --------------------------------------- */ + +#if defined __GLIBC__ \ + || defined __UCLIBC__ \ + || defined __dietlibc__ \ + || defined __BIONIC__ \ + || defined _NEWLIB_VERSION +# include +#endif + +/* Define bb_setpgrp */ +#if defined(__digital__) && defined(__unix__) +/* 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) +#else +# define bb_setpgrp() setpgrp() +#endif + +/* fdprintf is more readable, we used it before dprintf was standardized */ +#include +#define fdprintf dprintf + +/* Useful for defeating 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))) @@ -301,8 +295,7 @@ typedef unsigned smalluint; # define ALIGN4 #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. @@ -319,18 +312,10 @@ typedef unsigned smalluint; # define USE_FOR_MMU(...) __VA_ARGS__ #endif -/* Don't use lchown with glibc older than 2.1.x */ -#if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 1 -# define lchown chown -#endif - #if defined(__digital__) && defined(__unix__) - # include # include # 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 @@ -343,15 +328,48 @@ typedef unsigned smalluint; # if !defined ADJ_TICK && defined MOD_CLKB # define ADJ_TICK MOD_CLKB # endif +#endif -#else +#if defined(__CYGWIN__) +# define MAXSYMLINKS SYMLOOP_MAX +#endif -# define bb_setpgrp() setpgrp() -#endif +/* ---- Who misses what? ------------------------------------ */ -#if defined(__GLIBC__) -# define fdprintf dprintf +/* Assume all these functions and header files exist by default. + * Platforms where it is not true will #undef them below. + */ +#define HAVE_CLEARENV 1 +#define HAVE_FDATASYNC 1 +#define HAVE_DPRINTF 1 +#define HAVE_MEMRCHR 1 +#define HAVE_MKDTEMP 1 +#define HAVE_PTSNAME_R 1 +#define HAVE_SETBIT 1 +#define HAVE_SIGHANDLER_T 1 +#define HAVE_STPCPY 1 +#define HAVE_STRCASESTR 1 +#define HAVE_STRCHRNUL 1 +#define HAVE_STRSEP 1 +#define HAVE_STRSIGNAL 1 +#define HAVE_STRVERSCMP 1 +#define HAVE_VASPRINTF 1 +#define HAVE_UNLOCKED_STDIO 1 +#define HAVE_UNLOCKED_LINE_OPS 1 +#define HAVE_GETLINE 1 +#define HAVE_XTABS 1 +#define HAVE_MNTENT_H 1 +#define HAVE_NET_ETHERNET_H 1 +#define HAVE_SYS_STATFS_H 1 + +#if defined(__UCLIBC_MAJOR__) +# if __UCLIBC_MAJOR__ == 0 \ + && ( __UCLIBC_MINOR__ < 9 \ + || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 32) \ + ) +# undef HAVE_STRVERSCMP +# endif #endif #if defined(__dietlibc__) @@ -359,28 +377,79 @@ typedef unsigned smalluint; #endif #if defined(__WATCOMC__) -# undef HAVE_FDPRINTF +# undef HAVE_DPRINTF +# undef HAVE_GETLINE # undef HAVE_MEMRCHR # undef HAVE_MKDTEMP # undef HAVE_SETBIT +# undef HAVE_STPCPY # undef HAVE_STRCASESTR # undef HAVE_STRCHRNUL # undef HAVE_STRSEP # undef HAVE_STRSIGNAL +# undef HAVE_STRVERSCMP # undef HAVE_VASPRINTF +# undef HAVE_UNLOCKED_STDIO +# undef HAVE_UNLOCKED_LINE_OPS +# undef HAVE_NET_ETHERNET_H +#endif + +#if defined(__CYGWIN__) +# undef HAVE_CLEARENV +# undef HAVE_FDPRINTF +# undef HAVE_MEMRCHR +# undef HAVE_PTSNAME_R +# undef HAVE_STRVERSCMP +# undef HAVE_UNLOCKED_LINE_OPS +#endif + +/* These BSD-derived OSes share many similarities */ +#if (defined __digital__ && defined __unix__) \ + || defined __APPLE__ \ + || defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ +# undef HAVE_CLEARENV +# undef HAVE_FDATASYNC +# undef HAVE_GETLINE +# undef HAVE_MNTENT_H +# undef HAVE_PTSNAME_R +# undef HAVE_SYS_STATFS_H +# undef HAVE_SIGHANDLER_T +# undef HAVE_STRVERSCMP +# undef HAVE_XTABS +# undef HAVE_DPRINTF +# undef HAVE_UNLOCKED_STDIO +# undef HAVE_UNLOCKED_LINE_OPS #endif #if defined(__FreeBSD__) # undef HAVE_STRCHRNUL #endif +#if defined(__NetBSD__) +# define HAVE_GETLINE 1 /* Recent NetBSD versions have getline() */ +#endif + +#if defined(__digital__) && defined(__unix__) +# undef HAVE_STPCPY +#endif + +#if defined(ANDROID) || defined(__ANDROID__) +# undef HAVE_DPRINTF +# undef HAVE_GETLINE +# undef HAVE_STPCPY +# undef HAVE_STRCHRNUL +# undef HAVE_STRVERSCMP +# undef HAVE_UNLOCKED_LINE_OPS +# undef HAVE_NET_ETHERNET_H +#endif + /* * Now, define prototypes for all the functions defined in platform.c * These must come after all the HAVE_* macros are defined (or not) */ -#ifndef HAVE_FDPRINTF -extern int fdprintf(int fd, const char *format, ...); +#ifndef HAVE_DPRINTF +extern int dprintf(int fd, const char *format, ...); #endif #ifndef HAVE_MEMRCHR @@ -396,6 +465,14 @@ extern char *mkdtemp(char *template) FAST_FUNC; # define clrbit(a, b) ((a)[(b) >> 3] &= ~(1 << ((b) & 7))) #endif +#ifndef HAVE_SIGHANDLER_T +typedef void (*sighandler_t)(int); +#endif + +#ifndef HAVE_STPCPY +extern char *stpcpy(char *p, const char *to_add) FAST_FUNC; +#endif + #ifndef HAVE_STRCASESTR extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; #endif @@ -417,4 +494,10 @@ extern char *strsep(char **stringp, const char *delim) FAST_FUNC; extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; #endif +#ifndef HAVE_GETLINE +# include /* for FILE */ +# include /* size_t */ +extern ssize_t getline(char **lineptr, size_t *n, FILE *stream) FAST_FUNC; +#endif + #endif diff --git a/release/src/router/busybox/include/pwd_.h b/release/src/router/busybox/include/pwd_.h index e40b71dab5..ea158da452 100644 --- a/release/src/router/busybox/include/pwd_.h +++ b/release/src/router/busybox/include/pwd_.h @@ -30,7 +30,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endpwent #define setpwent bb_internal_setpwent #define endpwent bb_internal_endpwent #define getpwent bb_internal_getpwent diff --git a/release/src/router/busybox/include/shadow_.h b/release/src/router/busybox/include/shadow_.h index de126ddecc..648a62ab32 100644 --- a/release/src/router/busybox/include/shadow_.h +++ b/release/src/router/busybox/include/shadow_.h @@ -37,11 +37,6 @@ struct spwd { unsigned long sp_flag; /* Reserved */ }; -/* Paths to the user database files */ -#ifndef _PATH_SHADOW -#define _PATH_SHADOW "/etc/shadow" -#endif - #define setspent bb_internal_setspent #define endspent bb_internal_endspent #define getspent bb_internal_getspent diff --git a/release/src/router/busybox/include/unicode.h b/release/src/router/busybox/include/unicode.h index dee02e7776..0317a21517 100644 --- a/release/src/router/busybox/include/unicode.h +++ b/release/src/router/busybox/include/unicode.h @@ -27,6 +27,7 @@ enum { # define unicode_strwidth(string) strlen(string) # define unicode_status UNICODE_OFF # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) #else @@ -67,6 +68,7 @@ char* FAST_FUNC unicode_conv_to_printable_fixedwidth(/*uni_stat_t *stats,*/ cons extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # else @@ -75,9 +77,11 @@ void init_unicode(void) FAST_FUNC; # if !ENABLE_FEATURE_CHECK_UNICODE_IN_ENV # define unicode_status UNICODE_ON # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) # else extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # endif # undef MB_CUR_MAX diff --git a/release/src/router/busybox/include/usage.src.h b/release/src/router/busybox/include/usage.src.h dissimilarity index 99% index 30fef2440f..78beccf4d7 100644 --- a/release/src/router/busybox/include/usage.src.h +++ b/release/src/router/busybox/include/usage.src.h @@ -1,4461 +1,22 @@ -/* 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 1 - - -#define NOUSAGE_STR "\b" - -INSERT - -#define acpid_trivial_usage \ - "[-d] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]" -#define acpid_full_usage "\n\n" \ - "Listen to ACPI events and spawn specific helpers on event arrival\n" \ - "\nOptions:" \ - "\n -c DIR Config directory [/etc/acpi]" \ - "\n -d Don't daemonize, (implies -f)" \ - "\n -e FILE /proc event file [/proc/acpi/event]" \ - "\n -f Run in foreground" \ - "\n -l FILE Log file [/var/log/acpid.log]" \ - "\n -p FILE Pid file [/var/run/acpid.pid]" \ - "\n -a FILE Action file [/etc/acpid.conf]" \ - "\n -M FILE Map file [/etc/acpi.map]" \ - IF_FEATURE_ACPID_COMPAT( \ - "\n\nAccept and ignore compatibility options -g -m -s -S -v" \ - ) - -#define acpid_example_usage \ - "Without -e option, acpid uses all /dev/input/event* files\n" \ - "# acpid\n" \ - "# acpid -l /var/log/my-acpi-log\n" \ - "# acpid -e /proc/acpi/event\n" - -#define addgroup_trivial_usage \ - "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP" -#define addgroup_full_usage "\n\n" \ - "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \ - "\nOptions:" \ - "\n -g GID Group id" \ - "\n -S Create a system group" \ - -#define adduser_trivial_usage \ - "[OPTIONS] USER" -#define adduser_full_usage "\n\n" \ - "Add a user\n" \ - "\nOptions:" \ - "\n -h DIR Home directory" \ - "\n -g GECOS GECOS field" \ - "\n -s SHELL Login shell" \ - "\n -G GRP Add user to existing group" \ - "\n -S Create a system user" \ - "\n -D Don't assign a password" \ - "\n -H Don't create home directory" \ - "\n -u UID User id" \ - -#define adjtimex_trivial_usage \ - "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-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 OFF Time offset, microseconds" \ - "\n -f FREQ 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 TCONST" \ - -#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 HWTYPE] [-i IF] -a [HOSTNAME]" \ - "\n[-v] [-i IF] -d HOSTNAME [pub]" \ - "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]" \ - "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub" \ - "\n[-v] [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub" -#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 from given device" \ - "\n -A,-p AF Protocol family" \ - "\n -H HWTYPE Hardware address type" \ - -#define arping_trivial_usage \ - "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP" -#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, seconds" \ - "\n -I IFACE Interface to use (default eth0)" \ - "\n -s SRC_IP Sender IP address" \ - "\n DST_IP Target IP address" \ - -#define awk_trivial_usage \ - "[OPTIONS] [AWK_PROGRAM] [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 .SUFFIX from FILE\n" -#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 beep_trivial_usage \ - "-f FREQ -l LEN -d DELAY -r COUNT -n" -#define beep_full_usage "\n\n" \ - "Options:" \ - "\n -f Frequency in Hz" \ - "\n -l Length in ms" \ - "\n -d Delay in ms" \ - "\n -r Repetitions" \ - "\n -n Start new tone" \ - -#define blkid_trivial_usage \ - "" -#define blkid_full_usage "\n\n" \ - "Print UUIDs of all filesystems" - -#define brctl_trivial_usage \ - "COMMAND [BRIDGE [INTERFACE]]" -#define brctl_full_usage "\n\n" \ - "Manage ethernet bridges\n" \ - "\nCommands:" \ - IF_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" \ - IF_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/yes/on|0/no/off] STP on/off" \ - ) \ - -#define bzip2_trivial_usage \ - "[OPTIONS] [FILE]..." -#define bzip2_full_usage "\n\n" \ - "Compress FILEs (or stdin) with bzip2 algorithm\n" \ - "\nOptions:" \ - "\n -1..9 Compression level" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define busybox_notes_usage \ - "Hello world!\n" - -#define lzop_trivial_usage \ - "[-cfvd123456789CF] [FILE]..." -#define lzop_full_usage "\n\n" \ - "Options:" \ - "\n -1..9 Compression level" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - "\n -v Verbose" \ - "\n -F Don't store or verify checksum" \ - "\n -C Also write checksum of compressed block" \ - -#define lzopcat_trivial_usage \ - "[-vCF] [FILE]..." -#define lzopcat_full_usage "\n\n" \ - " -v Verbose" \ - "\n -F Don't store or verify checksum" \ - -#define unlzop_trivial_usage \ - "[-cfvCF] [FILE]..." -#define unlzop_full_usage "\n\n" \ - "Options:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - "\n -v Verbose" \ - "\n -F Don't store or verify checksum" \ - -#define unlzma_trivial_usage \ - "[-cf] [FILE]..." -#define unlzma_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define lzma_trivial_usage \ - "-d [-cf] [FILE]..." -#define lzma_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define lzcat_trivial_usage \ - "FILE" -#define lzcat_full_usage "\n\n" \ - "Decompress to stdout" - -#define unxz_trivial_usage \ - "[-cf] [FILE]..." -#define unxz_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define xz_trivial_usage \ - "-d [-cf] [FILE]..." -#define xz_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define xzcat_trivial_usage \ - "FILE" -#define xzcat_full_usage "\n\n" \ - "Decompress 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 \ - "[FILE]..." -#define cat_full_usage "\n\n" \ - "Concatenate FILEs and print them to stdout" \ - -#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] [FILE]..." -#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 Don't 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 Recurse" \ - "\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..." \ - IF_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" \ - IF_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" \ - ) \ - IF_NOT_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" \ - ) - -#define chmod_trivial_usage \ - "[-R"IF_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" \ - IF_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"IF_DESKTOP("cvf")"]... GROUP FILE..." -#define chgrp_full_usage "\n\n" \ - "Change the group membership of each FILE to GROUP\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\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 Don't traverse symlinks (default)" \ - IF_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"IF_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" \ - "\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 Don't traverse symlinks (default)" \ - IF_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[:GRP]] [-U USER[:GRP]] [-e DIR]\n" \ - " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" \ - " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" -#define chpst_full_usage "\n\n" \ - "Change the process state, run PROG\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 NICE Add NICE to nice value" \ - "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES" \ - "\n -d BYTES Limit data segment" \ - "\n -o N Limit number of open files per process" \ - "\n -p N Limit number of processes per uid" \ - "\n -f BYTES Limit output file sizes" \ - "\n -c BYTES Limit core file size" \ - "\n -v Verbose" \ - "\n -P Create new process group" \ - "\n -0 Close stdin" \ - "\n -1 Close stdout" \ - "\n -2 Close stderr" \ - -#define setuidgid_trivial_usage \ - "USER PROG ARGS" -#define setuidgid_full_usage "\n\n" \ - "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" \ - "run PROG" -#define envuidgid_trivial_usage \ - "USER PROG ARGS" -#define envuidgid_full_usage "\n\n" \ - "Set $UID to USER's uid and $GID to USER's gid, 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, run PROG" -#define softlimit_trivial_usage \ - "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" \ - " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" \ - " PROG ARGS" -#define softlimit_full_usage "\n\n" \ - "Set soft resource limits, then run PROG\n" \ - "\nOptions:" \ - "\n -a BYTES Limit total size of all segments" \ - "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES -a BYTES" \ - "\n -d BYTES Limit data segment" \ - "\n -s BYTES Limit stack segment" \ - "\n -l BYTES Limit locked memory size" \ - "\n -o N Limit number of open files per process" \ - "\n -p N Limit number of processes per uid" \ - "\nOptions controlling file sizes:" \ - "\n -f BYTES Limit output file sizes" \ - "\n -c BYTES Limit core file size" \ - "\nEfficiency opts:" \ - "\n -r BYTES Limit resident set size" \ - "\n -t N Limit CPU time, process receives" \ - "\n a SIGXCPU after N seconds" \ - -#define chroot_trivial_usage \ - "NEWROOT [PROG ARGS]" -#define chroot_full_usage "\n\n" \ - "Run PROG 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" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" -#define cmp_full_usage "\n\n" \ - "Compare FILE1 with FILE2 (or stdin)\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 with FILE2\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 used by busybox build" - -#define chrt_trivial_usage \ - "[-prfom] [PRIO] [PID | PROG ARGS]" -#define chrt_full_usage "\n\n" \ - "Change scheduling priority and class for a process\n" \ - "\nOptions:" \ - "\n -p Operate on PID" \ - "\n -r Set SCHED_RR class" \ - "\n -f Set SCHED_FIFO class" \ - "\n -o Set SCHED_OTHER class" \ - "\n -m Show min/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 nice_trivial_usage \ - "[-n ADJUST] [PROG ARGS]" -#define nice_full_usage "\n\n" \ - "Change scheduling priority, run PROG\n" \ - "\nOptions:" \ - "\n -n ADJUST Adjust priority by ADJUST" \ - -#define renice_trivial_usage \ - "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" -#define renice_full_usage "\n\n" \ - "Change scheduling priority for a running process\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 ionice_trivial_usage \ - "[-c 1-3] [-n 0-7] [-p PID] [PROG]" -#define ionice_full_usage "\n\n" \ - "Change I/O priority and class\n" \ - "\nOptions:" \ - "\n -c Class. 1:realtime 2:best-effort 3:idle" \ - "\n -n Priority" \ - -#define cp_trivial_usage \ - "[OPTIONS] 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" \ - IF_SELINUX( \ - "\n -c Preserve security context" \ - ) \ - "\n -R,-r Recurse" \ - "\n -d,-P Preserve symlinks (default if -R)" \ - "\n -L Follow all symlinks" \ - "\n -H Follow symlinks on command line" \ - "\n -p Preserve file attributes if possible" \ - "\n -f Overwrite" \ - "\n -i Prompt before overwrite" \ - "\n -l,-s Create (sym)links" \ - -#define cpio_trivial_usage \ - "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") \ - " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") -#define cpio_full_usage "\n\n" \ - "Extract or list files from a cpio archive" \ - IF_FEATURE_CPIO_O(", or" \ - "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") \ - " using file list on stdin" \ - ) \ - "\n" \ - "\nMain operation mode:" \ - "\n -t List" \ - "\n -i Extract" \ - IF_FEATURE_CPIO_O( \ - "\n -o Create (requires -H newc)" \ - ) \ - IF_FEATURE_CPIO_P( \ - "\n -p DIR Copy files to DIR" \ - ) \ - "\nOptions:" \ - "\n -d Make leading directories" \ - "\n -m Preserve mtime" \ - "\n -v Verbose" \ - "\n -u Overwrite" \ - "\n -F FILE Input (-t,-i,-p) or output (-o) file" \ - IF_FEATURE_CPIO_O( \ - "\n -H newc Archive format" \ - ) \ - -#define crond_trivial_usage \ - "-fbS -l N " IF_FEATURE_CROND_D("-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" \ - IF_FEATURE_CROND_D( \ - "\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 \ - "[OPTIONS] [PASSWORD] [SALT]" -/* We do support -s, we just don't mention it */ -#define cryptpw_full_usage "\n\n" \ - "Crypt the PASSWORD using crypt(3)\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -P,--password-fd=N Read password from fd N" \ -/* "\n -s,--stdin Use stdin; like -P0" */ \ - "\n -m,--method=TYPE Encryption method TYPE" \ - "\n -S,--salt=SALT" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -P N Read password from fd N" \ -/* "\n -s Use stdin; like -P0" */ \ - "\n -m TYPE Encryption method TYPE" \ - "\n -S SALT" \ - ) \ - -/* mkpasswd is an alias to cryptpw */ - -#define mkpasswd_trivial_usage \ - "[OPTIONS] [PASSWORD] [SALT]" -/* We do support -s, we just don't mention it */ -#define mkpasswd_full_usage "\n\n" \ - "Crypt the PASSWORD using crypt(3)\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -P,--password-fd=N Read password from fd N" \ -/* "\n -s,--stdin Use stdin; like -P0" */ \ - "\n -m,--method=TYPE Encryption method TYPE" \ - "\n -S,--salt=SALT" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -P N Read password from fd N" \ -/* "\n -s Use stdin; like -P0" */ \ - "\n -m TYPE Encryption method TYPE" \ - "\n -S SALT" \ - ) \ - -#define cut_trivial_usage \ - "[OPTIONS] [FILE]..." -#define cut_full_usage "\n\n" \ - "Print selected fields from each input FILE to stdout\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 dd_trivial_usage \ - "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \ - " [seek=N]" IF_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" \ - IF_FEATURE_DD_IBS_OBS( \ - "\n ibs=N Read N bytes at a time" \ - ) \ - IF_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" \ - IF_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 \ - IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" -#define delgroup_full_usage "\n\n" \ - "Delete group GROUP from the system" \ - IF_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 devmem_trivial_usage \ - "ADDRESS [WIDTH [VALUE]]" - -#define devmem_full_usage "\n\n" \ - "Read/write from physical address\n" \ - "\n ADDRESS Address to act upon" \ - "\n WIDTH Width (8/16/...)" \ - "\n VALUE Data to be written" \ - -#define devfsd_trivial_usage \ - "mntpnt [-v]" IF_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" \ - IF_DEVFSD_FG_NP( \ - "\n -fg Run in foreground" \ - "\n -np Exit after parsing the configuration file" \ - "\n and processing synthetic REGISTER events," \ - "\n don't poll for events" \ - ) - -#define df_trivial_usage \ - "[-Pk" \ - IF_FEATURE_HUMAN_READABLE("mh") \ - IF_FEATURE_DF_FANCY("ai] [-B SIZE") \ - "] [FILESYSTEM]..." -#define df_full_usage "\n\n" \ - "Print filesystem usage statistics\n" \ - "\nOptions:" \ - "\n -P POSIX output format" \ - "\n -k 1024-byte blocks (default)" \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -m 1M-byte blocks" \ - "\n -h Human readable (e.g. 1K 243M 2G)" \ - ) \ - IF_FEATURE_DF_FANCY( \ - "\n -a Show all filesystems" \ - "\n -i Inodes" \ - "\n -B SIZE Blocksize" \ - ) \ - -#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" \ - "$ POSIXLY_CORRECT=sure df /dev/sda3\n" \ - "Filesystem 512B-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 17381728 17107080 274648 98% /\n" \ - "$ POSIXLY_CORRECT=yep df -P /dev/sda3\n" \ - "Filesystem 512-blocks Used Available Capacity Mounted on\n" \ - "/dev/sda3 17381728 17107080 274648 98% /\n" - -#define dhcprelay_trivial_usage \ - "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" -#define dhcprelay_full_usage "\n\n" \ - "Relay DHCP requests between clients and server" \ - -#define diff_trivial_usage \ - "[-abBdiNqrTstw] [-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 -B Ignore changes whose lines are all blank" \ - "\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 Recurse" \ - "\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 \ - "[-dvs] [-c CONFFILE] [-t TTL_SEC] [-p PORT] [-i ADDR]" -#define dnsd_full_usage "\n\n" \ - "Small static DNS server daemon\n" \ - "\nOptions:" \ - "\n -c FILE Config file" \ - "\n -t SEC TTL" \ - "\n -p PORT Listen on PORT" \ - "\n -i ADDR Listen on ADDR" \ - "\n -d Daemonize" \ - "\n -v Verbose" \ - "\n -s Send successful replies only. Use this if you want" \ - "\n to use /etc/resolv.conf with two nameserver lines:" \ - "\n nameserver DNSD_SERVER" \ - "\n nameserver NORNAL_DNS_SERVER" \ - -#define dos2unix_trivial_usage \ - "[-ud] [FILE]" -#define dos2unix_full_usage "\n\n" \ - "Convert FILE in-place from DOS to Unix format.\n" \ - "When no file is given, use stdin/stdout.\n" \ - "\nOptions:" \ - "\n -u dos2unix" \ - "\n -d unix2dos" \ - -#define unix2dos_trivial_usage \ - "[-ud] [FILE]" -#define unix2dos_full_usage "\n\n" \ - "Convert FILE in-place from Unix to DOS format.\n" \ - "When no file is given, use stdin/stdout.\n" \ - "\nOptions:" \ - "\n -u dos2unix" \ - "\n -d unix2dos" \ - -#define dpkg_trivial_usage \ - "[-ilCPru] [-F OPT] PACKAGE" -#define dpkg_full_usage "\n\n" \ - "Install, remove and manage Debian packages\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -i,--install Install the package" \ - "\n -l,--list List of installed packages" \ - "\n --configure Configure an unpackaged package" \ - "\n -P,--purge Purge all files of a package" \ - "\n -r,--remove Remove all but the configuration files for a package" \ - "\n --unpack Unpack a package, but don't configure it" \ - "\n --force-depends Ignore dependency problems" \ - "\n --force-confnew Overwrite existing config files when installing" \ - "\n --force-confold Keep old config files when installing" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -i Install the package" \ - "\n -l List of installed packages" \ - "\n -C Configure an unpackaged package" \ - "\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" \ - "\n -F depends Ignore dependency problems" \ - "\n -F confnew Overwrite existing config files when installing" \ - "\n -F confold Keep old config files when installing" \ - ) - -#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" IF_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 " \ - IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") \ - IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") \ - " bytes.\n" \ - "\nOptions:" \ - "\n -a Show file sizes too" \ - "\n -L Follow all symlinks" \ - "\n -H Follow symlinks on command line" \ - "\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" \ - IF_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" \ - IF_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 stdout" -#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:" \ - IF_LONG_OPTS( \ - "\n -f,--file=FILE Lease file" \ - "\n -r,--remaining Show remaining time" \ - "\n -a,--absolute Show expiration time" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -f FILE Lease file" \ - "\n -r Show remaining time" \ - "\n -a Show expiration 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 \ - IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." -#define echo_full_usage "\n\n" \ - "Print the specified ARGs to stdout" \ - IF_FEATURE_FANCY_ECHO( "\n" \ - "\nOptions:" \ - "\n -n Suppress trailing newline" \ - "\n -e Interpret backslash escapes (i.e., \\t=tab)" \ - "\n -E Don't interpret backslash escapes (default)" \ - ) -#define echo_example_usage \ - "$ echo \"Erik is cool\"\n" \ - "Erik is cool\n" \ - IF_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 DEVICE or default /dev/cdrom\n" \ - "\nOptions:" \ - IF_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]... [PROG ARGS]" -#define env_full_usage "\n\n" \ - "Print the current environment or run PROG after setting up\n" \ - "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 N] [FILE]..." -#define expand_full_usage "\n\n" \ - "Convert tabs to spaces, writing to stdout\n" \ - "\nOptions:" \ - IF_FEATURE_EXPAND_LONG_OPTIONS( \ - "\n -i,--initial Don't convert tabs after non blanks" \ - "\n -t,--tabs=N Tabstops every N chars" \ - ) \ - IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( \ - "\n -i Don't 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 stdout\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: 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 fbsplash_trivial_usage \ - "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" -#define fbsplash_full_usage "\n\n" \ - "Options:" \ - "\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 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 IF_FEATURE_FDISK_BLKSIZE(a) -#endif - -#define fdisk_trivial_usage \ - "[-ul" IF_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" \ - IF_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 -S SECTORS" \ - -#define fgconsole_trivial_usage \ - "" -#define fgconsole_full_usage "\n\n" \ - "Get active console" - -#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 flash_lock_trivial_usage \ - "MTD_DEVICE OFFSET SECTORS" -#define flash_lock_full_usage "\n\n" \ - "Lock part or all of an MTD device. If SECTORS is -1, then all sectors\n" \ - "will be locked, regardless of the value of OFFSET" - -#define flash_unlock_trivial_usage \ - "MTD_DEVICE" -#define flash_unlock_full_usage "\n\n" \ - "Unlock an MTD device" - -#define flash_eraseall_trivial_usage \ - "[-jq] MTD_DEVICE" -#define flash_eraseall_full_usage "\n\n" \ - "Erase an MTD device\n" \ - "\nOptions:" \ - "\n -j Format the device for jffs2" \ - "\n -q Don't display progress messages" \ - -#define flashcp_trivial_usage \ - "-v FILE MTD_DEVICE" -#define flashcp_full_usage "\n\n" \ - "Copy an image to MTD device\n" \ - "\nOptions:" \ - "\n -v Verbose" \ - -#define flock_trivial_usage \ - "[-sxun] FD|{FILE [-c] PROG ARGS}" -#define flock_full_usage "\n\n" \ - "[Un]lock file descriptor, or lock FILE, run PROG\n" \ - "\nOptions:" \ - "\n -s Shared lock" \ - "\n -x Exclusive lock (default)" \ - "\n -u Unlock FD" \ - "\n -n Fail rather than wait" \ - -#define fold_trivial_usage \ - "[-bs] [-w WIDTH] [FILE]..." -#define fold_full_usage "\n\n" \ - "Wrap input lines in each FILE (or stdin), writing to stdout\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 \ - "" IF_DESKTOP("[-b/k/m/g]") -#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_OPTS] [BLOCKDEV]..." -#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] BLOCKDEV" -#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 superblock information" \ - "\n -m Show \"mode not cleared\" warnings" \ - "\n -f Force file system check" \ - -#define ftpd_trivial_usage \ - "[-wvS] [-t N] [-T N] [DIR]" -#define ftpd_full_usage "\n\n" \ - "Anonymous FTP server\n" \ - "\n" \ - "ftpd should be used as an inetd service.\n" \ - "ftpd's line for inetd.conf:\n" \ - " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" \ - "It also can be ran from tcpsvd:\n" \ - " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve\n" \ - "\nOptions:" \ - "\n -w Allow upload" \ - "\n -v Log to stderr" \ - "\n -S Log to syslog" \ - "\n -t,-T Idle and absolute timeouts" \ - "\n DIR Change root to this directory" \ - -#define ftpget_trivial_usage \ - "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" -#define ftpget_full_usage "\n\n" \ - "Retrieve a remote file via FTP\n" \ - "\nOptions:" \ - IF_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -c,--continue Continue previous transfer" \ - "\n -v,--verbose Verbose" \ - "\n -u,--username Username" \ - "\n -p,--password Password" \ - "\n -P,--port Port number" \ - ) \ - IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -c Continue previous transfer" \ - "\n -v Verbose" \ - "\n -u Username" \ - "\n -p Password" \ - "\n -P Port number" \ - ) - -#define ftpput_trivial_usage \ - "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" -#define ftpput_full_usage "\n\n" \ - "Store a local file on a remote machine via FTP\n" \ - "\nOptions:" \ - IF_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -v,--verbose Verbose" \ - "\n -u,--username Username" \ - "\n -p,--password Password" \ - "\n -P,--port Port number" \ - ) \ - IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\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,-6 Search only IPv4/IPv6 space" \ - "\n -s Don't display PIDs" \ - "\n -k Kill found processes" \ - "\n -SIGNAL Signal to send (default: KILL)" \ - -#define getenforce_trivial_usage NOUSAGE_STR -#define getenforce_full_usage "" - -#define getopt_trivial_usage \ - "[OPTIONS]" -#define getopt_full_usage "\n\n" \ - "Options:" \ - IF_LONG_OPTS( \ - "\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" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\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 Don't display /etc/issue before running login" \ - "\n -L Local line, don't 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 Don't prompt the user for a login name" \ - "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \ - "\n -l LOGIN Invoke LOGIN instead of /bin/login" \ - "\n -t SEC Terminate after SEC if no username is read" \ - "\n -I INITSTR Send INITSTR before anything else" \ - "\n -H HOST Log HOST into the utmp file as the hostname" \ - -#define gunzip_trivial_usage \ - "[-cft] [FILE]..." -#define gunzip_full_usage "\n\n" \ - "Decompress FILEs (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\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 \ - "[-cfd] [FILE]..." -#define gzip_full_usage "\n\n" \ - "Compress FILEs (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\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 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" \ - IF_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" \ - IF_FEATURE_HDPARM_GET_IDENTITY( \ - "\n -i Display drive identification") \ - IF_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)" \ - IF_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)" \ - IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( \ - "\n -U Unregister an IDE interface (DANGEROUS)") \ - "\n -v Defaults; same as -mcudkrag for IDE drives" \ - "\n -V Display program version and exit immediately" \ - IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( \ - "\n -w Perform device reset (DANGEROUS)") \ - "\n -W Set drive write-caching flag (0/1) (DANGEROUS)" \ - IF_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 Reread partition table" \ - -#define head_trivial_usage \ - "[OPTIONS] [FILE]..." -#define head_full_usage "\n\n" \ - "Print first 10 lines of each FILE (or stdin) to stdout.\n" \ - "With more than one FILE, precede each with a filename header.\n" \ - "\nOptions:" \ - "\n -n N[kbm] Print first N lines" \ - IF_FEATURE_FANCY_HEAD( \ - "\n -c N[kbm] Print first N bytes" \ - "\n -q Never print headers" \ - "\n -v Always print headers" \ - ) \ - "\n" \ - "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." \ - -#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 tail_trivial_usage \ - "[OPTIONS] [FILE]..." -#define tail_full_usage "\n\n" \ - "Print last 10 lines of each FILE (or stdin) to stdout.\n" \ - "With more than one FILE, precede each with a filename header.\n" \ - "\nOptions:" \ - "\n -f Print data as file grows" \ - IF_FEATURE_FANCY_TAIL( \ - "\n -s SECONDS Wait SECONDS between reads with -f" \ - ) \ - "\n -n N[kbm] Print last N lines" \ - IF_FEATURE_FANCY_TAIL( \ - "\n -c N[kbm] Print last N bytes" \ - "\n -q Never print headers" \ - "\n -v Always print headers" \ - "\n" \ - "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." \ - "\nIf N starts with a '+', output begins with the Nth item from the start" \ - "\nof each file, not from the end." \ - ) \ - -#define tail_example_usage \ - "$ tail -n 1 /etc/resolv.conf\n" \ - "nameserver 10.0.0.1\n" - -#define hexdump_trivial_usage \ - "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..." -#define hexdump_full_usage "\n\n" \ - "Display FILEs (or stdin) 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" \ - IF_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 \ - "[OPTIONS] [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 FILE's content as hostname" \ - -#define hostname_example_usage \ - "$ hostname\n" \ - "sage\n" - -#define dnsdomainname_trivial_usage NOUSAGE_STR -#define dnsdomainname_full_usage "" - -#define httpd_trivial_usage \ - "[-ifv[v]]" \ - " [-c CONFFILE]" \ - " [-p [IP:]PORT]" \ - IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") \ - IF_FEATURE_HTTPD_BASIC_AUTH(" [-r REALM]") \ - " [-h HOME]\n" \ - "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" -#define httpd_full_usage "\n\n" \ - "Listen for incoming HTTP requests\n" \ - "\nOptions:" \ - "\n -i Inetd mode" \ - "\n -f Don't daemonize" \ - "\n -v[v] Verbose" \ - "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" \ - IF_FEATURE_HTTPD_SETUID( \ - "\n -u USER[:GRP] Set uid/gid after binding to port") \ - IF_FEATURE_HTTPD_BASIC_AUTH( \ - "\n -r REALM Authentication Realm for Basic Authentication") \ - "\n -h HOME Home directory (default .)" \ - "\n -c FILE Configuration file (default {/etc,HOME}/httpd.conf)" \ - IF_FEATURE_HTTPD_AUTH_MD5( \ - "\n -m STRING MD5 crypt STRING") \ - "\n -e STRING HTML encode STRING" \ - "\n -d STRING URL decode STRING" \ - -#define hwclock_trivial_usage \ - IF_FEATURE_HWCLOCK_LONG_OPTIONS( \ - "[-r|--show] [-s|--hctosys] [-w|--systohc]" \ - " [-l|--localtime] [-u|--utc]" \ - " [-f FILE]" \ - ) \ - IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS( \ - "[-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:" \ - IF_SELINUX( \ - "\n -Z Security context" \ - ) \ - "\n -u User ID" \ - "\n -g Group ID" \ - "\n -G Supplementary group IDs" \ - "\n -n Print names instead of numbers" \ - "\n -r Print real ID instead of effective ID" \ - -#define id_example_usage \ - "$ id\n" \ - "uid=1000(andersen) gid=1000(andersen)\n" - -#define ifconfig_trivial_usage \ - IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]" -#define ifconfig_full_usage "\n\n" \ - "Configure a network interface\n" \ - "\nOptions:" \ - "\n" \ - IF_FEATURE_IPV6( \ - " [add ADDRESS[/PREFIXLEN]]\n") \ - IF_FEATURE_IPV6( \ - " [del ADDRESS[/PREFIXLEN]]\n") \ - " [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" \ - " [netmask ADDRESS] [dstaddr ADDRESS]\n" \ - IF_FEATURE_IFCONFIG_SLIP( \ - " [outfill NN] [keepalive NN]\n") \ - " " IF_FEATURE_IFCONFIG_HW("[hw ether" IF_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu NN]\n" \ - " [[-]trailers] [[-]arp] [[-]allmulti]\n" \ - " [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic]\n" \ - IF_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 netmask broadcast \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 ifplugd_trivial_usage \ - "[OPTIONS]" -#define ifplugd_full_usage "\n\n" \ - "Network interface plug detection daemon\n" \ - "\nOptions:" \ - "\n -n Don't daemonize" \ - "\n -s Don't log to syslog" \ - "\n -i IFACE Interface" \ - "\n -f/-F Treat link detection error as link down/link up" \ - "\n (otherwise exit on error)" \ - "\n -a Don't up interface at each link probe" \ - "\n -M Monitor creation/destruction of interface" \ - "\n (otherwise it must exist)" \ - "\n -r PROG Script to run" \ - "\n -x ARG Extra argument for script" \ - "\n -I Don't exit on nonzero exit code from script" \ - "\n -p Don't run script on daemon startup" \ - "\n -q Don't run script on daemon quit" \ - "\n -l Run script on startup even if no cable is detected" \ - "\n -t SECS Poll time in seconds" \ - "\n -u SECS Delay before running script after link up" \ - "\n -d SECS Delay after link down" \ - "\n -m MODE API mode (mii, priv, ethtool, wlan, iff, auto)" \ - "\n -k Kill running daemon" \ - -#define ifup_trivial_usage \ - "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." -#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" \ - IF_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 \ - "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." -#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" \ - IF_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 inotifyd_trivial_usage \ - "PROG FILE1[:MASK]..." -#define inotifyd_full_usage "\n\n" \ - "Run PROG on filesystem changes." \ - "\nWhen a filesystem event matching MASK occurs on FILEn," \ - "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." \ - "\nEvents:" \ - "\n a File is accessed" \ - "\n c File is modified" \ - "\n e Metadata changed" \ - "\n w Writable file is closed" \ - "\n 0 Unwritable file is closed" \ - "\n r File is opened" \ - "\n D File is deleted" \ - "\n M File is moved" \ - "\n u Backing fs is unmounted" \ - "\n o Event queue overflowed" \ - "\n x File can't be watched anymore" \ - "\nIf watching a directory:" \ - "\n m Subfile is moved into dir" \ - "\n y Subfile is moved out of dir" \ - "\n n Subfile is created" \ - "\n d Subfile is deleted" \ - "\n" \ - "\ninotifyd waits for PROG to exit." \ - "\nWhen x event happens for all FILEs, inotifyd exits." \ - -/* -v, -b, -c are ignored */ -#define install_trivial_usage \ - "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [SOURCE]... DEST" -#define install_full_usage "\n\n" \ - "Copy files and set attributes\n" \ - "\nOptions:" \ - "\n -c Just copy (default)" \ - "\n -d Create directories" \ - "\n -D Create leading target directories" \ - "\n -s Strip symbol table" \ - "\n -p Preserve date" \ - "\n -o USER Set ownership" \ - "\n -g GRP Set group ownership" \ - "\n -m MODE Set permissions" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -/* would need to make the " | " optional depending on more than one selected: */ -#define ip_trivial_usage \ - "[OPTIONS] {" \ - IF_FEATURE_IP_ADDRESS("address | ") \ - IF_FEATURE_IP_ROUTE("route | ") \ - IF_FEATURE_IP_LINK("link | ") \ - IF_FEATURE_IP_TUNNEL("tunnel | ") \ - IF_FEATURE_IP_RULE("rule") \ - "} {COMMAND}" -#define ip_full_usage "\n\n" \ - "ip [OPTIONS] OBJECT {COMMAND}\n" \ - "where OBJECT := {" \ - IF_FEATURE_IP_ADDRESS("address | ") \ - IF_FEATURE_IP_ROUTE("route | ") \ - IF_FEATURE_IP_LINK("link | ") \ - IF_FEATURE_IP_TUNNEL("tunnel | ") \ - IF_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 \ - "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" -#define ipcalc_full_usage "\n\n" \ - "Calculate IP network settings from a IP address\n" \ - "\nOptions:" \ - IF_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" \ - IF_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" \ - ) \ - ) \ - IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( \ - "\n -b Display calculated broadcast address" \ - "\n -n Display calculated network address" \ - "\n -m Display default netmask for IP" \ - IF_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]\n" \ - " [metric METRIC]" \ - -#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] [-C TTY]" -#define kbd_mode_full_usage "\n\n" \ - "Report or set the keyboard mode\n" \ - "\nOptions:" \ - "\n -a Default (ASCII)" \ - "\n -k Medium-raw (keyboard)" \ - "\n -s Raw (scancode)" \ - "\n -u Unicode (utf-8)" \ - "\n -C TTY Affect TTY instead of /dev/tty" \ - -#define kill_trivial_usage \ - "[-l] [-SIG] PID..." -#define kill_full_usage "\n\n" \ - "Send a signal (default: TERM) to given PIDs\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - -#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] [-SIG] PROCESS_NAME..." -#define killall_full_usage "\n\n" \ - "Send a signal (default: TERM) to given processes\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - "\n -q Don't complain if no processes were killed" \ - -#define killall_example_usage \ - "$ killall apache\n" - -#define killall5_trivial_usage \ - "[-l] [-SIG] [-o PID]..." -#define killall5_full_usage "\n\n" \ - "Send a signal (default: TERM) to all processes outside current session\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ - "\n -o PID Don't signal this PID" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - -#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~I?] [FILE]..." -#define less_full_usage "\n\n" \ - "View FILE (or stdin) one screenful at a time\n" \ - "\nOptions:" \ - "\n -E Quit once the end of a file is reached" \ - "\n -M,-m Display status line with line numbers" \ - "\n and percentage through the file" \ - "\n -N Prefix line number to each line" \ - "\n -I Ignore case in all searches" \ - "\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 setarch_trivial_usage \ - "personality PROG 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 \ - "[OPTIONS] TARGET... LINK|DIR" -#define ln_full_usage "\n\n" \ - "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" \ - "\nOptions:" \ - "\n -s Make symlinks instead of hardlinks" \ - "\n -f Remove existing destinations" \ - "\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 stdin" \ -/* "\n -C TTY Affect TTY instead of /dev/tty" */ \ - -#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 stdin\n" \ -/* "\n -C TTY Affect TTY instead of /dev/tty" */ \ - -#define loadkmap_example_usage \ - "$ loadkmap < /etc/i18n/lang-keymap\n" - -#define logger_trivial_usage \ - "[OPTIONS] [MESSAGE]" -#define logger_full_usage "\n\n" \ - "Write MESSAGE (or stdin) to syslog\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 Don't 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 \ - "[-f]" -#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" \ - "SPOOLDIR must contain (symlinks to) device nodes or directories" \ - "\nwith names matching print queue names. In the first case, jobs are" \ - "\nsent directly to the device. Otherwise each job is stored in queue" \ - "\ndirectory and HELPER program is called. Name of file to print" \ - "\nis passed in $DATAFILE variable." \ - "\nExample:" \ - "\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" IF_FEATURE_LS_TIMESTAMPS("c") "Cd" \ - IF_FEATURE_LS_TIMESTAMPS("e") IF_FEATURE_LS_FILETYPES("F") "iln" \ - IF_FEATURE_LS_FILETYPES("p") IF_FEATURE_LS_FOLLOWLINKS("L") \ - IF_FEATURE_LS_RECURSIVE("R") IF_FEATURE_LS_SORTFILES("rS") "s" \ - IF_FEATURE_AUTOWIDTH("T") IF_FEATURE_LS_TIMESTAMPS("tu") \ - IF_FEATURE_LS_SORTFILES("v") IF_FEATURE_AUTOWIDTH("w") "x" \ - IF_FEATURE_LS_SORTFILES("X") IF_FEATURE_HUMAN_READABLE("h") "k" \ - IF_SELINUX("K") "] [FILE]..." -#define ls_full_usage "\n\n" \ - "List directory contents\n" \ - "\nOptions:" \ - "\n -1 List in a single column" \ - "\n -A Don't list . and .." \ - "\n -a Don't hide entries starting with ." \ - "\n -C List by columns" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -c With -l: sort by ctime") \ - IF_FEATURE_LS_COLOR( \ - "\n --color[={always,never,auto}] Control coloring") \ - "\n -d List directory entries instead of contents" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -e List full date and time") \ - IF_FEATURE_LS_FILETYPES( \ - "\n -F Append indicator (one of */=@|) to entries") \ - "\n -i List inode numbers" \ - "\n -l Long listing format" \ - "\n -n List numeric UIDs and GIDs instead of names" \ - IF_FEATURE_LS_FILETYPES( \ - "\n -p Append indicator (one of /=@|) to entries") \ - IF_FEATURE_LS_FOLLOWLINKS( \ - "\n -L List entries pointed to by symlinks") \ - IF_FEATURE_LS_RECURSIVE( \ - "\n -R Recurse") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -r Sort in reverse order") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -S Sort by file size") \ - "\n -s List the size of each file, in blocks" \ - IF_FEATURE_AUTOWIDTH( \ - "\n -T N Assume tabstop every N columns") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -t With -l: sort by modification time") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -u With -l: sort by access time") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -v Sort by version") \ - IF_FEATURE_AUTOWIDTH( \ - "\n -w N Assume the terminal is N columns wide") \ - "\n -x List by lines" \ - IF_FEATURE_LS_SORTFILES( \ - "\n -X Sort by extension") \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -h List sizes in human readable format (1K 243M 2G)") \ - IF_SELINUX( \ - "\n -k List security context") \ - IF_SELINUX( \ - "\n -K List security context in long format") \ - IF_SELINUX( \ - "\n -Z List security context and permission") \ - -#define lsattr_trivial_usage \ - "[-Radlv] [FILE]..." -#define lsattr_full_usage "\n\n" \ - "List file attributes on an ext2 fs\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\n -a Don't hide entries starting with ." \ - "\n -d List directory entries instead of contents" \ - "\n -l List long flag names" \ - "\n -v List the file's version/generation number" \ - -#define lspci_trivial_usage \ - "[-mk]" -#define lspci_full_usage "\n\n" \ - "List all PCI devices" \ - "\n" \ - "\n -m Parseable output" \ - "\n -k Show driver" \ - -#define lsusb_trivial_usage NOUSAGE_STR -#define lsusb_full_usage "" - -#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" \ - "\nTYPE is:" \ - "\n b Block device" \ - "\n c Character device" \ - "\n f FIFO, MAJOR and MINOR are ignored" \ - "\n" \ - "\nFIRST..LAST specify numbers appended to NAME." \ - "\nIf 's' is the last argument, the base device is created as well." \ - "\n" \ - "\nExamples:" \ - "\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" \ - " \n" \ - "Where name is the file name, type can be one of:\n" \ - " f Regular file\n" \ - " d Directory\n" \ - " c Character device\n" \ - " b Block device\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" \ - " \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 makemime_trivial_usage \ - "[OPTIONS] [FILE]..." -#define makemime_full_usage "\n\n" \ - "Create multipart MIME-encoded message from FILEs\n" \ -/* "Transfer encoding is base64, disposition is inline (not attachment)\n" */ \ - "\nOptions:" \ - "\n -o FILE Output. Default: stdout" \ - "\n -a HDR Add header. Examples:" \ - "\n \"From: user@host.org\", \"Date: `date -R`\"" \ - "\n -c CT Content type. Default: text/plain" \ - "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET \ -/* "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ \ - "\n" \ - "\nOther options are silently ignored" \ - -#define man_trivial_usage \ - "[-aw] [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 Don't display path" \ - "\n -N Don't 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 \ - "[FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: md5sum -c [-sw] [FILE]") -#define md5sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted 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 sha1sum_trivial_usage \ - "[FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum -c [-sw] [FILE]") -#define sha1sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define sha256sum_trivial_usage \ - "[FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha256sum -c [-sw] [FILE]") -#define sha256sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define sha512sum_trivial_usage \ - "[FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha512sum -c [-sw] [FILE]") -#define sha512sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define mdev_trivial_usage \ - "[-s]" -#define mdev_full_usage "\n\n" \ - " -s Scan /sys and populate /dev during system boot\n" \ - "\n" \ - "It can be run by kernel as a hotplug helper. To activate it:\n" \ - " echo /sbin/mdev > /proc/sys/kernel/hotplug\n" \ - IF_FEATURE_MDEV_CONF( \ - "It uses /etc/mdev.conf with lines\n" \ - "[-]DEVNAME UID:GID PERM" \ - IF_FEATURE_MDEV_RENAME(" [>|=PATH]") \ - IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") \ - ) \ - -#define mdev_notes_usage "" \ - IF_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" \ - IF_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 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 \ - "[OPTIONS] DIRECTORY..." -#define mkdir_full_usage "\n\n" \ - "Create DIRECTORY\n" \ - "\nOptions:" \ - "\n -m MODE Mode" \ - "\n -p No error if exists; make parent directories as needed" \ - IF_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 mkfifo_trivial_usage \ - "[-m MODE] " IF_SELINUX("[-Z] ") "NAME" -#define mkfifo_full_usage "\n\n" \ - "Create named pipe\n" \ - "\nOptions:" \ - "\n -m MODE Mode (default a=rw)" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -#define mkfs_ext2_trivial_usage \ - "[-Fn] " \ - /* "[-c|-l filename] " */ \ - "[-b BLK_SIZE] " \ - /* "[-f fragment-size] [-g blocks-per-group] " */ \ - "[-i INODE_RATIO] [-I INODE_SIZE] " \ - /* "[-j] [-J journal-options] [-N number-of-inodes] " */ \ - "[-m RESERVED_PERCENT] " \ - /* "[-o creator-os] [-O feature[,...]] [-q] " */ \ - /* "[r fs-revision-level] [-E extended-options] [-v] [-F] " */ \ - "[-L LABEL] " \ - /* "[-M last-mounted-directory] [-S] [-T filesystem-type] " */ \ - "BLOCKDEV [KBYTES]" -#define mkfs_ext2_full_usage "\n\n" \ - " -b BLK_SIZE Block size, bytes" \ -/* "\n -c Check device for bad blocks" */ \ -/* "\n -E opts Set extended options" */ \ -/* "\n -f size Fragment size in bytes" */ \ - "\n -F Force" \ -/* "\n -g N Number of blocks in a block group" */ \ - "\n -i RATIO Max number of files is filesystem_size / RATIO" \ - "\n -I BYTES Inode size (min 128)" \ -/* "\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 Volume label" \ - "\n -m PERCENT Percent of blocks to reserve for admin" \ -/* "\n -M dir Set last mounted directory" */ \ - "\n -n Dry run" \ -/* "\n -N N 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 mkfs_minix_trivial_usage \ - "[-c | -l FILE] [-nXX] [-iXX] BLOCKDEV [KBYTES]" -#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 FILE Read bad blocks list from FILE" \ - "\n -v Make version 2 filesystem" \ - -#define mkfs_reiser_trivial_usage \ - "[-f] [-l LABEL] BLOCKDEV [4K-BLOCKS]" - -#define mkfs_reiser_full_usage "\n\n" \ - "Make a ReiserFS V3 filesystem\n" \ - "\nOptions:" \ - "\n -f Force" \ - "\n -l LBL Volume label" \ - -#define mkfs_vfat_trivial_usage \ - "[-v] [-n LABEL] BLOCKDEV [KBYTES]" -/* Accepted but ignored: - "[-c] [-C] [-I] [-l bad-block-file] [-b backup-boot-sector] " - "[-m boot-msg-file] [-i volume-id] " - "[-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs] " - "[-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors] " -*/ -#define mkfs_vfat_full_usage "\n\n" \ - "Make a FAT32 filesystem\n" \ - "\nOptions:" \ -/* "\n -c Check device for bad blocks" */ \ - "\n -v Verbose" \ -/* "\n -I Allow to use entire disk device (e.g. /dev/hda)" */ \ - "\n -n LBL Volume label" \ - -#define mknod_trivial_usage \ - "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE MAJOR MINOR" -#define mknod_full_usage "\n\n" \ - "Create a special file (block, character, or pipe)\n" \ - "\nOptions:" \ - "\n -m MODE Creation mode (default a=rw)" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) \ - "\nTYPE:" \ - "\n b Block device" \ - "\n c or u Character device" \ - "\n p Named pipe (MAJOR and MINOR are ignored)" \ - -#define mknod_example_usage \ - "$ mknod /dev/fd0 b 2 0\n" \ - "$ mknod -m 644 /tmp/pipe p\n" - -#define mkswap_trivial_usage \ - "[-L LBL] BLOCKDEV [KBYTES]" -#define mkswap_full_usage "\n\n" \ - "Prepare BLOCKDEV to be used as swap partition\n" \ - "\nOptions:" \ - "\n -L LBL Label" \ - -#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 more_trivial_usage \ - "[FILE]..." -#define more_full_usage "\n\n" \ - "View FILE (or stdin) one screenful at a time" - -#define more_example_usage \ - "$ dmesg | more\n" - -#define mount_trivial_usage \ - "[OPTIONS] [-o OPTS] DEVICE NODE" -#define mount_full_usage "\n\n" \ - "Mount a filesystem. Filesystem autodetection requires /proc.\n" \ - "\nOptions:" \ - "\n -a Mount all filesystems in fstab" \ - IF_FEATURE_MOUNT_FAKE( \ - IF_FEATURE_MTAB_SUPPORT( \ - "\n -f Update /etc/mtab, but don't mount" \ - ) \ - IF_NOT_FEATURE_MTAB_SUPPORT( \ - "\n -f Dry run" \ - ) \ - ) \ - IF_FEATURE_MOUNT_HELPERS( \ - "\n -i Don't run mount helper" \ - ) \ - IF_FEATURE_MTAB_SUPPORT( \ - "\n -n Don't update /etc/mtab" \ - ) \ - "\n -r Read-only mount" \ - "\n -w Read-write mount (default)" \ - "\n -t FSTYPE Filesystem type" \ - "\n -O OPT Mount only filesystems with option OPT (-a only)" \ - "\n-o OPT:" \ - IF_FEATURE_MOUNT_LOOP( \ - "\n loop Ignored (loop devices are autodetected)" \ - ) \ - IF_FEATURE_MOUNT_FLAGS( \ - "\n [a]sync Writes are [a]synchronous" \ - "\n [no]atime Disable/enable updates to inode access times" \ - "\n [no]diratime Disable/enable atime updates to directories" \ - "\n [no]relatime Disable/enable atime updates relative to modification time" \ - "\n [no]dev (Dis)allow use of special device files" \ - "\n [no]exec (Dis)allow use of executable files" \ - "\n [no]suid (Dis)allow set-user-id-root programs" \ - "\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 file or directory to another location" \ - "\n move Relocate an existing mount point" \ - ) \ - "\n remount Remount a mounted filesystem, changing flags" \ - "\n ro/rw Same as -r/-w" \ - "\n" \ - "\nThere are filesystem-specific -o flags." \ - -#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] <[-dn] DIR | -x DEVICE>" -#define mountpoint_full_usage "\n\n" \ - "Check if the directory is a mountpoint\n" \ - "\nOptions:" \ - "\n -q Quiet" \ - "\n -d Print major/minor device number of the filesystem" \ - "\n -n Print device name 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 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: /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" \ - -#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 instead of at EOL" \ - -#define nmeter_example_usage \ - "nmeter '%250d%t %20c int %i bio %b mem %m forks%p'" - -#define nohup_trivial_usage \ - "PROG ARGS" -#define nohup_full_usage "\n\n" \ - "Run PROG 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 ntpd_trivial_usage \ - "[-dnqNw"IF_FEATURE_NTPD_SERVER("l")"] [-S PROG] [-p PEER]..." -#define ntpd_full_usage "\n\n" \ - "NTP client/server\n" \ - "\nOptions:" \ - "\n -d Verbose" \ - "\n -n Do not daemonize" \ - "\n -q Quit after clock is set" \ - "\n -N Run at high priority" \ - "\n -w Do not set time (only query peers), implies -n" \ - IF_FEATURE_NTPD_SERVER( \ - "\n -l Run as server on port 123" \ - ) \ - "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" \ - "\n -p PEER Obtain time from PEER (may be repeated)" \ - -#define od_trivial_usage \ - "[-aBbcDdeFfHhIiLlOovXx] " IF_DESKTOP("[-t TYPE] ") "[FILE]" -#define od_full_usage "\n\n" \ - "Write an unambiguous representation, octal bytes by default, of FILE\n" \ - "(or stdin) to stdout" - -#define openvt_trivial_usage \ - "[-c N] [-sw] [PROG ARGS]" -#define openvt_full_usage "\n\n" \ - "Start PROG on a new virtual terminal\n" \ - "\nOptions:" \ - "\n -c N Use specified VT" \ - "\n -s Switch to the VT" \ -/* "\n -l Run PROG as login shell (by prepending '-')" */ \ - "\n -w Wait for PROG to exit" \ - -#define openvt_example_usage \ - "openvt 2 /bin/ash\n" - -/* -#define parse_trivial_usage \ - "[-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..." -#define parse_full_usage "" -*/ - -#define passwd_trivial_usage \ - "[OPTIONS] [USER]" -#define passwd_full_usage "\n\n" \ - "Change USER's password. If no USER is specified,\n" \ - "changes the password for the current user.\n" \ - "\nOptions:" \ - "\n -a ALG Algorithm to use for password (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 \ - IF_LONG_OPTS("[--md5|--encrypted]") IF_NOT_LONG_OPTS("[-m|-e]") -#define chpasswd_full_usage "\n\n" \ - "Read user:password from stdin and update /etc/passwd\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -e,--encrypted Supplied passwords are in encrypted form" \ - "\n -m,--md5 Use MD5 encryption instead of DES" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -e Supplied passwords are in encrypted form" \ - "\n -m Use MD5 encryption instead of DES" \ - ) - -#define pgrep_trivial_usage \ - "[-flnovx] [-s SID|-P PPID|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 match" \ - "\n -x Match whole name (not substring)" \ - "\n -s Match session ID (0 for current)" \ - "\n -P Match parent process ID" \ - -#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) -#define pidof_trivial_usage \ - "[OPTIONS] [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 \ - IF_FEATURE_PIDOF_SINGLE( \ - "\n -s Show only one PID" \ - ) \ - IF_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" \ - IF_FEATURE_PIDOF_OMIT( \ - "$ pidof /bin/sh\n20351 5973 5950\n") \ - IF_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 \ - "[OPTIONS] HOST" -#define ping_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts\n" \ - "\nOptions:" \ - "\n -4,-6 Force IP or IPv6 name 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 SEC Seconds to wait for the first response (default:10)" \ - "\n (after all -c CNT packets are sent)" \ - "\n -w SEC 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 \ - "[OPTIONS] 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|-SIGNAL] [-fnovx] [-s SID|-P PPID|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 match" \ - "\n -x Match whole name (not substring)" \ - "\n -s Match session ID (0 for current)" \ - "\n -P Match parent process ID" \ - -#define popmaildir_trivial_usage \ - "[OPTIONS] MAILDIR [CONN_HELPER ARGS]" -#define popmaildir_full_usage "\n\n" \ - "Fetch content of remote mailbox to local maildir\n" \ - "\nOptions:" \ -/* "\n -b Binary mode. Ignored" */ \ -/* "\n -d Debug. Ignored" */ \ -/* "\n -m Show used memory. Ignored" */ \ -/* "\n -V Show version. Ignored" */ \ -/* "\n -c Use tcpclient. Ignored" */ \ -/* "\n -a Use APOP protocol. Implied. If server supports APOP -> use it" */ \ - "\n -s Skip authorization" \ - "\n -T Get messages with TOP instead of RETR" \ - "\n -k Keep retrieved messages on the server" \ - "\n -t SEC Network timeout" \ - IF_FEATURE_POPMAILDIR_DELIVERY( \ - "\n -F \"PROG ARGS\" Filter program (may be repeated)" \ - "\n -M \"PROG ARGS\" Delivery program" \ - ) \ - "\n" \ - "\nFetch from plain POP3 server:" \ - "\npopmaildir -k DIR nc pop3.server.com 110 = BYTES. Ignored" */ -/* "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" */ -/* "\n -L BYTES Don't retrieve new messages >= BYTES. Ignored" */ -/* "\n -H LINES Type first LINES of a message. Ignored" */ -#define popmaildir_example_usage \ - "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [ after signal is processed" \ - -#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" IF_SCRIPTREPLAY("t") "] [-c PROG] [OUTFILE]" -#define script_full_usage "\n\n" \ - "Options:" \ - "\n -a Append output" \ - "\n -c PROG Run PROG, not shell" \ - "\n -f Flush output after each write" \ - "\n -q Quiet" \ - IF_SCRIPTREPLAY( \ - "\n -t Send timing to stderr" \ - ) - -#define sed_trivial_usage \ - "[-efinr] SED_CMD [FILE]..." -#define sed_full_usage "\n\n" \ - "Options:" \ - "\n -e CMD Add CMD to sed commands to be executed" \ - "\n -f FILE Add FILE contents to sed commands to be executed" \ - "\n -i Edit files in-place (else sends result to stdout)" \ - "\n -n Suppress automatic printing of pattern space" \ - "\n -r Use extended regex syntax" \ - "\n" \ - "\nIf no -e or -f, the first non-option argument is the sed command string." \ - "\nRemaining arguments are input files (stdin if none)." - -#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 \ - "[OPTIONS] [RECIPIENT_EMAIL]..." -#define sendmail_full_usage "\n\n" \ - "Read email from stdin and send it\n" \ - "\nStandard options:" \ - "\n -t Read additional recipients from message body" \ - "\n -f sender Sender (required)" \ - "\n -o options Various options. -oi implied, others are ignored" \ - "\n -i -oi synonym. implied and ignored" \ - "\n" \ - "\nBusybox specific options:" \ - "\n -w seconds Network timeout" \ - "\n -H 'PROG ARGS' Run connection helper" \ - "\n Examples:" \ - "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" \ - "\n -connect smtp.gmail.com:25' -ap]" \ - "\n -H 'exec openssl s_client -quiet -tls1" \ - "\n -connect smtp.gmail.com:465' -ap]" \ - "\n -S server[:port] Server" \ - "\n -au Username for AUTH LOGIN" \ - "\n -ap Password for AUTH LOGIN" \ - "\n -am Authentication method. Ignored. LOGIN is implied" \ - "\n" \ - "\nOther options are silently ignored; -oi -t is implied" \ - IF_MAKEMIME( \ - "\nUse makemime applet to create message with attachments" \ - ) - -#define seq_trivial_usage \ - "[-w] [-s SEP] [FIRST [INC]] LAST" -#define seq_full_usage "\n\n" \ - "Print numbers from FIRST to LAST, in steps of INC.\n" \ - "FIRST, INC default to 1.\n" \ - "\nOptions:" \ - "\n -w Pad to last with leading zeros" \ - "\n -s SEP String separator" \ - -#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" IF_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]" \ - IF_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" \ - IF_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 alternate root path" \ - "\n -e DIR Exclude DIR" \ - "\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 stdin (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 setfont_trivial_usage \ - "FONT [-m MAPFILE] [-C TTY]" -#define setfont_full_usage "\n\n" \ - "Load a console font\n" \ - "\nOptions:" \ - "\n -m MAPFILE Load console screen map" \ - "\n -C TTY Affect TTY instead of /dev/tty" \ - -#define setfont_example_usage \ - "$ setfont -m koi8-r /etc/i18n/fontname\n" - -#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 ARGS" -#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 last_trivial_usage \ - ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]") -#define last_full_usage "\n\n" \ - "Show listing of the last users that logged into the system" \ - IF_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 showkey_trivial_usage \ - "[-a | -k | -s]" -#define showkey_full_usage "\n\n" \ - "Show keys pressed\n" \ - "\nOptions:" \ - "\n -a Display decimal/octal/hex values of the keys" \ - "\n -k Display interpreted keycodes (default)" \ - "\n -s Display raw scan-codes" \ - -#define slattach_trivial_usage \ - "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" -#define slattach_full_usage "\n\n" \ - "Attach network interface(s) to serial line(s)\n" \ - "\nOptions:" \ - "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" \ - "\n -s SPD Set line speed" \ - "\n -e Exit after initializing device" \ - "\n -h Exit when the carrier is lost" \ - "\n -c PROG Run PROG 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 \ - IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...") -#define sleep_full_usage "\n\n" \ - IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds") \ - IF_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" \ - IF_FEATURE_FANCY_SLEEP( \ - "$ sleep 1d 3h 22m 8s\n" \ - "[98528 second delay results]\n") - -#define sort_trivial_usage \ - "[-nru" \ - IF_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:" \ - IF_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" \ - IF_FEATURE_SORT_BIG( \ - "\n -o Output to file" \ - "\n -k Sort by key" \ - "\n -t CHAR Key separator" \ - ) \ - "\n -r Reverse sort order" \ - IF_FEATURE_SORT_BIG( \ - "\n -s Stable (don't sort ties alphabetically)" \ - ) \ - "\n -u Suppress duplicate lines" \ - IF_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" \ - IF_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 \ - "[OPTIONS] [INPUT [PREFIX]]" -#define split_full_usage "\n\n" \ - "Options:" \ - "\n -b N[k|m] Split by N (kilo|mega)bytes" \ - "\n -l N Split by N 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] ... [-- ARGS...]" -#define start_stop_daemon_full_usage "\n\n" \ - "Search for matching processes, and then\n" \ - "-K: stop all matching processes.\n" \ - "-S: start a process unless a matching process is found.\n" \ - IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \ - "\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-S only:" \ - "\n -x,--exec EXECUTABLE Program to run" \ - "\n -a,--startas NAME Zeroth argument" \ - "\n -b,--background Background" \ - IF_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-K only:" \ - "\n -s,--signal SIG Signal to send" \ - "\n -t,--test Match only, exit with 0 if a process is found" \ - "\nOther:" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -o,--oknodo Exit with status 0 if nothing is done" \ - "\n -v,--verbose Verbose" \ - ) \ - "\n -q,--quiet Quiet" \ - ) \ - IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \ - "\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-S only:" \ - "\n -x EXECUTABLE Program to run" \ - "\n -a NAME Zeroth argument" \ - "\n -b Background" \ - IF_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-K only:" \ - "\n -s SIG Signal to send" \ - "\n -t Match only, exit with 0 if a process is found" \ - "\nOther:" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -o Exit with status 0 if nothing is done" \ - "\n -v Verbose" \ - ) \ - "\n -q Quiet" \ - ) \ - -#define stat_trivial_usage \ - "[OPTIONS] FILE..." -#define stat_full_usage "\n\n" \ - "Display file (default) or filesystem status\n" \ - "\nOptions:" \ - IF_FEATURE_STAT_FORMAT( \ - "\n -c fmt Use the specified format" \ - ) \ - "\n -f Display filesystem status" \ - "\n -L Follow links" \ - "\n -t Display info in terse form" \ - IF_SELINUX( \ - "\n -Z Print security context" \ - ) \ - IF_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 File name, with -> TARGET 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" \ - IF_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 LEN] [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 LEN At least LEN 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 \ - "[OPTIONS] [-] [USERNAME]" -#define su_full_usage "\n\n" \ - "Change user id or become root\n" \ - "\nOptions:" \ - "\n -p,-m Preserve environment" \ - "\n -c CMD Command to pass to 'sh -c'" \ - "\n -s SH Shell to use instead of default shell" \ - -#define sulogin_trivial_usage \ - "[-t N] [TTY]" -#define sulogin_full_usage "\n\n" \ - "Single user login\n" \ - "\nOptions:" \ - "\n -t N Timeout" \ - -#define sum_trivial_usage \ - "[-rs] [FILE]..." -#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] CMD SERVICE_DIR..." -#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, don't 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 CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..." -#define svlogd_full_usage "\n\n" \ - "Continuously read log data from stdin, optionally\n" \ - "filter log messages, and write the data to one or more automatically\n" \ - "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]" IF_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" \ - IF_FEATURE_SWAPON_PRI( \ - "\n -p PRI Set swap device priority" \ - ) \ - -#define switch_root_trivial_usage \ - "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]" -#define switch_root_full_usage "\n\n" \ - "Free initramfs and switch to another root fs:\n" \ - "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" \ - "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" \ - "\nOptions:" \ - "\n -c DEV Reopen stdio to DEV after switch" \ - -#define sync_trivial_usage \ - "" -#define sync_full_usage "\n\n" \ - "Write all buffered blocks to disk" - -#define fsync_trivial_usage \ - "[-d] FILE..." -#define fsync_full_usage "\n\n" \ - "Write files' buffered blocks to disk\n" \ - "\nOptions:" \ - "\n -d Avoid syncing metadata" - -#define sysctl_trivial_usage \ - "[OPTIONS] [VALUE]..." -#define sysctl_full_usage "\n\n" \ - "Configure kernel parameters at runtime\n" \ - "\nOptions:" \ - "\n -n Don't print 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 \ - "[OPTIONS]" -#define syslogd_full_usage "\n\n" \ - "System logging utility.\n" \ - "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" \ - IF_FEATURE_ROTATE_LOGFILE( \ - "\n -s SIZE Max size (KB) before rotate (default:200KB, 0=off)" \ - "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)") \ - IF_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)") \ - IF_FEATURE_SYSLOGD_DUP( \ - "\n -D Drop duplicates") \ - IF_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 FILEs and print them in reverse" - -#define taskset_trivial_usage \ - "[-p] [MASK] [PID | PROG ARGS]" -#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 \ - "[-ai] [FILE]..." -#define tee_full_usage "\n\n" \ - "Copy stdin to each FILE, and also to stdout\n" \ - "\nOptions:" \ - "\n -a Append to the given FILEs, don't 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 Automatic login with $USER variable" \ - "\n -l USER Automatic login as USER" \ - -#else -#define telnet_trivial_usage \ - "HOST [PORT]" -#define telnet_full_usage "\n\n" \ - "Connect to telnet server" -#endif - -#define telnetd_trivial_usage \ - "[OPTIONS]" -#define telnetd_full_usage "\n\n" \ - "Handle incoming telnet connections" \ - IF_NOT_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)" \ - IF_FEATURE_TELNETD_STANDALONE( \ - "\n -p PORT Port to listen on" \ - "\n -b ADDR[:PORT] Address to bind to" \ - "\n -F Run in foreground" \ - "\n -i Inetd mode" \ - IF_FEATURE_TELNETD_INETD_WAIT( \ - "\n -w SEC Inetd 'wait' mode, linger time SEC" \ - "\n -S Log to syslog (implied by -i or without -F and -w)" \ - ) \ - ) - -/* "test --help" does not print help (POSIX compat), only "[ --help" does. - * We display " EXPRESSION ]" here (not " EXPRESSION") - * Unfortunately, it screws up generated BusyBox.html. TODO. */ -#define test_trivial_usage \ - "EXPRESSION ]" -#define test_full_usage "\n\n" \ - "Check file types, compare values etc. Return a 0/1 exit code\n" \ - "depending on logical 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 tc_trivial_usage \ - /*"[OPTIONS] "*/"OBJECT CMD [dev STRING]" -#define tc_full_usage "\n\n" \ - "OBJECT: {qdisc|class|filter}\n" \ - "CMD: {add|del|change|replace|show}\n" \ - "\n" \ - "qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \ - /* "[ estimator INTERVAL TIME_CONSTANT ]\n" */ \ - " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \ - " QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" \ - "qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n" \ - "class [ classid CLASSID ] [ root | parent CLASSID ]\n" \ - " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \ - "class show [ dev STRING ] [ root | parent CLASSID ]\n" \ - "filter [ pref PRIO ] [ protocol PROTO ]\n" \ - /* "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ \ - " [ root | classid CLASSID ] [ handle FILTERID ]\n" \ - " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" \ - "filter show [ dev STRING ] [ root | parent CLASSID ]" - -#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 to IP:PORT and listen\n" \ - "for incoming connection. Run PROG for each connection.\n" \ - "\n IP IP to listen on. '0' = all" \ - "\n PORT Port to listen on" \ - "\n PROG ARGS Program to run" \ - "\n -l NAME Local hostname (else looks up local hostname in DNS)" \ - "\n -u USER[:GRP] 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 Don't 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 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" \ - "\n IP IP to listen on. '0' = all" \ - "\n PORT Port to listen on" \ - "\n PROG ARGS Program to run" \ - "\n -l NAME Local hostname (else looks up local hostname in DNS)" \ - "\n -u USER[:GRP] Change to user/group after bind" \ - "\n -c N Handle up to N connections simultaneously" \ - "\n -h Look up peer's hostname" \ - "\n -E Don't set up environment variables" \ - "\n -v Verbose" \ - -#define tftp_trivial_usage \ - "[OPTIONS] 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" \ - IF_FEATURE_TFTP_GET( \ - "\n -g Get file" \ - ) \ - IF_FEATURE_TFTP_PUT( \ - "\n -p Put file" \ - ) \ - IF_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" \ - "\n" \ - "tftpd should be used as an inetd service.\n" \ - "tftpd's line for inetd.conf:\n" \ - " 69 dgram udp nowait root tftpd tftpd /files/to/serve\n" \ - "It also can be ran from udpsvd:\n" \ - " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" \ - "\nOptions:" \ - "\n -r Prohibit upload" \ - "\n -c Allow file creation via upload" \ - "\n -u Access files as USER" \ - -#define time_trivial_usage \ - "[-v] PROG ARGS" -#define time_full_usage "\n\n" \ - "Run PROG, display resource usage when it exits\n" \ - "\nOptions:" \ - "\n -v Verbose" \ - -#define timeout_trivial_usage \ - "[-t SECS] [-s SIG] PROG ARGS" -#define timeout_full_usage "\n\n" \ - "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n" \ - "Defaults: SECS: 10, SIG: TERM." \ - -#define top_trivial_usage \ - "[-b] [-nCOUNT] [-dSECONDS]" IF_FEATURE_TOPMEM(" [-m]") -#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 display a screenful of them." \ -//TODO: add options and keyboard commands - -#define touch_trivial_usage \ - "[-c] [-d DATE] [-r FILE] FILE [FILE]..." -#define touch_full_usage "\n\n" \ - "Update the last-modified date on the given FILE[s]\n" \ - "\nOptions:" \ - "\n -c Don't create files" \ - "\n -d DT Date/time to use" \ - "\n -r FILE Use FILE's date/time" \ - -#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, or delete characters from stdin, writing to stdout\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 \ - "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" \ - " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" \ - " [-z PAUSE_MSEC] HOST [BYTES]" -#define traceroute_full_usage "\n\n" \ - "Trace the route to HOST\n" \ - "\nOptions:" \ - IF_TRACEROUTE6( \ - "\n -4,-6 Force IP or IPv6 name resolution" \ - ) \ - "\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 numeric addresses" \ - "\n -r Bypass routing tables, send directly to HOST" \ - "\n -v Verbose" \ - "\n -m Max time-to-live (max number of hops)" \ - "\n -p Base UDP port number used in probes" \ - "\n (default 33434)" \ - "\n -q Number of probes per TTL (default 3)" \ - "\n -s IP address to use as the source address" \ - "\n -t Type-of-service in probe packets (default 0)" \ - "\n -w Time in seconds to wait for a response (default 3)" \ - "\n -g Loose source route gateway (8 max)" \ - -#define traceroute6_trivial_usage \ - "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" \ - " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" \ - " HOST [BYTES]" -#define traceroute6_full_usage "\n\n" \ - "Trace the route to HOST\n" \ - "\nOptions:" \ - "\n -d Set SO_DEBUG options to socket" \ - "\n -n Print numeric addresses" \ - "\n -r Bypass routing tables, send directly to HOST" \ - "\n -v Verbose" \ - "\n -m Max time-to-live (max number of hops)" \ - "\n -p Base UDP port number used in probes" \ - "\n (default is 33434)" \ - "\n -q Number of probes per TTL (default 3)" \ - "\n -s IP address to use as the source address" \ - "\n -t Type-of-service in probe packets (default 0)" \ - "\n -w Time in seconds to wait for a response (default 3)" \ - -#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 stdin's terminal" \ - IF_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 stdin's terminal, on error return 80x25" - -#define tunctl_trivial_usage \ - "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") -#define tunctl_full_usage "\n\n" \ - "Create or delete tun interfaces\n" \ - "\nOptions:" \ - "\n -f name tun device (/dev/net/tun)" \ - "\n -t name Create iface 'name'" \ - "\n -d name Delete iface 'name'" \ - IF_FEATURE_TUNCTL_UG( \ - "\n -u owner Set iface owner" \ - "\n -g group Set iface group" \ - "\n -b Brief output" \ - ) -#define tunctl_example_usage \ - "# tunctl\n" \ - "# tunctl -d tun0\n" - -#define udhcpd_trivial_usage \ - "[-fS]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" \ - -#define udhcpd_full_usage "\n\n" \ - "DHCP server\n" \ - "\n -f Run in foreground" \ - "\n -S Log to syslog too" \ - IF_FEATURE_UDHCP_PORT( \ - "\n -P N Use port N (default 67)" \ - ) - -#define umount_trivial_usage \ - "[OPTIONS] FILESYSTEM|DIRECTORY" -#define umount_full_usage "\n\n" \ - "Unmount file systems\n" \ - "\nOptions:" \ - IF_FEATURE_UMOUNT_ALL( \ - "\n -a Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab") \ - ) \ - IF_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)" \ - IF_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 \ - "[-cf] [FILE]..." -#define uncompress_full_usage "\n\n" \ - "Decompress .Z file[s]\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Overwrite" \ - -#define unexpand_trivial_usage \ - "[-fa][-t N] [FILE]..." -#define unexpand_full_usage "\n\n" \ - "Convert spaces to tabs, writing to stdout\n" \ - "\nOptions:" \ - IF_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" \ - ) \ - IF_NOT_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 \ - "[-cdu][-f,s,w N] [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 unzip_trivial_usage \ - "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]" -#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 files (default)" \ - "\n -o Overwrite" \ - "\n -p Send output to stdout" \ - "\n -q Quiet" \ - "\n -x XLST Exclude these files" \ - "\n -d DIR Extract files into DIR" \ - -#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" \ - "\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 \ - "[OPTIONS] [FILE]..." -#define vi_full_usage "\n\n" \ - "Edit FILE\n" \ - "\nOptions:" \ - IF_FEATURE_VI_COLON( \ - "\n -c Initial command to run ($EXINIT also available)" \ - ) \ - IF_FEATURE_VI_READONLY( \ - "\n -R Read-only" \ - ) \ - "\n -H Short help regarding available features" \ - -#define vlock_trivial_usage \ - "[-a]" -#define vlock_full_usage "\n\n" \ - "Lock a virtual terminal. A password is required to unlock.\n" \ - "\nOptions:" \ - "\n -a Lock all VTs" \ - -#define volname_trivial_usage \ - "[DEVICE]" -#define volname_full_usage "\n\n" \ - "Show CD volume name of the DEVICE (default /dev/cdrom)" - -#define wall_trivial_usage \ - "[FILE]" -#define wall_full_usage "\n\n" \ - "Write content of FILE or stdin to all logged-in users" -#define wall_sample_usage \ - "echo foo | wall\n" \ - "wall ./mymessage" - -#define watch_trivial_usage \ - "[-n SEC] [-t] PROG ARGS" -#define watch_full_usage "\n\n" \ - "Run PROG 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]] [-T N[ms]] [-F] DEV" -#define watchdog_full_usage "\n\n" \ - "Periodically write to watchdog device DEV\n" \ - "\nOptions:" \ - "\n -T N Reboot after N seconds if not reset (default 60)" \ - "\n -t N Reset every N seconds (default 30)" \ - "\n -F Run in foreground" \ - "\n" \ - "\nUse 500ms to specify period in milliseconds" \ - -#define wget_trivial_usage \ - IF_FEATURE_WGET_LONG_OPTIONS( \ - "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" \ - " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" \ - " [--no-check-certificate] [-U|--user-agent AGENT]" \ - IF_FEATURE_WGET_TIMEOUT("[-T SEC] ") " URL" \ - ) \ - IF_NOT_FEATURE_WGET_LONG_OPTIONS( \ - "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]" \ - IF_FEATURE_WGET_TIMEOUT("[-T SEC] ") " 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 DIR Save to DIR (default .)" \ - IF_FEATURE_WGET_TIMEOUT( \ - "\n -T SEC Network read timeout is SEC seconds" \ - ) \ - "\n -O FILE Save to FILE ('-' for stdout)" \ - "\n -U STR Use STR for User-Agent header" \ - "\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 zcat_trivial_usage \ - "FILE" -#define zcat_full_usage "\n\n" \ - "Decompress to stdout" - -#define zcip_trivial_usage \ - "[OPTIONS] IFACE 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 obtaining address" \ - "\n -r 169.254.x.x Request this address first" \ - "\n -v Verbose" \ - "\n" \ - "\nWith no -q, runs continuously monitoring for ARP conflicts," \ - "\nexits only on I/O errors (link down etc)" \ - - -#endif +/* 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 1 + +#define NOUSAGE_STR "\b" + +INSERT + +#define busybox_notes_usage \ + "Hello world!\n" + +#endif diff --git a/release/src/router/busybox/include/volume_id.h b/release/src/router/busybox/include/volume_id.h index 4e5c692a61..b61f100eb9 100644 --- a/release/src/router/busybox/include/volume_id.h +++ b/release/src/router/busybox/include/volume_id.h @@ -21,7 +21,7 @@ char *get_devname_from_label(const char *spec); char *get_devname_from_uuid(const char *spec); char *get_devname_from_device(dev_t dev); -void display_uuid_cache(void); +void display_uuid_cache(int scan_devices); /* Returns: * 0 : no UUID= or LABEL= prefix found @@ -30,3 +30,4 @@ void display_uuid_cache(void); * -2: UUID= or LABEL= prefixes cannot be resolved */ int resolve_mount_spec(char **fsname); +int add_to_uuid_cache(const char *device, dev_t devno); diff --git a/release/src/router/busybox/include/xatonum.h b/release/src/router/busybox/include/xatonum.h index 6f76a3c96f..45ebbfc00e 100644 --- a/release/src/router/busybox/include/xatonum.h +++ b/release/src/router/busybox/include/xatonum.h @@ -168,6 +168,15 @@ uint32_t bb_strtou32(const char *arg, char **endp, int base) return bb_strtoul(arg, endp, base); return BUG_bb_strtou32_unimplemented(); } +static ALWAYS_INLINE +int32_t bb_strtoi32(const char *arg, char **endp, int base) +{ + if (sizeof(int32_t) == sizeof(int)) + return bb_strtoi(arg, endp, base); + if (sizeof(int32_t) == sizeof(long)) + return bb_strtol(arg, endp, base); + return BUG_bb_strtou32_unimplemented(); +} /* Floating point */ diff --git a/release/src/router/busybox/init/bootchartd.c b/release/src/router/busybox/init/bootchartd.c index 5a1b3e8e88..9fd6233578 100644 --- a/release/src/router/busybox/init/bootchartd.c +++ b/release/src/router/busybox/init/bootchartd.c @@ -3,7 +3,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_BOOTCHARTD(APPLET(bootchartd, BB_DIR_SBIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_BOOTCHARTD) += bootchartd.o @@ -208,14 +208,8 @@ static char *make_tempdir(void) return tempdir; } -static void do_logging(unsigned sample_period_us) +static void do_logging(unsigned sample_period_us, int process_accounting) { - //# Enable process accounting if configured - //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then - // [ -e kernel_pacct ] || : > kernel_pacct - // accton kernel_pacct - //fi - FILE *proc_stat = xfopen("proc_stat.log", "w"); FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); @@ -223,6 +217,11 @@ static void do_logging(unsigned sample_period_us) int look_for_login_process = (getppid() == 1); unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ + if (process_accounting) { + close(xopen("kernel_pacct", O_WRONLY | O_CREAT | O_TRUNC)); + acct("kernel_pacct"); + } + while (--count && !bb_got_signal) { char *p; int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2); @@ -253,11 +252,9 @@ static void do_logging(unsigned sample_period_us) wait_more: usleep(sample_period_us); } - - // [ -e kernel_pacct ] && accton off } -static void finalize(char *tempdir, const char *prog) +static void finalize(char *tempdir, const char *prog, int process_accounting) { //# Stop process accounting if configured //local pacct= @@ -265,6 +262,9 @@ static void finalize(char *tempdir, const char *prog) FILE *header_fp = xfopen("header", "w"); + if (process_accounting) + acct(NULL); + if (prog) fprintf(header_fp, "profile.process = %s\n", prog); @@ -307,7 +307,7 @@ static void finalize(char *tempdir, const char *prog) fclose(header_fp); /* Package log files */ - system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct + system(xasprintf("tar -zcf /var/log/bootlog.tgz header %s *.log", process_accounting ? "kernel_pacct" : "")); /* Clean up (if we are not in detached tmpfs) */ if (tempdir) { unlink("header"); @@ -315,6 +315,8 @@ static void finalize(char *tempdir, const char *prog) unlink("proc_diskstats.log"); //unlink("proc_netdev.log"); unlink("proc_ps.log"); + if (process_accounting) + unlink("kernel_pacct"); rmdir(tempdir); } @@ -327,7 +329,6 @@ static void finalize(char *tempdir, const char *prog) //usage: "start [PROG ARGS]|stop|init" //usage:#define bootchartd_full_usage "\n\n" //usage: "Create /var/log/bootchart.tgz with boot chart data\n" -//usage: "\nOptions:" //usage: "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" //usage: "\nstop: send USR1 to all bootchartd processes" //usage: "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" @@ -339,6 +340,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) unsigned sample_period_us; pid_t parent_pid, logger_pid; smallint cmd; + int process_accounting; enum { CMD_STOP = 0, CMD_START, @@ -372,6 +374,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) /* Read config file: */ sample_period_us = 200 * 1000; + process_accounting = 0; if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { char* token[2]; parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); @@ -380,11 +383,16 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) sample_period_us = atof(token[1]) * 1000000; + if (strcmp(token[0], "PROCESS_ACCOUNTING") == 0 && token[1] + && (strcmp(token[1], "on") == 0 || strcmp(token[1], "yes") == 0) + ) { + process_accounting = 1; + } } config_close(parser); + if ((int)sample_period_us <= 0) + sample_period_us = 1; /* prevent division by 0 */ } - if ((int)sample_period_us <= 0) - sample_period_us = 1; /* prevent division by 0 */ /* Create logger child: */ logger_pid = fork_or_rexec(argv); @@ -412,13 +420,15 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) putenv((char*)bb_PATH_root_path); tempdir = make_tempdir(); - do_logging(sample_period_us); - finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); + do_logging(sample_period_us, process_accounting); + finalize(tempdir, cmd == CMD_START ? argv[2] : NULL, process_accounting); return EXIT_SUCCESS; } /* parent */ + USE_FOR_NOMMU(argv[0][0] &= 0x7f); /* undo fork_or_rexec() damage */ + if (DO_SIGNAL_SYNC) { /* Wait for logger child to set handlers, then unpause it. * Otherwise with short-lived PROG (e.g. "bootchartd start true") @@ -441,8 +451,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) pid_t pid = xvfork(); if (pid == 0) { /* child */ argv += 2; - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } /* parent */ waitpid(pid, NULL, 0); diff --git a/release/src/router/busybox/init/halt.c b/release/src/router/busybox/init/halt.c index 47f1ef7b2b..7974adb17f 100644 --- a/release/src/router/busybox/init/halt.c +++ b/release/src/router/busybox/init/halt.c @@ -7,9 +7,9 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP)) -//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff)) -//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot)) +//applet:IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff)) +//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot)) //kbuild:lib-$(CONFIG_HALT) += halt.o @@ -43,7 +43,6 @@ //usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]") //usage:#define halt_full_usage "\n\n" //usage: "Halt the system\n" -//usage: "\nOptions:" //usage: "\n -d SEC Delay interval" //usage: "\n -n Do not sync" //usage: "\n -f Force (don't go through init)" @@ -55,7 +54,6 @@ //usage: "[-d DELAY] [-n] [-f]" //usage:#define poweroff_full_usage "\n\n" //usage: "Halt and shut off power\n" -//usage: "\nOptions:" //usage: "\n -d SEC Delay interval" //usage: "\n -n Do not sync" //usage: "\n -f Force (don't go through init)" @@ -64,7 +62,6 @@ //usage: "[-d DELAY] [-n] [-f]" //usage:#define reboot_full_usage "\n\n" //usage: "Reboot the system\n" -//usage: "\nOptions:" //usage: "\n -d SEC Delay interval" //usage: "\n -n Do not sync" //usage: "\n -f Force (don't go through init)" @@ -74,7 +71,6 @@ #if ENABLE_FEATURE_WTMP #include -#include static void write_wtmp(void) { @@ -158,11 +154,13 @@ int halt_main(int argc UNUSED_PARAM, char **argv) /* runlevels: * 0 == shutdown * 6 == reboot */ - rc = execlp(CONFIG_TELINIT_PATH, + execlp(CONFIG_TELINIT_PATH, CONFIG_TELINIT_PATH, which == 2 ? "6" : "0", (char *)NULL ); + bb_perror_msg_and_die("can't execute '%s'", + CONFIG_TELINIT_PATH); } } } else { diff --git a/release/src/router/busybox/init/init.c b/release/src/router/busybox/init/init.c index 0a0d503b5b..7248946988 100644 --- a/release/src/router/busybox/init/init.c +++ b/release/src/router/busybox/init/init.c @@ -9,8 +9,8 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP)) -//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc)) +//applet:IF_INIT(APPLET(init, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, BB_DIR_ROOT, BB_SUID_DROP, linuxrc)) //kbuild:lib-$(CONFIG_INIT) += init.o @@ -108,18 +108,27 @@ //config: Note that on Linux, init attempts to detect serial terminal and //config: sets TERM to "vt102" if one is found. +#define DEBUG_SEGV_HANDLER 0 + #include "libbb.h" #include #include #include #ifdef __linux__ -#include -#endif -#if ENABLE_FEATURE_UTMP -# include /* DEAD_PROCESS */ +# include +# include #endif #include "reboot.h" /* reboot() constants */ +#if DEBUG_SEGV_HANDLER +# undef _GNU_SOURCE +# define _GNU_SOURCE 1 +# undef __USE_GNU +# define __USE_GNU 1 +# include +# include +#endif + /* Used only for sanitizing purposes in set_sane_term() below. On systems where * the baud rate is stored in a separate field, we can safely disable them. */ #ifndef CBAUD @@ -401,20 +410,23 @@ static void init_exec(const char *command) char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); + command += dash; + /* See if any special /bin/sh requiring characters are present */ if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { - strcpy(buf, "exec "); - strcpy(buf + 5, command + dash); /* excluding "-" */ + sprintf(buf, "exec %s", command); /* 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; + command = LIBBB_DEFAULT_LOGIN_SHELL + 1; } else { /* Convert command (char*) into cmd (char**, one word per string) */ char *word, *next; int i = 0; - next = strcpy(buf, command); /* including "-" */ + next = strcpy(buf, command - dash); /* command including "-" */ + command = next + dash; while ((word = strsep(&next, " \t")) != NULL) { if (*word != '\0') { /* not two spaces/tabs together? */ cmd[i] = word; @@ -425,14 +437,14 @@ static void init_exec(const char *command) } /* If we saw leading "-", it is interactive shell. * Try harder to give it a controlling tty. - * And skip "-" in actual exec call. */ - if (dash) { + */ + if (ENABLE_FEATURE_INIT_SCTTY && dash) { /* _Attempt_ to make stdin a controlling tty. */ - if (ENABLE_FEATURE_INIT_SCTTY) - ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); + ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); } - BB_EXECVP(cmd[0] + dash, cmd); - message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno)); + /* Here command never contains the dash, cmd[0] might */ + BB_EXECVP(command, cmd); + message(L_LOG | L_CONSOLE, "can't run '%s': %s", command, strerror(errno)); /* returns if execvp fails */ } @@ -522,15 +534,17 @@ static struct init_action *mark_terminated(pid_t pid) struct init_action *a; if (pid > 0) { + update_utmp(pid, DEAD_PROCESS, + /*tty_name:*/ NULL, + /*username:*/ NULL, + /*hostname:*/ NULL + ); for (a = init_action_list; a; a = a->next) { if (a->pid == pid) { a->pid = 0; return a; } } - update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, - /*username:*/ NULL, - /*hostname:*/ NULL); } return NULL; } @@ -595,7 +609,7 @@ static void new_init_action(uint8_t action_type, const char *command, const char */ nextp = &init_action_list; while ((a = *nextp) != NULL) { - /* Don't enter action if it's already in the list, + /* Don't enter action if it's already in the list. * This prevents losing running RESPAWNs. */ if (strcmp(a->command, command) == 0 @@ -607,14 +621,15 @@ static void new_init_action(uint8_t action_type, const char *command, const char while (*nextp != NULL) nextp = &(*nextp)->next; a->next = NULL; - break; + goto append; } nextp = &a->next; } - if (!a) - a = xzalloc(sizeof(*a)); + a = xzalloc(sizeof(*a)); + /* Append to the end of the list */ + append: *nextp = a; a->action_type = action_type; safe_strncpy(a->command, command, sizeof(a->command)); @@ -953,6 +968,33 @@ static int check_delayed_sigs(void) } } +#if DEBUG_SEGV_HANDLER +static +void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) +{ + long ip; + ucontext_t *uc; + + uc = ucontext; + ip = uc->uc_mcontext.gregs[REG_EIP]; + fdprintf(2, "signal:%d address:0x%lx ip:0x%lx\n", + sig, + /* this is void*, but using %p would print "(null)" + * even for ptrs which are not exactly 0, but, say, 0x123: + */ + (long)info->si_addr, + ip); + { + /* glibc extension */ + void *array[50]; + int size; + size = backtrace(array, 50); + backtrace_symbols_fd(array, size, 2); + } + for (;;) sleep(9999); +} +#endif + int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { @@ -960,6 +1002,19 @@ int init_main(int argc UNUSED_PARAM, char **argv) return kill(1, SIGHUP); } +#if DEBUG_SEGV_HANDLER + { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handle_sigsegv; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + } +#endif + if (!DEBUG_INIT) { /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 diff --git a/release/src/router/busybox/init/mesg.c b/release/src/router/busybox/init/mesg.c index b6fd070e17..45c13b8e03 100644 --- a/release/src/router/busybox/init/mesg.c +++ b/release/src/router/busybox/init/mesg.c @@ -7,16 +7,28 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - -//kbuild:lib-$(CONFIG_MESG) += mesg.o - //config:config MESG //config: bool "mesg" //config: default y //config: help //config: Mesg controls access to your terminal by others. It is typically //config: used to allow or disallow other users to write to your terminal +//config: +//config:config FEATURE_MESG_ENABLE_ONLY_GROUP +//config: bool "Enable writing to tty only by group, not by everybody" +//config: default y +//config: depends on MESG +//config: help +//config: Usually, ttys are owned by group "tty", and "write" tool is +//config: setgid to this group. This way, "mesg y" only needs to enable +//config: "write by owning group" bit in tty mode. +//config: +//config: If you set this option to N, "mesg y" will enable writing +//config: by anybody at all. This is not recommended. + +//applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_MESG) += mesg.o //usage:#define mesg_trivial_usage //usage: "[y|n]" @@ -27,7 +39,7 @@ #include "libbb.h" -#ifdef USE_TTY_GROUP +#if ENABLE_FEATURE_MESG_ENABLE_ONLY_GROUP #define S_IWGRP_OR_S_IWOTH S_IWGRP #else #define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH) @@ -37,30 +49,28 @@ int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mesg_main(int argc UNUSED_PARAM, char **argv) { struct stat sb; - const char *tty; + mode_t m; char c = 0; argv++; - if (!argv[0] - || (!argv[1] && ((c = argv[0][0]) == 'y' || c == 'n')) + if (argv[0] + && (argv[1] || ((c = argv[0][0]) != 'y' && c != 'n')) ) { - tty = xmalloc_ttyname(STDERR_FILENO); - if (tty == NULL) { - tty = "ttyname"; - } else if (stat(tty, &sb) == 0) { - mode_t m; - if (c == 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(); + } + + if (!isatty(STDIN_FILENO)) + bb_error_msg_and_die("not a tty"); + + xfstat(STDIN_FILENO, &sb, "stderr"); + if (c == 0) { + puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); + return EXIT_SUCCESS; } - bb_show_usage(); + m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH + : sb.st_mode & ~(S_IWGRP|S_IWOTH); + if (fchmod(STDIN_FILENO, m) != 0) + bb_perror_nomsg_and_die(); + return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/libbb/Config.src b/release/src/router/busybox/libbb/Config.src index f6c7a11ea4..ee1b66a458 100644 --- a/release/src/router/busybox/libbb/Config.src +++ b/release/src/router/busybox/libbb/Config.src @@ -14,9 +14,9 @@ config PASSWORD_MINLEN help Minimum allowable password length. -config MD5_SIZE_VS_SPEED +config MD5_SMALL int "MD5: Trade bytes for speed (0:fast, 3:slow)" - default 2 + default 1 range 0 3 help Trade binary size versus speed for the md5sum algorithm. @@ -80,11 +80,12 @@ config FEATURE_EDITING_VI config FEATURE_EDITING_HISTORY int "History size" - range 0 99999 + # Don't allow way too big values here, code uses fixed "char *history[N]" struct member + range 0 9999 default 255 depends on FEATURE_EDITING help - Specify command history size. + Specify command history size (0 - disable). config FEATURE_EDITING_SAVEHISTORY bool "History saving" @@ -93,6 +94,21 @@ config FEATURE_EDITING_SAVEHISTORY help Enable history saving in shells. +config FEATURE_EDITING_SAVE_ON_EXIT + bool "Save history on shell exit, not after every command" + default n + depends on FEATURE_EDITING_SAVEHISTORY + help + Save history on shell exit, not after every command. + +config FEATURE_REVERSE_SEARCH + bool "Reverse history search" + default y + depends on FEATURE_EDITING_SAVEHISTORY + help + Enable readline-like Ctrl-R combination for reverse history search. + Increases code by about 0.5k. + config FEATURE_TAB_COMPLETION bool "Tab completion" default y @@ -135,7 +151,7 @@ config FEATURE_NON_POSIX_CP and create a regular file. This does not conform to POSIX, but prevents a symlink attack. Similarly, "cp file device" will not send file's data - to the device. + to the device. (To do that, use "cat file >device") config FEATURE_VERBOSE_CP_MESSAGE bool "Give more precise messages when copy fails (cp, mv etc)" @@ -156,15 +172,34 @@ config FEATURE_COPYBUF_KB range 1 1024 default 4 help - Size of buffer used by cp, mv, install etc. + Size of buffer used by cp, mv, install, wget 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 FEATURE_SKIP_ROOTFS + bool "Skip rootfs in mount table" + default y + help + Ignore rootfs entry in mount table. + + In Linux, kernel has a special filesystem, rootfs, which is initially + mounted on /. It contains initramfs data, if kernel is configured + to have one. Usually, another file system is mounted over / early + in boot process, and therefore most tools which manipulate + mount table, such as df, will skip rootfs entry. + + However, some systems do not mount anything on /. + If you need to configure busybox for one of these systems, + you may find it useful to turn this option off to make df show + initramfs statistics. + + Otherwise, choose Y. + config MONOTONIC_SYSCALL bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" default n - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring time intervals (time, ping, traceroute etc need this). diff --git a/release/src/router/busybox/libbb/Kbuild.src b/release/src/router/busybox/libbb/Kbuild.src index 0fa1451597..61eec26f70 100644 --- a/release/src/router/busybox/libbb/Kbuild.src +++ b/release/src/router/busybox/libbb/Kbuild.src @@ -13,7 +13,6 @@ INSERT lib-y += appletlib.o lib-y += ask_confirmation.o lib-y += bb_askpass.o -lib-y += bb_basename.o lib-y += bb_bswap_64.o lib-y += bb_do_delay.o lib-y += bb_pwd.o @@ -59,15 +58,12 @@ lib-y += llist.o lib-y += login.o lib-y += make_directory.o lib-y += makedev.o -lib-y += match_fstype.o lib-y += hash_md5_sha.o # Alternative (disabled) MD5 implementation #lib-y += hash_md5prime.o lib-y += messages.o lib-y += mode_string.o -lib-y += obscure.o lib-y += parse_mode.o -lib-y += parse_config.o lib-y += perror_msg.o lib-y += perror_nomsg.o lib-y += perror_nomsg_and_die.o @@ -101,7 +97,6 @@ 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 @@ -120,6 +115,8 @@ lib-y += xgethostbyname.o lib-y += xreadlink.o lib-y += xrealloc_vector.o +lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o + lib-$(CONFIG_FEATURE_UTMP) += utmp.o # A mix of optimizations (why build stuff we know won't be used) @@ -129,6 +126,15 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o +lib-$(CONFIG_NC) += udp_io.o +lib-$(CONFIG_DNSD) += udp_io.o +lib-$(CONFIG_NTPD) += udp_io.o +lib-$(CONFIG_TFTP) += udp_io.o +lib-$(CONFIG_TFTPD) += udp_io.o +lib-$(CONFIG_TCPSVD) += udp_io.o +lib-$(CONFIG_UDPSVD) += udp_io.o +lib-$(CONFIG_TRACEROUTE) += udp_io.o + lib-$(CONFIG_LOSETUP) += loop.o lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o @@ -137,7 +143,7 @@ lib-$(CONFIG_ADDUSER) += update_passwd.o lib-$(CONFIG_DELGROUP) += update_passwd.o lib-$(CONFIG_DELUSER) += update_passwd.o -lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o +lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o lib-$(CONFIG_CRYPTPW) += pw_encrypt.o lib-$(CONFIG_SULOGIN) += pw_encrypt.o @@ -160,6 +166,13 @@ lib-$(CONFIG_IOSTAT) += get_cpu_count.o lib-$(CONFIG_MPSTAT) += get_cpu_count.o lib-$(CONFIG_POWERTOP) += get_cpu_count.o +lib-$(CONFIG_PING) += inet_cksum.o +lib-$(CONFIG_TRACEROUTE) += inet_cksum.o +lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o +lib-$(CONFIG_UDHCPC) += inet_cksum.o +lib-$(CONFIG_UDHCPC6) += inet_cksum.o +lib-$(CONFIG_UDHCPD) += inet_cksum.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. diff --git a/release/src/router/busybox/libbb/appletlib.c b/release/src/router/busybox/libbb/appletlib.c index c417a270d3..73f71f1d02 100644 --- a/release/src/router/busybox/libbb/appletlib.c +++ b/release/src/router/busybox/libbb/appletlib.c @@ -27,14 +27,11 @@ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( */ #include "busybox.h" -#include -#include -/* Try to pull in PAGE_SIZE */ -#ifdef __linux__ -# include -#endif -#ifdef __GNU__ /* Hurd */ -# include + +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for mallopt */ #endif @@ -43,7 +40,6 @@ #include "applets.h" #undef PROTOTYPES - /* Include generated applet names, pointers to _main, etc */ #include "applet_tables.h" /* ...and if applet_tables generator says we have only one applet... */ @@ -54,9 +50,9 @@ # define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__ #endif - #include "usage_compressed.h" + #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else @@ -66,7 +62,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #if ENABLE_FEATURE_COMPRESS_USAGE static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; -# include "archive.h" +# include "bb_archive.h" static const char *unpack_usage_messages(void) { char *outbuf = NULL; @@ -227,15 +223,14 @@ bool re_execed; IF_FEATURE_SUID(static uid_t ruid;) /* real uid */ -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG -/* applets[] is const, so we have to define this "override" structure */ -static struct BB_suid_config { +static struct suid_config_t { + /* next ptr must be first: this struct needs to be llist-compatible */ + struct suid_config_t *m_next; + struct bb_uidgid_t m_ugid; 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; @@ -244,13 +239,10 @@ static bool suid_cfg_readable; 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; } @@ -258,9 +250,7 @@ static int ingroup(uid_t u, gid_t g) return 0; } -/* This should probably be a libbb routine. In that case, - * I'd probably rename it to something like bb_trimmed_slice. - */ +/* libbb candidate */ static char *get_trimmed_slice(char *s, char *e) { /* First, consider the value at e to be nul and back up until we @@ -278,38 +268,19 @@ static char *get_trimmed_slice(char *s, char *e) 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; + /* Don't depend on the tools to combine strings. */ + static const char config_file[] ALIGN1 = "/etc/busybox.conf"; + + struct suid_config_t *sct_head; 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; @@ -318,7 +289,7 @@ static void parse_config_file(void) || !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_for_read(config_file)) /* Cannot open? */ + || !(f = fopen_for_read(config_file)) /* Cannot open? */ ) { return; } @@ -328,18 +299,21 @@ static void parse_config_file(void) 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"); - } + char buffer[256]; + char *s; + + if (!fgets(buffer, sizeof(buffer), f)) { /* Are we done? */ + // Looks like bloat + //if (ferror(f)) { /* Make sure it wasn't a read error. */ + // errmsg = "reading"; + // goto pe_label; + //} fclose(f); suid_config = sct_head; /* Success, so set the pointer. */ return; } + s = buffer; lc++; /* Got a (partial) line. */ /* If a line is too long for our buffer, we consider it an error. @@ -351,7 +325,8 @@ static void parse_config_file(void) * 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"); + errmsg = "line too long"; + goto pe_label; } /* Trim leading and trailing whitespace, ignoring comments, and @@ -367,12 +342,13 @@ static void parse_config_file(void) /* 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, ']'); + char *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"); + errmsg = "section header"; + goto pe_label; } /* Right now we only have one section so just check it. * If more sections are added in the future, please don't @@ -397,12 +373,13 @@ static void parse_config_file(void) * where both key and value could contain inner whitespace. */ /* First get the key (an applet name in our case). */ - e = strchr(s, '='); + char *e = strchr(s, '='); if (e) { s = get_trimmed_slice(s, e); } if (!e || !*s) { /* Missing '=' or empty key. */ - parse_error("keyword"); + errmsg = "keyword"; + goto pe_label; } /* Ok, we have an applet name. Process the rhs if this @@ -411,13 +388,16 @@ static void parse_config_file(void) * up when the busybox configuration is changed. */ applet_no = find_applet_by_name(s); if (applet_no >= 0) { + unsigned i; + struct suid_config_t *sct; + /* 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 = xzalloc(sizeof(*sct)); sct->m_applet = applet_no; - sct->m_mode = 0; + /*sct->m_mode = 0;*/ sct->m_next = sct_head; sct_head = sct; @@ -426,48 +406,41 @@ static void parse_config_file(void) 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"); + /* There are 4 chars for each of user/group/other. + * "x-xx" instead of "x-" are to make + * "idx > 3" check catch invalid chars. + */ + static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx"; + static const unsigned short mode_mask[] ALIGN2 = { + S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* Ssx- */ + S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* Ssx- */ + S_IXOTH, 0 /* x- */ + }; + const char *q = strchrnul(mode_chars + 4*i, *e); + unsigned idx = q - (mode_chars + 4*i); + if (idx > 3) { + errmsg = "mode"; + goto pe_label; } - /* Adjust by -i to account for nul. */ - sct->m_mode |= mode_mask[(q - mode_chars) - i]; + sct->m_mode |= mode_mask[q - mode_chars]; + e++; } - /* Now get the the user/group info. */ + /* Now get 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("."); - } - *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"); + /* Default is 0.0, else parse USER.GROUP: */ + if (*s) { + /* We require whitespace between mode and USER.GROUP */ + if ((s == e) || !(e = strchr(s, '.'))) { + errmsg = "uid.gid"; + goto pe_label; } - 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"); + *e = ':'; /* get_uidgid needs USER:GROUP syntax */ + if (get_uidgid(&sct->m_ugid, s, /*allow_numeric:*/ 1) == 0) { + errmsg = "unknown user/group"; + goto pe_label; } - sct->m_gid = grp->gr_gid; } } continue; @@ -481,32 +454,28 @@ static void parse_config_file(void) * 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"); + errmsg = "keyword outside section"; + goto pe_label; } } /* while (1) */ pe_label: - fprintf(stderr, "Parse error in %s, line %d: %s\n", - config_file, lc, errmsg); - fclose(f); + bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg); + /* Release any allocated memory before returning. */ - while (sct_head) { - sct = sct_head->m_next; - free(sct_head); - sct_head = sct; - } + llist_free((llist_t*)sct_head, NULL); } -#else +# else static inline void parse_config_file(void) { IF_FEATURE_SUID(ruid = getuid();) } -#endif /* FEATURE_SUID_CONFIG */ +# endif /* FEATURE_SUID_CONFIG */ -#if ENABLE_FEATURE_SUID +# if ENABLE_FEATURE_SUID static void check_suid(int applet_no) { gid_t rgid; /* real gid */ @@ -515,10 +484,10 @@ static void check_suid(int applet_no) return; /* run by root - no need to check more */ rgid = getgid(); -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG if (suid_cfg_readable) { uid_t uid; - struct BB_suid_config *sct; + struct suid_config_t *sct; mode_t m; for (sct = suid_config; sct; sct = sct->m_next) { @@ -527,78 +496,85 @@ static void check_suid(int applet_no) } goto check_need_suid; found: + /* Is this user allowed to run this applet? */ m = sct->m_mode; - if (sct->m_uid == ruid) + if (sct->m_ugid.uid == ruid) /* same uid */ m >>= 6; - else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid)) + else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.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 */ + if (!(m & S_IXOTH)) /* is x bit not set? */ + bb_error_msg_and_die("you have no permission to run this applet"); /* We set effective AND saved ids. If saved-id is not set - * like we do below, seteiud(0) can still later succeed! */ + * like we do below, seteuid(0) can still later succeed! */ + + /* Are we directed to change gid + * (APPLET = *s* USER.GROUP or APPLET = *S* USER.GROUP)? + */ + if (sct->m_mode & S_ISGID) + rgid = sct->m_ugid.gid; + /* else: we will set egid = rgid, thus dropping sgid effect */ if (setresgid(-1, rgid, rgid)) bb_perror_msg_and_die("setresgid"); - /* do we have to set effective uid? */ + /* Are we directed to change uid + * (APPLET = s** USER.GROUP or APPLET = S** USER.GROUP)? + */ uid = ruid; if (sct->m_mode & S_ISUID) - uid = sct->m_uid; - /* else (no seteuid) we will set euid = ruid */ - + uid = sct->m_ugid.uid; + /* else: we will set euid = ruid, thus dropping suid effect */ if (setresuid(-1, uid, uid)) bb_perror_msg_and_die("setresuid"); - return; + + goto ret; } -#if !ENABLE_FEATURE_SUID_CONFIG_QUIET +# if !ENABLE_FEATURE_SUID_CONFIG_QUIET { static bool onetime = 0; if (!onetime) { onetime = 1; - fprintf(stderr, "Using fallback suid method\n"); + bb_error_msg("using fallback suid method"); } } -#endif +# endif check_need_suid: -#endif - if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) { +# endif + if (APPLET_SUID(applet_no) == BB_SUID_REQUIRE) { /* 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_DROP) { + } else if (APPLET_SUID(applet_no) == BB_SUID_DROP) { xsetgid(rgid); /* drop all privileges */ xsetuid(ruid); } +# if ENABLE_FEATURE_SUID_CONFIG + ret: ; + llist_free((llist_t*)suid_config, NULL); +# endif } -#else -#define check_suid(x) ((void)0) -#endif /* FEATURE_SUID */ +# else +# define check_suid(x) ((void)0) +# endif /* FEATURE_SUID */ -#if ENABLE_FEATURE_INSTALLER +# if ENABLE_FEATURE_INSTALLER 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], /* "/" */ &usr_bin [4], /* "/bin/" */ &usr_sbin[4] /* "/sbin/" */ -# if !ENABLE_INSTALL_NO_USR +# if !ENABLE_INSTALL_NO_USR ,usr_bin ,usr_sbin -# endif +# endif }; - /* create (sym)links for each applet */ static void install_links(const char *busybox, int use_symbolic_links, char *custom_install_dir) @@ -628,9 +604,9 @@ static void install_links(const char *busybox, int use_symbolic_links, free(fpc); } } -#else -# define install_links(x,y,z) ((void)0) -#endif +# else +# define install_links(x,y,z) ((void)0) +# endif /* If we were called as "busybox..." */ static int busybox_main(char **argv) @@ -651,12 +627,15 @@ static int busybox_main(char **argv) full_write2_str(bb_banner); /* reuse const string */ full_write2_str(" multi-call binary.\n"); /* reuse */ full_write2_str( - "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" + "Copyright (C) 1998-2011 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: busybox --list[-full]\n" + " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" + IF_FEATURE_INSTALLER( + " or: busybox --install [-s] [DIR]\n" + ) " or: function [arguments]...\n" "\n" "\tBusyBox is a multi-call binary that combines many common Unix\n" @@ -695,10 +674,10 @@ static int busybox_main(char **argv) const char *a = applet_names; dup2(1, 2); while (*a) { -#if ENABLE_FEATURE_INSTALLER - if (argv[1][6]) /* --list-path? */ +# if ENABLE_FEATURE_INSTALLER + if (argv[1][6]) /* --list-full? */ full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); -#endif +# endif full_write2_str(a); full_write2_str("\n"); i++; @@ -710,13 +689,23 @@ static int busybox_main(char **argv) if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { int use_symbolic_links; const char *busybox; + busybox = xmalloc_readlink(bb_busybox_exec_path); - if (!busybox) - busybox = bb_busybox_exec_path; - /* busybox --install [-s] [DIR]: */ - /* -s: make symlinks */ - /* DIR: directory to install links to */ - use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++); + if (!busybox) { + /* bb_busybox_exec_path is usually "/proc/self/exe". + * In chroot, readlink("/proc/self/exe") usually fails. + * In such case, better use argv[0] as symlink target + * if it is a full path name. + */ + if (argv[0][0] != '/') + bb_error_msg_and_die("'%s' is not an absolute path", argv[0]); + busybox = argv[0]; + } + /* busybox --install [-s] [DIR]: + * -s: make symlinks + * DIR: directory to install links to + */ + use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); install_links(busybox, use_symbolic_links, argv[2]); return 0; } @@ -771,7 +760,7 @@ void FAST_FUNC 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)) + if (strncmp(name, "busybox", 7) == 0) exit(busybox_main(argv)); } @@ -786,31 +775,20 @@ int main(int argc UNUSED_PARAM, char **argv) #endif { /* Tweak malloc for reduced memory consumption */ -#ifndef PAGE_SIZE -# define PAGE_SIZE (4*1024) /* guess */ -#endif #ifdef M_TRIM_THRESHOLD /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory * to keep before releasing to the OS * Default is way too big: 256k */ - mallopt(M_TRIM_THRESHOLD, 2 * PAGE_SIZE); + mallopt(M_TRIM_THRESHOLD, 8 * 1024); #endif #ifdef M_MMAP_THRESHOLD /* M_MMAP_THRESHOLD is the request size threshold for using mmap() * Default is too big: 256k */ - mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256); + mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256); #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 IF_FEATURE_INDIVIDUAL(, argv)); - return SINGLE_APPLET_MAIN(argc, argv); -#else - lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); - #if !BB_MMU /* NOMMU re-exec trick sets high-order bit in first byte of name */ if (argv[0][0] & 0x80) { @@ -818,6 +796,19 @@ int main(int argc UNUSED_PARAM, char **argv) argv[0][0] &= 0x7f; } #endif + +#if defined(SINGLE_APPLET_MAIN) + /* Only one applet is selected in .config */ + if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { + /* "busybox " should still work as expected */ + argv++; + } + /* applet_names in this case is just "applet\0\0" */ + lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); + return SINGLE_APPLET_MAIN(argc, argv); +#else + lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); + applet_name = argv[0]; if (applet_name[0] == '-') applet_name++; diff --git a/release/src/router/busybox/libbb/bb_askpass.c b/release/src/router/busybox/libbb/bb_askpass.c index 9a4188f52f..fe2b50677f 100644 --- a/release/src/router/busybox/libbb/bb_askpass.c +++ b/release/src/router/busybox/libbb/bb_askpass.c @@ -30,14 +30,23 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) struct sigaction sa, oldsa; struct termios tio, oldtio; - tcgetattr(fd, &oldtio); + fputs(prompt, stdout); + fflush_all(); tcflush(fd, TCIFLUSH); + + tcgetattr(fd, &oldtio); tio = oldtio; -#ifndef IUCLC -# define IUCLC 0 -#endif +#if 0 + /* Switch off UPPERCASE->lowercase conversion (never used since 198x) + * and XON/XOFF (why we want to mess with this??) + */ +# ifndef IUCLC +# define IUCLC 0 +# endif tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); - tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); +#endif + /* Switch off echo */ + tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL); tcsetattr(fd, TCSANOW, &tio); memset(&sa, 0, sizeof(sa)); @@ -50,9 +59,6 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) alarm(timeout); } - fputs(prompt, stdout); - fflush_all(); - if (!passwd) passwd = xmalloc(sizeof_passwd); ret = passwd; diff --git a/release/src/router/busybox/libbb/bb_pwd.c b/release/src/router/busybox/libbb/bb_pwd.c index 32406cb58e..4829b723a0 100644 --- a/release/src/router/busybox/libbb/bb_pwd.c +++ b/release/src/router/busybox/libbb/bb_pwd.c @@ -72,13 +72,13 @@ char* FAST_FUNC gid2group(gid_t gid) return (gr) ? gr->gr_name : NULL; } -char* FAST_FUNC uid2uname_utoa(long uid) +char* FAST_FUNC uid2uname_utoa(uid_t uid) { char *name = uid2uname(uid); return (name) ? name : utoa(uid); } -char* FAST_FUNC gid2group_utoa(long gid) +char* FAST_FUNC gid2group_utoa(gid_t gid) { char *name = gid2group(gid); return (name) ? name : utoa(gid); diff --git a/release/src/router/busybox/libbb/bb_strtonum.c b/release/src/router/busybox/libbb/bb_strtonum.c index e08eac6b7b..c92cc1c04a 100644 --- a/release/src/router/busybox/libbb/bb_strtonum.c +++ b/release/src/router/busybox/libbb/bb_strtonum.c @@ -36,14 +36,14 @@ static unsigned long long ret_ERANGE(void) return ULLONG_MAX; } -static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) +static unsigned long long handle_errors(unsigned long long v, char **endp) { - if (endp) *endp = endptr; + char next_ch = **endp; /* errno is already set to ERANGE by strtoXXX if value overflowed */ - if (endptr[0]) { + if (next_ch) { /* "1234abcg" or out-of-range? */ - if (isalnum(endptr[0]) || errno) + if (isalnum(next_ch) || errno) return ret_ERANGE(); /* good number, just suspicious terminator */ errno = EINVAL; @@ -57,6 +57,9 @@ unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base) unsigned long long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ /* I don't think that this is right. Preventing this... */ //if (!isalnum(arg[0])) return ret_ERANGE(); @@ -65,24 +68,28 @@ unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base) /* not 100% correct for lib func, but convenient for the caller */ errno = 0; - v = strtoull(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoull(arg, endp, base); + return handle_errors(v, endp); } long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) { unsigned long long v; char *endptr; + char first; + + if (!endp) endp = &endptr; + *endp = (char*) arg; /* Check for the weird "feature": * a "-" string is apparently a valid "number" for strto[u]l[l]! * It returns zero and errno is 0! :( */ - char first = (arg[0] != '-' ? arg[0] : arg[1]); + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtoll(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoll(arg, endp, base); + return handle_errors(v, endp); } #if ULONG_MAX != ULLONG_MAX @@ -91,25 +98,31 @@ unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base) unsigned long v; char *endptr; - char first = (arg[0] != '-' ? arg[0] : arg[1]); - if (!isalnum(first)) return ret_ERANGE(); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoul(arg, endp, base); + return handle_errors(v, endp); } long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) { long v; char *endptr; + char first; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtol(arg, endp, base); + return handle_errors(v, endp); } #endif @@ -119,27 +132,33 @@ unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base) unsigned long v; char *endptr; - char first = (arg[0] != '-' ? arg[0] : arg[1]); - if (!isalnum(first)) return ret_ERANGE(); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); + v = strtoul(arg, endp, base); if (v > UINT_MAX) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) { long v; char *endptr; + char first; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); + v = strtol(arg, endp, base); if (v > INT_MAX) return ret_ERANGE(); if (v < INT_MIN) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } #endif diff --git a/release/src/router/busybox/libbb/copy_file.c b/release/src/router/busybox/libbb/copy_file.c index 57d9dbfdb4..9333a8d499 100644 --- a/release/src/router/busybox/libbb/copy_file.c +++ b/release/src/router/busybox/libbb/copy_file.c @@ -78,9 +78,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* 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; + smallint retval = 0; + smallint dest_exists = 0; + smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) @@ -147,7 +147,6 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) return -1; } - /* Create DEST */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); @@ -156,6 +155,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { + /* Create DEST */ mode_t mode; saved_umask = umask(0); diff --git a/release/src/router/busybox/libbb/crc32.c b/release/src/router/busybox/libbb/crc32.c index c63bf07720..ac9836cc9e 100644 --- a/release/src/router/busybox/libbb/crc32.c +++ b/release/src/router/busybox/libbb/crc32.c @@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l const void *end = (uint8_t*)buf + len; while (buf != end) { - val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); buf = (uint8_t*)buf + 1; } return val; diff --git a/release/src/router/busybox/libbb/die_if_bad_username.c b/release/src/router/busybox/libbb/die_if_bad_username.c index 9946e3a1d8..cf1297bd6a 100644 --- a/release/src/router/busybox/libbb/die_if_bad_username.c +++ b/release/src/router/busybox/libbb/die_if_bad_username.c @@ -18,23 +18,45 @@ void FAST_FUNC die_if_bad_username(const char *name) { - /* 1st char being dash or dot isn't valid: */ - goto skip; - /* For example, name like ".." can make adduser - * chown "/home/.." recursively - NOT GOOD + const char *start = name; + + /* 1st char being dash or dot isn't valid: + * for example, name like ".." can make adduser + * chown "/home/.." recursively - NOT GOOD. + * Name of just a single "$" is also rejected. */ + goto skip; do { - if (*name == '-' || *name == '.') + unsigned char ch; + + /* These chars are valid unless they are at the 1st pos: */ + if (*name == '-' + || *name == '.' + /* $ is allowed if it's the last char: */ + || (*name == '$' && !name[1]) + ) { continue; + } skip: - if (isalnum(*name) - || *name == '_' - || *name == '@' - || (*name == '$' && !name[1]) + ch = *name; + if (ch == '_' + /* || ch == '@' -- we disallow this too. Think about "user@host" */ + /* open-coded isalnum: */ + || (ch >= '0' && ch <= '9') + || ((ch|0x20) >= 'a' && (ch|0x20) <= 'z') ) { continue; } - bb_error_msg_and_die("illegal character '%c'", *name); + bb_error_msg_and_die("illegal character with code %u at position %u", + (unsigned)ch, (unsigned)(name - start)); } while (*++name); + + /* The minimum size of the login name is one char or two if + * last char is the '$'. Violations of this are caught above. + * The maximum size of the login name is LOGIN_NAME_MAX + * including the terminating null byte. + */ + if (name - start >= LOGIN_NAME_MAX) + bb_error_msg_and_die("name is too long"); } diff --git a/release/src/router/busybox/libbb/dump.c b/release/src/router/busybox/libbb/dump.c index 1b1d03a661..7e435643bd 100644 --- a/release/src/router/busybox/libbb/dump.c +++ b/release/src/router/busybox/libbb/dump.c @@ -71,7 +71,8 @@ static NOINLINE int bb_dump_size(FS *fs) * skip any special chars -- save precision in * case it's a %s format. */ - while (strchr(index_str + 1, *++fmt)); + while (strchr(index_str + 1, *++fmt)) + continue; if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); while (isdigit(*++fmt)) @@ -99,8 +100,8 @@ static NOINLINE int bb_dump_size(FS *fs) static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; - PR *pr, **nextpr = NULL; FU *fu; + PR *pr; char *p1, *p2, *p3; char savech, *fmtp; const char *byte_count_str; @@ -111,15 +112,12 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * break each format unit into print units; each * conversion character gets its own. */ - for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + for (nconv = 0, fmtp = fu->fmt; *fmtp; ) { /* 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. - */ /* skip preceding text and up to the next % sign */ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) @@ -295,16 +293,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * interprets any data at all, and has no iteration count, * repeat it as necessary. * - * if, rep count is greater than 1, no trailing whitespace + * 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 = fu->nextfu) { - if (!fu->nextfu && fs->bcnt < dumper->blocksize - && !(fu->flags & F_SETREP) && fu->bcnt + if (!fu->nextfu + && fs->bcnt < dumper->blocksize + && !(fu->flags & F_SETREP) + && fu->bcnt ) { fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; } - if (fu->reps > 1) { + if (fu->reps > 1 && fu->nextpr) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; @@ -724,7 +724,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) p = fmt; for (;;) { p = skip_whitespace(p); - if (!*p) { + if (*p == '\0') { break; } @@ -752,7 +752,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* skip slash and trailing white space */ if (*p == '/') { - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* byte count */ @@ -766,7 +766,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) } tfu->bcnt = atoi(savep); /* skip trailing white space */ - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* format */ @@ -774,7 +774,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) bb_error_msg_and_die("bad format {%s}", fmt); } for (savep = ++p; *p != '"';) { - if (*p++ == 0) { + if (*p++ == '\0') { bb_error_msg_and_die("bad format {%s}", fmt); } } @@ -785,7 +785,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* alphabetic escape sequences have to be done in place */ for (p2 = p1;; ++p1, ++p2) { - if (!*p1) { + if (*p1 == '\0') { *p2 = *p1; break; } diff --git a/release/src/router/busybox/libbb/execable.c b/release/src/router/busybox/libbb/execable.c index d376400077..178a00a5f1 100644 --- a/release/src/router/busybox/libbb/execable.c +++ b/release/src/router/busybox/libbb/execable.c @@ -68,12 +68,12 @@ int FAST_FUNC exists_execable(const char *filename) } #if ENABLE_FEATURE_PREFER_APPLETS -/* just like the real execvp, but try to launch an applet named 'file' first - */ -int FAST_FUNC bb_execvp(const char *file, char *const argv[]) +/* just like the real execvp, but try to launch an applet named 'file' first */ +int FAST_FUNC BB_EXECVP(const char *file, char *const argv[]) { - return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, - argv); + if (find_applet_by_name(file) >= 0) + execvp(bb_busybox_exec_path, argv); + return execvp(file, argv); } #endif diff --git a/release/src/router/busybox/libbb/find_mount_point.c b/release/src/router/busybox/libbb/find_mount_point.c index 361698a6bd..9676b5f52c 100644 --- a/release/src/router/busybox/libbb/find_mount_point.c +++ b/release/src/router/busybox/libbb/find_mount_point.c @@ -30,7 +30,8 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) devno_of_name = s.st_dev; block_dev = 0; - if (S_ISBLK(s.st_mode)) { + /* Why S_ISCHR? - UBI volumes use char devices, not block */ + if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) { devno_of_name = s.st_rdev; block_dev = 1; } @@ -43,7 +44,7 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) /* rootfs mount in Linux 2.6 exists always, * and it makes sense to always ignore it. * Otherwise people can't reference their "real" root! */ - if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0) continue; if (strcmp(name, mountEntry->mnt_dir) == 0 diff --git a/release/src/router/busybox/libbb/find_root_device.c b/release/src/router/busybox/libbb/find_root_device.c index 8436cd664f..32c86cea8e 100644 --- a/release/src/router/busybox/libbb/find_root_device.c +++ b/release/src/router/busybox/libbb/find_root_device.c @@ -29,15 +29,14 @@ static char *find_block_device_in_dir(struct arena *ap) char *retpath = NULL; int len, rem; - len = strlen(ap->devpath); - rem = DEVNAME_MAX-2 - len; - if (rem <= 0) - return NULL; - 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) { diff --git a/release/src/router/busybox/libbb/get_last_path_component.c b/release/src/router/busybox/libbb/get_last_path_component.c index 72598d22e6..04fdf2a3e5 100644 --- a/release/src/router/busybox/libbb/get_last_path_component.c +++ b/release/src/router/busybox/libbb/get_last_path_component.c @@ -6,8 +6,16 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "libbb.h" + +const char* FAST_FUNC bb_basename(const char *name) +{ + const char *cp = strrchr(name, '/'); + if (cp) + return cp + 1; + return name; +} + /* * "/" -> "/" * "abc" -> "abc" diff --git a/release/src/router/busybox/libbb/get_line_from_file.c b/release/src/router/busybox/libbb/get_line_from_file.c index a0ed9193fa..a98dd35eb2 100644 --- a/release/src/router/busybox/libbb/get_line_from_file.c +++ b/release/src/router/busybox/libbb/get_line_from_file.c @@ -11,38 +11,21 @@ #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 is stored in it. - * If lineno is not NULL, *lineno is incremented for each line, - * and also trailing '\' is recognized as line continuation. - * - * Returns NULL if EOF/error. */ -char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) +char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) { int ch; - int idx = 0; + unsigned idx = 0; char *linebuf = NULL; - int linebufsz = 0; while ((ch = getc(file)) != EOF) { /* grow the line buffer as necessary */ - if (idx >= linebufsz) { - linebufsz += 256; - linebuf = xrealloc(linebuf, linebufsz); - } + if (!(idx & 0xff)) + linebuf = xrealloc(linebuf, idx + 0x100); linebuf[idx++] = (char) ch; - if (!ch) + if (ch == '\0') + break; + if (end && ch == '\n') break; - if (end && ch == '\n') { - if (lineno == NULL) - break; - (*lineno)++; - if (idx < 2 || linebuf[idx-2] != '\\') - break; - idx -= 2; - } } if (end) *end = idx; @@ -59,11 +42,6 @@ char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno return linebuf; } -char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) -{ - return bb_get_chunk_with_continuation(file, end, NULL); -} - /* Get line, including trailing \n if any */ char* FAST_FUNC xmalloc_fgets(FILE *file) { diff --git a/release/src/router/busybox/libbb/get_shell_name.c b/release/src/router/busybox/libbb/get_shell_name.c new file mode 100644 index 0000000000..c930afd94e --- /dev/null +++ b/release/src/router/busybox/libbb/get_shell_name.c @@ -0,0 +1,25 @@ +/* + * Copyright 2011, Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += get_shell_name.o + +#include "libbb.h" + +const char *get_shell_name(void) +{ + struct passwd *pw; + char *shell; + + shell = getenv("SHELL"); + if (shell && shell[0]) + return shell; + + pw = getpwuid(getuid()); + if (pw && pw->pw_shell && pw->pw_shell[0]) + return pw->pw_shell; + + return DEFAULT_SHELL; +} diff --git a/release/src/router/busybox/libbb/getopt32.c b/release/src/router/busybox/libbb/getopt32.c index 25bae319eb..d0e83d88ee 100644 --- a/release/src/router/busybox/libbb/getopt32.c +++ b/release/src/router/busybox/libbb/getopt32.c @@ -7,7 +7,9 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#include +#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG +# include +#endif #include "libbb.h" /* Documentation @@ -80,9 +82,9 @@ 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" - ; + //"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 @@ -226,7 +228,7 @@ Special characters: 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. + bb_show_usage() and die. "x--x" Variation of the above, it means that -x option should occur at most once. @@ -465,13 +467,17 @@ getopt32(char **argv, const char *applet_opts, ...) } for (on_off = complementary; on_off->opt_char; on_off++) if (on_off->opt_char == *s) - break; + goto found_opt; + /* Without this, diagnostic of such bugs is not easy */ + bb_error_msg_and_die("NO OPT %c!", *s); + found_opt: if (c == ':' && s[2] == ':') { on_off->param_type = PARAM_LIST; continue; } if (c == '+' && (s[2] == ':' || s[2] == '\0')) { on_off->param_type = PARAM_INT; + s++; continue; } if (c == ':' || c == '\0') { @@ -531,7 +537,7 @@ getopt32(char **argv, const char *applet_opts, ...) /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. - * run_nofork_applet_prime() does this, but we might end up here + * run_nofork_applet() does this, but we might end up here * also via gunzip_main() -> gzip_main(). Play safe. */ #ifdef __GLIBC__ @@ -542,8 +548,6 @@ getopt32(char **argv, const char *applet_opts, ...) #endif /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - pargv = NULL; - /* Note: just "getopt() <= 0" will not work well for * "fake" short options, like this one: * wget $'-\203' "Test: test" http://kernel.org/ @@ -574,19 +578,16 @@ getopt32(char **argv, const char *applet_opts, ...) flags ^= trigger; if (on_off->counter) (*(on_off->counter))++; - if (on_off->param_type == PARAM_LIST) { - if (optarg) + if (optarg) { + if (on_off->param_type == PARAM_LIST) { llist_add_to_end((llist_t **)(on_off->optarg), optarg); - } else if (on_off->param_type == PARAM_INT) { - if (optarg) + } else if (on_off->param_type == PARAM_INT) { //TODO: xatoi_positive indirectly pulls in printf machinery *(unsigned*)(on_off->optarg) = xatoi_positive(optarg); - } else if (on_off->optarg) { - if (optarg) + } else if (on_off->optarg) { *(char **)(on_off->optarg) = optarg; + } } - if (pargv != NULL) - break; } /* check depending requires for given options */ diff --git a/release/src/router/busybox/libbb/getpty.c b/release/src/router/busybox/libbb/getpty.c index ea653b0b6c..435e4d09f3 100644 --- a/release/src/router/busybox/libbb/getpty.c +++ b/release/src/router/busybox/libbb/getpty.c @@ -19,20 +19,22 @@ int FAST_FUNC xgetpty(char *line) if (p > 0) { grantpt(p); /* chmod+chown corresponding slave pty */ unlockpt(p); /* (what does this do?) */ -#if 0 /* if ptsname_r is not available... */ - const char *name; - name = ptsname(p); /* find out the name of slave pty */ - if (!name) { - bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); +# ifndef HAVE_PTSNAME_R + { + const char *name; + name = ptsname(p); /* find out the name of slave pty */ + if (!name) { + bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); + } + safe_strncpy(line, name, GETPTY_BUFSIZE); } - safe_strncpy(line, name, GETPTY_BUFSIZE); -#else +# else /* find out the name of slave pty */ if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) { bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); } line[GETPTY_BUFSIZE-1] = '\0'; -#endif +# endif return p; } #else diff --git a/release/src/router/busybox/libbb/hash_md5_sha.c b/release/src/router/busybox/libbb/hash_md5_sha.c index b87d1dde8c..a313c2a65c 100644 --- a/release/src/router/busybox/libbb/hash_md5_sha.c +++ b/release/src/router/busybox/libbb/hash_md5_sha.c @@ -104,12 +104,12 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) */ /* 0: fastest, 3: smallest */ -#if CONFIG_MD5_SIZE_VS_SPEED < 0 -# define MD5_SIZE_VS_SPEED 0 -#elif CONFIG_MD5_SIZE_VS_SPEED > 3 -# define MD5_SIZE_VS_SPEED 3 +#if CONFIG_MD5_SMALL < 0 +# define MD5_SMALL 0 +#elif CONFIG_MD5_SMALL > 3 +# define MD5_SMALL 3 #else -# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED +# define MD5_SMALL CONFIG_MD5_SMALL #endif /* These are the four functions used in the four steps of the MD5 algorithm @@ -129,7 +129,7 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) /* Hash a single block, 64 bytes long and 4-byte aligned */ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) { -#if MD5_SIZE_VS_SPEED > 0 +#if MD5_SMALL > 0 /* 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 @@ -157,7 +157,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; static const char P_array[] ALIGN1 = { -# if MD5_SIZE_VS_SPEED > 1 +# if MD5_SMALL > 1 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ # endif 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ @@ -171,7 +171,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) uint32_t C = ctx->hash[2]; uint32_t D = ctx->hash[3]; -#if MD5_SIZE_VS_SPEED >= 2 /* 2 or 3 */ +#if MD5_SMALL >= 2 /* 2 or 3 */ static const char S_array[] ALIGN1 = { 7, 12, 17, 22, @@ -190,7 +190,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) words[i] = SWAP_LE32(words[i]); # endif -# if MD5_SIZE_VS_SPEED == 3 +# if MD5_SMALL == 3 pc = C_array; pp = P_array; ps = S_array - 4; @@ -220,7 +220,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) C = B; B = temp; } -# else /* MD5_SIZE_VS_SPEED == 2 */ +# else /* MD5_SMALL == 2 */ pc = C_array; pp = P_array; ps = S_array; @@ -271,13 +271,13 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) ctx->hash[2] += C; ctx->hash[3] += D; -#else /* MD5_SIZE_VS_SPEED == 0 or 1 */ +#else /* MD5_SMALL == 0 or 1 */ 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 +# if MD5_SMALL == 1 const uint32_t *pc; const char *pp; int i; @@ -299,7 +299,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) } while (0) /* Round 1 */ -# if MD5_SIZE_VS_SPEED == 1 +# if MD5_SMALL == 1 pc = C_array; for (i = 0; i < 4; i++) { OP(A, B, C, D, 7, *pc++); @@ -339,7 +339,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) } while (0) /* Round 2 */ -# if MD5_SIZE_VS_SPEED == 1 +# if MD5_SMALL == 1 pp = P_array; for (i = 0; i < 4; i++) { OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); @@ -367,7 +367,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) # endif /* Round 3 */ -# if MD5_SIZE_VS_SPEED == 1 +# if MD5_SMALL == 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++); @@ -394,7 +394,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) # endif /* Round 4 */ -# if MD5_SIZE_VS_SPEED == 1 +# if MD5_SMALL == 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++); diff --git a/release/src/router/busybox/libbb/hash_md5prime.c b/release/src/router/busybox/libbb/hash_md5prime.c index 7986f4d292..e089a15f5a 100644 --- a/release/src/router/busybox/libbb/hash_md5prime.c +++ b/release/src/router/busybox/libbb/hash_md5prime.c @@ -59,7 +59,7 @@ * Completely removed static PADDING array. * * Reintroduced the loop unrolling in md5_transform and added the - * MD5_SIZE_VS_SPEED option for configurability. Define below as: + * MD5_SMALL 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) @@ -75,12 +75,12 @@ #include "libbb.h" /* 1: fastest, 3: smallest */ -#if CONFIG_MD5_SIZE_VS_SPEED < 1 -# define MD5_SIZE_VS_SPEED 1 -#elif CONFIG_MD5_SIZE_VS_SPEED > 3 -# define MD5_SIZE_VS_SPEED 3 +#if CONFIG_MD5_SMALL < 1 +# define MD5_SMALL 1 +#elif CONFIG_MD5_SMALL > 3 +# define MD5_SMALL 3 #else -# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED +# define MD5_SMALL CONFIG_MD5_SMALL #endif #if BB_LITTLE_ENDIAN @@ -152,7 +152,7 @@ memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len) static void md5_transform(uint32_t state[4], const unsigned char block[64]) { uint32_t a, b, c, d, x[16]; -#if MD5_SIZE_VS_SPEED > 1 +#if MD5_SMALL > 1 uint32_t temp; const unsigned char *ps; @@ -162,9 +162,9 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) 4, 11, 16, 23, 6, 10, 15, 21 }; -#endif /* MD5_SIZE_VS_SPEED > 1 */ +#endif /* MD5_SMALL > 1 */ -#if MD5_SIZE_VS_SPEED > 0 +#if MD5_SMALL > 0 const uint32_t *pc; const unsigned char *pp; int i; @@ -198,7 +198,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ }; -#endif /* MD5_SIZE_VS_SPEED > 0 */ +#endif /* MD5_SMALL > 0 */ memcpy32_le2cpu(x, block, 64); @@ -207,7 +207,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) c = state[2]; d = state[3]; -#if MD5_SIZE_VS_SPEED > 2 +#if MD5_SMALL > 2 pc = C; pp = P; ps = S - 4; @@ -233,7 +233,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) temp += b; a = d; d = c; c = b; b = temp; } -#elif MD5_SIZE_VS_SPEED > 1 +#elif MD5_SMALL > 1 pc = C; pp = P; ps = S; @@ -260,7 +260,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) 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_VS_SPEED > 0 +#elif MD5_SMALL > 0 pc = C; pp = P; /* Round 1 */ diff --git a/release/src/router/busybox/libbb/inet_cksum.c b/release/src/router/busybox/libbb/inet_cksum.c new file mode 100644 index 0000000000..3d5dc3adf1 --- /dev/null +++ b/release/src/router/busybox/libbb/inet_cksum.c @@ -0,0 +1,36 @@ +/* + * Checksum routine for Internet Protocol family headers (C Version) + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" + +uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft) +{ + /* + * Our algorithm is simple, using a 32 bit accumulator, + * we add sequential 16 bit words to it, and at the end, fold + * back all the carry bits from the top 16 bits into the lower + * 16 bits. + */ + unsigned sum = 0; + while (nleft > 1) { + sum += *addr++; + nleft -= 2; + } + + /* Mop up an odd byte, if necessary */ + if (nleft == 1) { + if (BB_LITTLE_ENDIAN) + sum += *(uint8_t*)addr; + else + sum += *(uint8_t*)addr << 8; + } + + /* Add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + + return (uint16_t)~sum; +} diff --git a/release/src/router/busybox/libbb/inet_common.c b/release/src/router/busybox/libbb/inet_common.c index 6f585ebd90..7208db9ea9 100644 --- a/release/src/router/busybox/libbb/inet_common.c +++ b/release/src/router/busybox/libbb/inet_common.c @@ -164,18 +164,19 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) { - struct addrinfo req, *ai; + struct addrinfo req, *ai = NULL; int s; - memset(&req, '\0', sizeof req); + memset(&req, 0, sizeof(req)); req.ai_family = AF_INET6; s = getaddrinfo(name, NULL, &req, &ai); - if (s) { + if (s != 0) { bb_error_msg("getaddrinfo: %s: %d", name, s); return -1; } - memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6)); - freeaddrinfo(ai); + memcpy(sin6, ai->ai_addr, sizeof(*sin6)); + if (ai) + freeaddrinfo(ai); return 0; } @@ -209,9 +210,11 @@ char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) return xstrdup("*"); } - s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), - name, sizeof(name), NULL, 0, 0); - if (s) { + s = getnameinfo((struct sockaddr *) sin6, sizeof(*sin6), + name, sizeof(name), + /*serv,servlen:*/ NULL, 0, + 0); + if (s != 0) { bb_error_msg("getnameinfo failed"); return NULL; } diff --git a/release/src/router/busybox/libbb/isdirectory.c b/release/src/router/busybox/libbb/isdirectory.c index 9861be6f84..ba6c52ce8d 100644 --- a/release/src/router/busybox/libbb/isdirectory.c +++ b/release/src/router/busybox/libbb/isdirectory.c @@ -15,22 +15,17 @@ * Return TRUE if fileName is a directory. * Nonexistent files return FALSE. */ -int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) +int FAST_FUNC is_directory(const char *fileName, int followLinks) { int status; - struct stat astatBuf; - - if (statBuf == NULL) { - /* use auto stack buffer */ - statBuf = &astatBuf; - } + struct stat statBuf; if (followLinks) - status = stat(fileName, statBuf); + status = stat(fileName, &statBuf); else - status = lstat(fileName, statBuf); + status = lstat(fileName, &statBuf); - status = (status == 0 && S_ISDIR(statBuf->st_mode)); + status = (status == 0 && S_ISDIR(statBuf.st_mode)); return status; } diff --git a/release/src/router/busybox/libbb/lineedit.c b/release/src/router/busybox/libbb/lineedit.c index 5dd835ccad..b89748a1c6 100644 --- a/release/src/router/busybox/libbb/lineedit.c +++ b/release/src/router/busybox/libbb/lineedit.c @@ -41,6 +41,10 @@ */ #include "libbb.h" #include "unicode.h" +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE '\0' +#endif + #ifdef TEST # define ENABLE_FEATURE_EDITING 0 @@ -184,6 +188,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ } while (0) + static void deinit_S(void) { #if ENABLE_FEATURE_EDITING_FANCY_PROMPT @@ -202,67 +207,87 @@ static void deinit_S(void) #if ENABLE_UNICODE_SUPPORT -static size_t load_string(const char *src, int maxsize) +static size_t load_string(const char *src) { - ssize_t len = mbstowcs(command_ps, src, maxsize - 1); - if (len < 0) - len = 0; - command_ps[len] = BB_NUL; - return len; + if (unicode_status == UNICODE_ON) { + ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1); + if (len < 0) + len = 0; + command_ps[len] = BB_NUL; + return len; + } else { + unsigned i = 0; + while (src[i] && i < S.maxsize - 1) { + command_ps[i] = src[i]; + i++; + } + command_ps[i] = BB_NUL; + return i; + } } static unsigned save_string(char *dst, unsigned maxsize) { + if (unicode_status == UNICODE_ON) { # if !ENABLE_UNICODE_PRESERVE_BROKEN - ssize_t len = wcstombs(dst, command_ps, maxsize - 1); - if (len < 0) - len = 0; - dst[len] = '\0'; - return len; + ssize_t len = wcstombs(dst, command_ps, maxsize - 1); + if (len < 0) + len = 0; + dst[len] = '\0'; + return len; # else - unsigned dstpos = 0; - unsigned srcpos = 0; + unsigned dstpos = 0; + unsigned srcpos = 0; - maxsize--; - while (dstpos < maxsize) { - wchar_t wc; - int n = srcpos; + maxsize--; + while (dstpos < maxsize) { + wchar_t wc; + int n = srcpos; - /* Convert up to 1st invalid byte (or up to end) */ - while ((wc = command_ps[srcpos]) != BB_NUL - && !unicode_is_raw_byte(wc) - ) { + /* Convert up to 1st invalid byte (or up to end) */ + while ((wc = command_ps[srcpos]) != BB_NUL + && !unicode_is_raw_byte(wc) + ) { + srcpos++; + } + command_ps[srcpos] = BB_NUL; + n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); + if (n < 0) /* should not happen */ + break; + dstpos += n; + if (wc == BB_NUL) /* usually is */ + break; + + /* We do have invalid byte here! */ + command_ps[srcpos] = wc; /* restore it */ srcpos++; + if (dstpos == maxsize) + break; + dst[dstpos++] = (char) wc; } - command_ps[srcpos] = BB_NUL; - n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); - if (n < 0) /* should not happen */ - break; - dstpos += n; - if (wc == BB_NUL) /* usually is */ - break; - - /* We do have invalid byte here! */ - command_ps[srcpos] = wc; /* restore it */ - srcpos++; - if (dstpos == maxsize) - break; - dst[dstpos++] = (char) wc; - } - dst[dstpos] = '\0'; - return dstpos; + dst[dstpos] = '\0'; + return dstpos; # endif + } else { + unsigned i = 0; + while ((dst[i] = command_ps[i]) != 0) + i++; + return i; + } } /* I thought just fputwc(c, stdout) would work. But no... */ static void BB_PUTCHAR(wchar_t c) { - char buf[MB_CUR_MAX + 1]; - mbstate_t mbst = { 0 }; - ssize_t len; - - len = wcrtomb(buf, c, &mbst); - if (len > 0) { - buf[len] = '\0'; - fputs(buf, stdout); + if (unicode_status == UNICODE_ON) { + char buf[MB_CUR_MAX + 1]; + mbstate_t mbst = { 0 }; + ssize_t len = wcrtomb(buf, c, &mbst); + if (len > 0) { + buf[len] = '\0'; + fputs(buf, stdout); + } + } else { + /* In this case, c is always one byte */ + putchar(c); } } # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS @@ -297,9 +322,9 @@ static wchar_t adjust_width_and_validate_wc(wchar_t wc) return wc; } #else /* !UNICODE */ -static size_t load_string(const char *src, int maxsize) +static size_t load_string(const char *src) { - safe_strncpy(command_ps, src, maxsize); + safe_strncpy(command_ps, src, S.maxsize); return strlen(command_ps); } # if ENABLE_FEATURE_TAB_COMPLETION @@ -1202,10 +1227,10 @@ static NOINLINE void input_tab(smallint *lastWasTab) strcpy(match_buf, &command[cursor_mb]); /* where do we want to have cursor after all? */ strcpy(&command[cursor_mb], chosen_match + match_pfx_len); - len = load_string(command, S.maxsize); + len = load_string(command); /* add match and tail */ sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); - command_len = load_string(command, S.maxsize); + command_len = load_string(command); /* write out the matched command */ /* paranoia: load_string can return 0 on conv error, * prevent passing pos = (0 - 12) to redraw */ @@ -1226,12 +1251,26 @@ line_input_t* FAST_FUNC new_line_input_t(int flags) { line_input_t *n = xzalloc(sizeof(*n)); n->flags = flags; + n->max_history = MAX_HISTORY; return n; } #if MAX_HISTORY > 0 +unsigned size_from_HISTFILESIZE(const char *hp) +{ + int size = MAX_HISTORY; + if (hp) { + size = atoi(hp); + if (size <= 0) + return 1; + if (size > MAX_HISTORY) + return MAX_HISTORY; + } + return size; +} + static void save_command_ps_at_cur_history(void) { if (command_ps[0] != BB_NUL) { @@ -1312,7 +1351,8 @@ static void load_history(line_input_t *st_parm) /* fill temp_h[], retaining only last MAX_HISTORY lines */ memset(temp_h, 0, sizeof(temp_h)); - st_parm->cnt_history_in_file = idx = 0; + idx = 0; + st_parm->cnt_history_in_file = 0; while ((line = xmalloc_fgetline(fp)) != NULL) { if (line[0] == '\0') { free(line); @@ -1322,7 +1362,7 @@ static void load_history(line_input_t *st_parm) temp_h[idx] = line; st_parm->cnt_history_in_file++; idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; } fclose(fp); @@ -1331,18 +1371,18 @@ static void load_history(line_input_t *st_parm) if (st_parm->cnt_history_in_file) { while (temp_h[idx] == NULL) { idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; } } /* copy temp_h[] to st_parm->history[] */ - for (i = 0; i < MAX_HISTORY;) { + for (i = 0; i < st_parm->max_history;) { line = temp_h[idx]; if (!line) break; idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; line_len = strlen(line); if (line_len >= MAX_LINELEN) @@ -1350,15 +1390,62 @@ static void load_history(line_input_t *st_parm) st_parm->history[i++] = line; } st_parm->cnt_history = i; + if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) + st_parm->cnt_history_in_file = i; } } -/* state->flags is already checked to be nonzero */ +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +void save_history(line_input_t *st) +{ + FILE *fp; + + if (!st->hist_file) + return; + if (st->cnt_history <= st->cnt_history_in_file) + return; + + fp = fopen(st->hist_file, "a"); + if (fp) { + int i, fd; + char *new_name; + line_input_t *st_temp; + + for (i = st->cnt_history_in_file; i < st->cnt_history; i++) + fprintf(fp, "%s\n", st->history[i]); + fclose(fp); + + /* we may have concurrently written entries from others. + * load them */ + st_temp = new_line_input_t(st->flags); + st_temp->hist_file = st->hist_file; + st_temp->max_history = st->max_history; + load_history(st_temp); + + /* write out temp file and replace hist_file atomically */ + new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid()); + fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd >= 0) { + fp = xfdopen_for_write(fd); + for (i = 0; i < st_temp->cnt_history; i++) + fprintf(fp, "%s\n", st_temp->history[i]); + fclose(fp); + if (rename(new_name, st->hist_file) == 0) + st->cnt_history_in_file = st_temp->cnt_history; + } + free(new_name); + free_line_input_t(st_temp); + } +} +# else static void save_history(char *str) { int fd; int len, len2; + if (!state->hist_file) + return; + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); if (fd < 0) return; @@ -1373,7 +1460,7 @@ static void save_history(char *str) /* did we write so much that history file needs trimming? */ state->cnt_history_in_file++; - if (state->cnt_history_in_file > MAX_HISTORY * 4) { + if (state->cnt_history_in_file > state->max_history * 4) { char *new_name; line_input_t *st_temp; @@ -1381,11 +1468,12 @@ static void save_history(char *str) * load them */ st_temp = new_line_input_t(state->flags); st_temp->hist_file = state->hist_file; + st_temp->max_history = state->max_history; load_history(st_temp); /* write out temp file and replace hist_file atomically */ new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); - fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd >= 0) { FILE *fp; int i; @@ -1401,6 +1489,7 @@ static void save_history(char *str) free_line_input_t(st_temp); } } +# endif # else # define load_history(a) ((void)0) # define save_history(a) ((void)0) @@ -1419,25 +1508,28 @@ static void remember_in_history(char *str) if (i && strcmp(state->history[i-1], str) == 0) return; - free(state->history[MAX_HISTORY]); /* redundant, paranoia */ - state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */ + free(state->history[state->max_history]); /* redundant, paranoia */ + state->history[state->max_history] = NULL; /* redundant, paranoia */ /* If history[] is full, remove the oldest command */ - /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */ - if (i >= MAX_HISTORY) { + /* we need to keep history[state->max_history] empty, hence >=, not > */ + if (i >= state->max_history) { free(state->history[0]); - for (i = 0; i < MAX_HISTORY-1; i++) + for (i = 0; i < state->max_history-1; i++) state->history[i] = state->history[i+1]; - /* i == MAX_HISTORY-1 */ + /* i == state->max_history-1 */ +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + if (state->cnt_history_in_file) + state->cnt_history_in_file--; +# endif } - /* i <= MAX_HISTORY-1 */ + /* i <= state->max_history-1 */ state->history[i++] = xstrdup(str); - /* i <= MAX_HISTORY */ + /* i <= state->max_history */ state->cur_history = i; state->cnt_history = i; -# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY - if ((state->flags & SAVE_HISTORY) && state->hist_file) - save_history(str); +# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(str); # endif IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) } @@ -1644,7 +1736,7 @@ static void ask_terminal(void) * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! - * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) + * poll([{fd=0, events=POLLIN}], 1, -1) = 1 ([{fd=0, revents=POLLIN}]) * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first */ struct pollfd pfd; @@ -1802,17 +1894,17 @@ static void win_changed(int nsig) { int sv_errno = errno; 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 */ +//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!) + cmdedit_setwidth(width, /*redraw_flg:*/ nsig); + errno = sv_errno; } -static int lineedit_read_key(char *read_key_buffer) +static int lineedit_read_key(char *read_key_buffer, int timeout) { int64_t ic; - int timeout = -1; #if ENABLE_UNICODE_SUPPORT char unicode_buf[MB_CUR_MAX + 1]; int unicode_idx = 0; @@ -1911,13 +2003,147 @@ static int isrtl_str(void) #undef CTRL #define CTRL(a) ((a) & ~0x40) +enum { + VI_CMDMODE_BIT = 0x40000000, + /* 0x80000000 bit flags KEYCODE_xxx */ +}; + +#if ENABLE_FEATURE_REVERSE_SEARCH +/* Mimic readline Ctrl-R reverse history search. + * When invoked, it shows the following prompt: + * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R] + * and typing results in search being performed: + * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp] + * Search is performed by looking at progressively older lines in history. + * Ctrl-R again searches for the next match in history. + * Backspace deletes last matched char. + * Control keys exit search and return to normal editing (at current history line). + */ +static int32_t reverse_i_search(void) +{ + char match_buf[128]; /* for user input */ + char read_key_buffer[KEYCODE_BUFFER_SIZE]; + const char *matched_history_line; + const char *saved_prompt; + int32_t ic; + + matched_history_line = NULL; + read_key_buffer[0] = 0; + match_buf[0] = '\0'; + + /* Save and replace the prompt */ + saved_prompt = cmdedit_prompt; + goto set_prompt; + + while (1) { + int h; + unsigned match_buf_len = strlen(match_buf); + + fflush_all(); +//FIXME: correct timeout? + ic = lineedit_read_key(read_key_buffer, -1); + + switch (ic) { + case CTRL('R'): /* searching for the next match */ + break; + + case '\b': + case '\x7f': + /* Backspace */ + if (unicode_status == UNICODE_ON) { + while (match_buf_len != 0) { + uint8_t c = match_buf[--match_buf_len]; + if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */ + break; /* yes */ + } + } else { + if (match_buf_len != 0) + match_buf_len--; + } + match_buf[match_buf_len] = '\0'; + break; + + default: + if (ic < ' ' + || (!ENABLE_UNICODE_SUPPORT && ic >= 256) + || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT) + ) { + goto ret; + } + + /* Append this char */ +#if ENABLE_UNICODE_SUPPORT + if (unicode_status == UNICODE_ON) { + mbstate_t mbstate = { 0 }; + char buf[MB_CUR_MAX + 1]; + int len = wcrtomb(buf, ic, &mbstate); + if (len > 0) { + buf[len] = '\0'; + if (match_buf_len + len < sizeof(match_buf)) + strcpy(match_buf + match_buf_len, buf); + } + } else +#endif + if (match_buf_len < sizeof(match_buf) - 1) { + match_buf[match_buf_len] = ic; + match_buf[match_buf_len + 1] = '\0'; + } + break; + } /* switch (ic) */ + + /* Search in history for match_buf */ + h = state->cur_history; + if (ic == CTRL('R')) + h--; + while (h >= 0) { + if (state->history[h]) { + char *match = strstr(state->history[h], match_buf); + if (match) { + state->cur_history = h; + matched_history_line = state->history[h]; + command_len = load_string(matched_history_line); + cursor = match - matched_history_line; +//FIXME: cursor position for Unicode case + + free((char*)cmdedit_prompt); + set_prompt: + cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf); + cmdedit_prmt_len = strlen(cmdedit_prompt); + goto do_redraw; + } + } + h--; + } + + /* Not found */ + match_buf[match_buf_len] = '\0'; + beep(); + continue; + + do_redraw: + redraw(cmdedit_y, command_len - cursor); + } /* while (1) */ + + ret: + if (matched_history_line) + command_len = load_string(matched_history_line); + + free((char*)cmdedit_prompt); + cmdedit_prompt = saved_prompt; + cmdedit_prmt_len = strlen(cmdedit_prompt); + redraw(cmdedit_y, command_len - cursor); + + return ic; +} +#endif + /* maxsize must be >= 2. * 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 FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) +int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) { int len; #if ENABLE_FEATURE_TAB_COMPLETION @@ -1954,11 +2180,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li maxsize = MAX_LINELEN; S.maxsize = maxsize; - /* With null flags, no other fields are ever used */ + /* With zero flags, no other fields are ever used */ state = st ? st : (line_input_t*) &const_int_0; #if MAX_HISTORY > 0 # if ENABLE_FEATURE_EDITING_SAVEHISTORY - if ((state->flags & SAVE_HISTORY) && state->hist_file) + if (state->hist_file) if (state->cnt_history == 0) load_history(state); # endif @@ -1978,22 +2204,19 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #define command command_must_not_be_used 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 */ + /* ~ICANON: unbuffered input (most c_cc[] are disabled, VMIN/VTIME are enabled) */ + /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */ + /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */ + new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG); + /* reads would block only if < 1 char is available */ new_settings.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ 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; + /* Should be not needed if ISIG is off: */ + /* Turn off CTRL-C */ + /* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */ tcsetattr_stdin_TCSANOW(&new_settings); - /* Now initialize things */ - previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); - win_changed(0); /* do initial resizing */ #if ENABLE_USERNAME_OR_HOMEDIR { struct passwd *entry; @@ -2007,7 +2230,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #endif #if 0 - for (i = 0; i <= MAX_HISTORY; i++) + for (i = 0; i <= state->max_history; i++) bb_error_msg("history[%d]:'%s'", i, state->history[i]); bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history); #endif @@ -2016,6 +2239,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li parse_and_put_prompt(prompt); ask_terminal(); + /* Install window resize handler (NB: after *all* init is complete) */ +//FIXME: save entire sigaction! + previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); + win_changed(0); /* get initial window size */ + read_key_buffer[0] = 0; while (1) { /* @@ -2026,15 +2254,14 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li * clutters the big switch a bit, but keeps all the code * in one place. */ - enum { - VI_CMDMODE_BIT = 0x40000000, - /* 0x80000000 bit flags KEYCODE_xxx */ - }; int32_t ic, ic_raw; fflush_all(); - ic = ic_raw = lineedit_read_key(read_key_buffer); + ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); +#if ENABLE_FEATURE_REVERSE_SEARCH + again: +#endif #if ENABLE_FEATURE_EDITING_VI newdelflag = 1; if (vi_cmdmode) { @@ -2138,6 +2365,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) input_backspace(); break; +#if ENABLE_FEATURE_REVERSE_SEARCH + case CTRL('R'): + ic = ic_raw = reverse_i_search(); + goto again; +#endif #if ENABLE_FEATURE_EDITING_VI case 'i'|VI_CMDMODE_BIT: @@ -2194,7 +2426,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case 'd'|VI_CMDMODE_BIT: { int nc, sc; - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ goto return_error_indicator; if (ic == ic_raw) { /* "cc", "dd" */ @@ -2258,7 +2490,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li break; case 'r'|VI_CMDMODE_BIT: //FIXME: unicode case? - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ goto return_error_indicator; if (ic < ' ' || ic > 255) { @@ -2275,6 +2507,44 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li vi_cmdmode = 1; input_backward(1); } + /* Handle a few ESC- combinations the same way + * standard readline bindings (IOW: bash) do. + * Often, Alt- generates ESC-. + */ + ic = lineedit_read_key(read_key_buffer, timeout); + switch (ic) { + //case KEYCODE_LEFT: - bash doesn't do this + case 'b': + ctrl_left(); + break; + //case KEYCODE_RIGHT: - bash doesn't do this + case 'f': + ctrl_right(); + break; + //case KEYCODE_DELETE: - bash doesn't do this + case 'd': /* Alt-D */ + { + /* Delete word forward */ + int nc, sc = cursor; + ctrl_right(); + nc = cursor; + input_backward(cursor - sc); + while (--nc >= cursor) + input_delete(1); + break; + } + case '\b': /* Alt-Backspace(?) */ + case '\x7f': /* Alt-Backspace(?) */ + //case 'w': - bash doesn't do this + { + /* Delete word backward */ + int sc = cursor; + ctrl_left(); + while (sc-- > cursor) + input_delete(1); + break; + } + } break; #endif /* FEATURE_COMMAND_EDITING_VI */ @@ -2291,7 +2561,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li /* Rewrite the line with the selected history item */ /* change command */ command_len = load_string(state->history[state->cur_history] ? - state->history[state->cur_history] : "", maxsize); + state->history[state->cur_history] : ""); /* redraw and go to eol (bol, in vi) */ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); break; @@ -2303,9 +2573,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li input_backward(1); break; case KEYCODE_CTRL_LEFT: + case KEYCODE_ALT_LEFT: /* bash doesn't do it */ ctrl_left(); break; case KEYCODE_CTRL_RIGHT: + case KEYCODE_ALT_RIGHT: /* bash doesn't do it */ ctrl_right(); break; case KEYCODE_HOME: diff --git a/release/src/router/busybox/libbb/llist.c b/release/src/router/busybox/libbb/llist.c index ed84e64723..032e9fac8e 100644 --- a/release/src/router/busybox/libbb/llist.c +++ b/release/src/router/busybox/libbb/llist.c @@ -62,7 +62,7 @@ void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm) /* Recursively free all elements in the linked list. If freeit != NULL * call it on each datum in the list */ -void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data)) +void FAST_FUNC llist_free(llist_t *elm, void (*freeit)(void *data)) { while (elm) { void *data = llist_pop(&elm); diff --git a/release/src/router/busybox/libbb/loop.c b/release/src/router/busybox/libbb/loop.c index b798932faf..b3a5208481 100644 --- a/release/src/router/busybox/libbb/loop.c +++ b/release/src/router/busybox/libbb/loop.c @@ -84,7 +84,7 @@ int FAST_FUNC del_loop(const char *device) search will re-use an existing loop device already bound to that file/offset if it finds one. */ -int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset) +int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, int ro) { char dev[LOOP_NAMESIZE]; char *try; @@ -93,11 +93,13 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse int i, dfd, ffd, mode, rc = -1; /* Open the file. Barf if this doesn't work. */ - mode = O_RDWR; + mode = ro ? O_RDONLY : O_RDWR; ffd = open(file, mode); if (ffd < 0) { - mode = O_RDONLY; - ffd = open(file, mode); + if (mode != O_RDONLY) { + mode = O_RDONLY; + ffd = open(file, mode); + } if (ffd < 0) return -errno; } diff --git a/release/src/router/busybox/libbb/makedev.c b/release/src/router/busybox/libbb/makedev.c index cf59e616b8..06c4039a31 100644 --- a/release/src/router/busybox/libbb/makedev.c +++ b/release/src/router/busybox/libbb/makedev.c @@ -8,16 +8,23 @@ /* We do not include libbb.h - #define makedev() is there! */ #include "platform.h" -#include -#include + +/* Different Unixes want different headers for makedev */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) +# include +#else +# include +# include +#endif #ifdef __GLIBC__ -/* At least glibc has horrendously large inline for this, so wrap it */ +/* 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 FAST_FUNC bb_makedev(unsigned int major, unsigned int minor); -unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor) +/* Suppress gcc "no previous prototype" warning */ +unsigned long long FAST_FUNC bb_makedev(unsigned major, unsigned minor); +unsigned long long FAST_FUNC bb_makedev(unsigned major, unsigned minor) { return makedev(major, minor); } diff --git a/release/src/router/busybox/libbb/match_fstype.c b/release/src/router/busybox/libbb/match_fstype.c index 83d6e67700..32c3d7f188 100644 --- a/release/src/router/busybox/libbb/match_fstype.c +++ b/release/src/router/busybox/libbb/match_fstype.c @@ -12,6 +12,8 @@ #include "libbb.h" +#ifdef HAVE_MNTENT_H + int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) { int match = 1; @@ -40,3 +42,5 @@ int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) return !match; } + +#endif /* HAVE_MNTENT_H */ diff --git a/release/src/router/busybox/libbb/messages.c b/release/src/router/busybox/libbb/messages.c index b6f2c5ccdc..7ee434c559 100644 --- a/release/src/router/busybox/libbb/messages.c +++ b/release/src/router/busybox/libbb/messages.c @@ -22,7 +22,7 @@ const char bb_banner[] ALIGN1 = BANNER; -const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted"; +const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory"; const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'"; const char bb_msg_unknown[] ALIGN1 = "(unknown)"; const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket"; @@ -48,15 +48,16 @@ const int const_int_1 = 1; * and it will end up in bss */ const int const_int_0 = 0; -#include +#if ENABLE_FEATURE_WTMP /* This is usually something like "/var/adm/wtmp" or "/var/log/wtmp" */ const char bb_path_wtmp_file[] ALIGN1 = -#if defined _PATH_WTMP +# if defined _PATH_WTMP _PATH_WTMP; -#elif defined WTMP_FILE +# elif defined WTMP_FILE WTMP_FILE; -#else -#error unknown path to wtmp file +# else +# error unknown path to wtmp file +# endif #endif /* We use it for "global" data via *(struct global*)&bb_common_bufsiz1. diff --git a/release/src/router/busybox/libbb/obscure.c b/release/src/router/busybox/libbb/obscure.c index dd8cd319a0..9ecc1f672c 100644 --- a/release/src/router/busybox/libbb/obscure.c +++ b/release/src/router/busybox/libbb/obscure.c @@ -109,10 +109,12 @@ static const char *obscure_msg(const char *old_p, const char *new_p, const struc if (string_checker(new_p, pw->pw_name)) { return "similar to username"; } +#ifndef __BIONIC__ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */ if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) { return "similar to gecos"; } +#endif /* hostname as-is, as sub-string, reversed, capitalized, doubled */ hostname = safe_gethostname(); i = string_checker(new_p, hostname); diff --git a/release/src/router/busybox/libbb/parse_config.c b/release/src/router/busybox/libbb/parse_config.c index d471edbeec..1590d9a4c0 100644 --- a/release/src/router/busybox/libbb/parse_config.c +++ b/release/src/router/busybox/libbb/parse_config.c @@ -8,6 +8,28 @@ * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later. */ +/* Uncomment to enable test applet */ +////config:config PARSE +////config: bool "Uniform config file parser debugging applet: parse" +////config: default n +////config: help +////config: Typical usage of parse API: +////config: char *t[3]; +////config: parser_t *p = config_open(filename); +////config: while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens +////config: bb_error_msg("TOKENS: '%s''%s''%s'", t[0], t[1], t[2]); +////config: } +////config: config_close(p); + +////applet:IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-y += parse_config.o + +//usage:#define parse_trivial_usage +//usage: "[-x] [-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..." +//usage:#define parse_full_usage "\n\n" +//usage: " -x Suppress output (for benchmarking)" + #include "libbb.h" #if defined ENABLE_PARSE && ENABLE_PARSE @@ -15,52 +37,34 @@ int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int parse_main(int argc UNUSED_PARAM, char **argv) { const char *delims = "# \t"; + char **t; unsigned flags = PARSE_NORMAL; int mintokens = 0, ntokens = 128; + unsigned noout; opt_complementary = "-1:n+:m+:f+"; - getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); + noout = 1 & getopt32(argv, "xn:m:d:f:", &ntokens, &mintokens, &delims, &flags); //argc -= optind; argv += optind; + + t = xmalloc(sizeof(t[0]) * ntokens); while (*argv) { + int n; parser_t *p = config_open(*argv); - if (p) { - int n; - char **t = xmalloc(sizeof(char *) * ntokens); - while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) { + while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) { + if (!noout) { for (int i = 0; i < n; ++i) printf("[%s]", t[i]); puts(""); } - config_close(p); } + config_close(p); argv++; } return EXIT_SUCCESS; } #endif -/* - -Typical usage: - ------ CUT ----- - char *t[3]; // tokens placeholder - parser_t *p = config_open(filename); - if (p) { - // parse line-by-line - while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens - // use tokens - bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); - } - ... - // free parser - config_close(p); - } ------ CUT ----- - -*/ - parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) { FILE* fp; @@ -79,25 +83,58 @@ parser_t* FAST_FUNC config_open(const char *filename) return config_open2(filename, fopen_or_warn_stdin); } -static void config_free_data(parser_t *parser) -{ - free(parser->line); - parser->line = NULL; - if (PARSE_KEEP_COPY) { /* compile-time constant */ - free(parser->data); - parser->data = NULL; - } -} - void FAST_FUNC config_close(parser_t *parser) { if (parser) { - config_free_data(parser); + if (PARSE_KEEP_COPY) /* compile-time constant */ + free(parser->data); fclose(parser->fp); + free(parser->line); + free(parser->nline); free(parser); } } +/* This function reads an entire line from a text file, + * up to a newline, exclusive. + * Trailing '\' is recognized as line continuation. + * Returns -1 if EOF/error. + */ +static int get_line_with_continuation(parser_t *parser) +{ + ssize_t len, nlen; + char *line; + + len = getline(&parser->line, &parser->line_alloc, parser->fp); + if (len <= 0) + return len; + + line = parser->line; + for (;;) { + parser->lineno++; + if (line[len - 1] == '\n') + len--; + if (len == 0 || line[len - 1] != '\\') + break; + len--; + + nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp); + if (nlen <= 0) + break; + + if (parser->line_alloc < len + nlen + 1) { + parser->line_alloc = len + nlen + 1; + line = parser->line = xrealloc(line, parser->line_alloc); + } + memcpy(&line[len], parser->nline, nlen); + len += nlen; + } + + line[len] = '\0'; + return len; +} + + /* 0. If parser is NULL return 0. 1. Read a line from config file. If nothing to read then return 0. @@ -126,27 +163,22 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const { char *line; int ntokens, mintokens; - int t, len; + int t; + + if (!parser) + return 0; ntokens = (uint8_t)flags; mintokens = (uint8_t)(flags >> 8); - if (parser == NULL) - return 0; - -again: + again: memset(tokens, 0, sizeof(tokens[0]) * ntokens); - config_free_data(parser); /* Read one line (handling continuations with backslash) */ - line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno); - if (line == NULL) + if (get_line_with_continuation(parser) < 0) return 0; - parser->line = line; - /* Strip trailing line-feed if any */ - if (len && line[len-1] == '\n') - line[len-1] = '\0'; + line = parser->line; /* Skip token in the start of line? */ if (flags & PARSE_TRIM) @@ -155,8 +187,10 @@ again: if (line[0] == '\0' || line[0] == delims[0]) goto again; - if (flags & PARSE_KEEP_COPY) + if (flags & PARSE_KEEP_COPY) { + free(parser->data); parser->data = xstrdup(line); + } /* Tokenize the line */ t = 0; @@ -170,7 +204,7 @@ again: line += strcspn(line, delims[0] ? delims : delims + 1); } else { /* Combining, find comment char if any */ - line = strchrnul(line, delims[0]); + line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); /* Trim any extra delimiters from the end */ if (flags & PARSE_TRIM) { @@ -202,8 +236,6 @@ again: parser->lineno, t, mintokens); if (flags & PARSE_MIN_DIE) xfunc_die(); - if (flags & PARSE_KEEP_COPY) - free(parser->data); goto again; } diff --git a/release/src/router/busybox/libbb/percent_decode.c b/release/src/router/busybox/libbb/percent_decode.c new file mode 100644 index 0000000000..9a9d80c4a3 --- /dev/null +++ b/release/src/router/busybox/libbb/percent_decode.c @@ -0,0 +1,69 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += percent_decode.o + +#include "libbb.h" + +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; } +*/ +} + +char* FAST_FUNC percent_decode_in_place(char *str, int strict) +{ + /* note that decoded string is always shorter than original */ + char *src = str; + char *dst = str; + char c; + + while ((c = *src++) != '\0') { + unsigned v; + + if (!strict && c == '+') { + *dst++ = ' '; + continue; + } + if (c != '%') { + *dst++ = c; + continue; + } + v = hex_to_bin(src[0]); + if (v > 15) { + bad_hex: + if (strict) + return NULL; + *dst++ = '%'; + continue; + } + v = (v * 16) | hex_to_bin(src[1]); + if (v > 255) + goto bad_hex; + if (strict && (v == '/' || v == '\0')) { + /* caller takes it as indication of invalid + * (dangerous wrt exploits) chars */ + return str + 1; + } + *dst++ = v; + src += 2; + } + *dst = '\0'; + return str; +} diff --git a/release/src/router/busybox/libbb/platform.c b/release/src/router/busybox/libbb/platform.c index ccde2bf02e..19734517b1 100644 --- a/release/src/router/busybox/libbb/platform.c +++ b/release/src/router/busybox/libbb/platform.c @@ -28,23 +28,25 @@ int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) r = vsnprintf(buf, 128, format, p); va_end(p); + /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ + if (r < 128) { va_end(p2); - *string_ptr = xstrdup(buf); - return r; + *string_ptr = strdup(buf); + return (*string_ptr ? r : -1); } - *string_ptr = xmalloc(r+1); - r = vsnprintf(*string_ptr, r+1, format, p2); + *string_ptr = malloc(r+1); + r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); va_end(p2); return r; } #endif -#ifndef HAVE_FDPRINTF -/* dprintf is now actually part of POSIX.1, but was only added in 2008 */ -int fdprintf(int fd, const char *format, ...) +#ifndef HAVE_DPRINTF +/* dprintf is now part of POSIX.1, but was only added in 2008 */ +int dprintf(int fd, const char *format, ...) { va_list p; int r; @@ -134,3 +136,43 @@ char* FAST_FUNC strsep(char **stringp, const char *delim) return start; } #endif + +#ifndef HAVE_STPCPY +char* FAST_FUNC stpcpy(char *p, const char *to_add) +{ + while ((*p = *to_add) != '\0') { + p++; + to_add++; + } + return p; +} +#endif + +#ifndef HAVE_GETLINE +ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream) +{ + int ch; + char *line = *lineptr; + size_t alloced = *n; + size_t len = 0; + + do { + ch = fgetc(stream); + if (ch == EOF) + break; + if (len + 1 >= alloced) { + alloced += alloced/4 + 64; + line = xrealloc(line, alloced); + } + line[len++] = ch; + } while (ch != '\n'); + + if (len == 0) + return -1; + + line[len] = '\0'; + *lineptr = line; + *n = alloced; + return len; +} +#endif diff --git a/release/src/router/busybox/libbb/procps.c b/release/src/router/busybox/libbb/procps.c index 33932a3a3b..40587db82b 100644 --- a/release/src/router/busybox/libbb/procps.c +++ b/release/src/router/busybox/libbb/procps.c @@ -12,13 +12,13 @@ #include "libbb.h" -typedef struct unsigned_to_name_map_t { - long id; +typedef struct id_to_name_map_t { + uid_t id; char name[USERNAME_MAX_SIZE]; -} unsigned_to_name_map_t; +} id_to_name_map_t; typedef struct cache_t { - unsigned_to_name_map_t *cache; + id_to_name_map_t *cache; int size; } cache_t; @@ -39,7 +39,7 @@ void FAST_FUNC clear_username_cache(void) #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) +static int get_cached(cache_t *cp, uid_t id) { int i; for (i = 0; i < cp->size; i++) @@ -52,8 +52,8 @@ static int get_cached(cache_t *cp, unsigned id) } #endif -static char* get_cached(cache_t *cp, long id, - char* FAST_FUNC x2x_utoa(long id)) +static char* get_cached(cache_t *cp, uid_t id, + char* FAST_FUNC x2x_utoa(uid_t id)) { int i; for (i = 0; i < cp->size; i++) @@ -127,10 +127,11 @@ static unsigned long fast_strtoul_16(char **endptr) char *str = *endptr; unsigned long n = 0; - while ((c = *str++) != ' ') { + /* Need to stop on both ' ' and '\n' */ + while ((c = *str++) > ' ') { c = ((c|0x20) - '0'); if (c > 9) - // c = c + '0' - 'a' + 10: + /* c = c + '0' - 'a' + 10: */ c = c - ('a' - '0' - 10); n = n*16 + c; } @@ -143,11 +144,12 @@ static unsigned long fast_strtoul_16(char **endptr) /* We cut a lot of corners here for speed */ static unsigned long fast_strtoul_10(char **endptr) { - char c; + unsigned char c; char *str = *endptr; unsigned long n = *str - '0'; - while ((c = *++str) != ' ') + /* Need to stop on both ' ' and '\n' */ + while ((c = *++str) > ' ') n = n*10 + (c - '0'); *endptr = str + 1; /* We skip trailing space! */ @@ -198,7 +200,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, memset(&currec, 0, sizeof(currec)); while (fgets(buf, PROCPS_BUFSIZE, file)) { // Each mapping datum has this form: - // f7d29000-f7d39000 rw-s ADR M:m OFS FILE + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME // Size: nnn kB // Rss: nnn kB // ..... @@ -223,7 +225,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, tp = strchr(buf, '-'); if (tp) { // We reached next mapping - the line of this form: - // f7d29000-f7d39000 rw-s ADR M:m OFS FILE + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME if (cb) { /* If we have a previous record, there's nothing more @@ -242,7 +244,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); - // skipping "rw-s ADR M:m OFS " + // skipping "rw-s FILEOFS M:m INODE " 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) { @@ -284,21 +286,20 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, void BUG_comm_size(void); procps_status_t* FAST_FUNC 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 (;;) { + struct dirent *entry; + char buf[PROCPS_BUFSIZE]; + long tasknice; + unsigned pid; + int n; + char filename[sizeof("/proc/%u/task/%u/cmdline") + sizeof(int)*3 * 2]; + char *filename_tail; + #if ENABLE_FEATURE_SHOW_THREADS - if ((flags & PSSCAN_TASKS) && sp->task_dir) { + if (sp->task_dir) { entry = readdir(sp->task_dir); if (entry) goto got_entry; @@ -320,9 +321,10 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) /* We found another /proc/PID. Do not use it, * there will be /proc/PID/task/PID (same PID!), * so just go ahead and dive into /proc/PID/task. */ - char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; - sprintf(task_dir, "/proc/%u/task", pid); - sp->task_dir = xopendir(task_dir); + sprintf(filename, "/proc/%u/task", pid); + /* Note: if opendir fails, we just go to next /proc/XXX */ + sp->task_dir = opendir(filename); + sp->main_thread_pid = pid; continue; } #endif @@ -345,9 +347,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) } #endif - filename_tail = filename + sprintf(filename, "/proc/%u/", pid); +#if ENABLE_FEATURE_SHOW_THREADS + if (sp->task_dir) + filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->main_thread_pid, pid); + else +#endif + filename_tail = filename + sprintf(filename, "/proc/%u/", pid); if (flags & PSSCAN_UIDGID) { + struct stat sb; if (stat(filename, &sb)) continue; /* process probably exited */ /* Effective UID/GID, not real */ @@ -355,7 +363,14 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) sp->gid = sb.st_gid; } - if (flags & PSSCAN_STAT) { + /* These are all retrieved from proc/NN/stat in one go: */ + if (flags & (PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID + | PSSCAN_COMM | PSSCAN_STATE + | PSSCAN_VSZ | PSSCAN_RSS + | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME + | PSSCAN_TTY | PSSCAN_NICE + | PSSCAN_CPU) + ) { char *cp, *comm1; int tty; #if !ENABLE_FEATURE_FAST_TOP @@ -557,18 +572,47 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) { int sz; - char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; + char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; sprintf(filename, "/proc/%u/cmdline", pid); sz = open_read_close(filename, buf, col - 1); if (sz > 0) { + const char *base; + int comm_len; + buf[sz] = '\0'; while (--sz >= 0 && buf[sz] == '\0') continue; - do { + base = bb_basename(buf); /* before we replace argv0's NUL with space */ + while (sz >= 0) { if ((unsigned char)(buf[sz]) < ' ') buf[sz] = ' '; - } while (--sz >= 0); + sz--; + } + + /* If comm differs from argv0, prepend "{comm} ". + * It allows to see thread names set by prctl(PR_SET_NAME). + */ + if (base[0] == '-') /* "-sh" (login shell)? */ + base++; + comm_len = strlen(comm); + /* Why compare up to comm_len, not COMM_LEN-1? + * Well, some processes rewrite argv, and use _spaces_ there + * while rewriting. (KDE is observed to do it). + * I prefer to still treat argv0 "process foo bar" + * as 'equal' to comm "process". + */ + if (strncmp(base, comm, comm_len) != 0) { + comm_len += 3; + if (col > comm_len) + memmove(buf + comm_len, buf, col - comm_len); + snprintf(buf, col, "{%s}", comm); + if (col <= comm_len) + return; + buf[comm_len - 1] = ' '; + buf[col - 1] = '\0'; + } + } else { snprintf(buf, col, "[%s]", comm); } diff --git a/release/src/router/busybox/libbb/progress.c b/release/src/router/busybox/libbb/progress.c index 22e2d001e8..199fd0105b 100644 --- a/release/src/router/busybox/libbb/progress.c +++ b/release/src/router/busybox/libbb/progress.c @@ -52,81 +52,121 @@ static unsigned int get_tty2_width(void) return width; } -void FAST_FUNC bb_progress_init(bb_progress_t *p) +void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) { +#if ENABLE_UNICODE_SUPPORT + init_unicode(); + p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); +#else + p->curfile = curfile; +#endif p->start_sec = monotonic_sec(); - p->lastupdate_sec = p->start_sec; - p->lastsize = 0; - p->inited = 1; + p->last_update_sec = p->start_sec; + p->last_change_sec = p->start_sec; + p->last_size = 0; } void FAST_FUNC bb_progress_update(bb_progress_t *p, - const char *curfile, - off_t beg_range, - off_t transferred, - off_t totalsize) + uoff_t beg_size, + uoff_t transferred, + uoff_t totalsize) { uoff_t beg_and_transferred; unsigned since_last_update, elapsed; - unsigned ratio; - int barlength, i; + int barlength; + int kiloscale; - /* totalsize == 0 if it is unknown */ + //transferred = 1234; /* use for stall detection testing */ + //totalsize = 0; /* use for unknown size download testing */ elapsed = monotonic_sec(); - since_last_update = elapsed - p->lastupdate_sec; - /* Do not update on every call - * (we can be called on every network read!) */ - if (since_last_update == 0 && !totalsize) - return; - - beg_and_transferred = beg_range + transferred; - ratio = 100; - if (beg_and_transferred < totalsize) { - /* Do not update on every call - * (we can be called on every network read!) */ - if (since_last_update == 0) - return; - /* long long helps to have it working even if !LFS */ - ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; + since_last_update = elapsed - p->last_update_sec; + p->last_update_sec = elapsed; + + if (totalsize != 0 && transferred >= totalsize - beg_size) { + /* Last call. Do not skip this update */ + transferred = totalsize - beg_size; /* sanitize just in case */ + } + else if (since_last_update == 0) { + /* + * Do not update on every call + * (we can be called on every network read!) + */ + return; } -#if ENABLE_UNICODE_SUPPORT - init_unicode(); - { - char *buf = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); - fprintf(stderr, "\r%s%4u%% ", buf, ratio); - free(buf); + kiloscale = 0; + /* + * Scale sizes down if they are close to overflowing. + * This allows calculations like (100 * transferred / totalsize) + * without risking overflow: we guarantee 10 highest bits to be 0. + * Introduced error is less than 1 / 2^12 ~= 0.025% + */ + if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) { + /* + * 64-bit CPU || small off_t: in either case, + * >> is cheap, single-word operation. + * ... || strange off_t: also use this code + * (it is safe, just suboptimal wrt code size), + * because 32/64 optimized one works only for 64-bit off_t. + */ + if (totalsize >= (1 << 22)) { + totalsize >>= 10; + beg_size >>= 10; + transferred >>= 10; + kiloscale = 1; + } + } else { + /* 32-bit CPU and 64-bit off_t. + * Use a 40-bit shift, it is easier to do on 32-bit CPU. + */ +/* ONE suppresses "warning: shift count >= width of type" */ +#define ONE (sizeof(off_t) > 4) + if (totalsize >= (uoff_t)(1ULL << 54*ONE)) { + totalsize = (uint32_t)(totalsize >> 32*ONE) >> 8; + beg_size = (uint32_t)(beg_size >> 32*ONE) >> 8; + transferred = (uint32_t)(transferred >> 32*ONE) >> 8; + kiloscale = 4; + } } -#else - fprintf(stderr, "\r%-20.20s%4u%% ", curfile, ratio); -#endif - barlength = get_tty2_width() - 49; - if (barlength > 0) { - /* god bless gcc for variable arrays :) */ - char buf[barlength + 1]; - unsigned stars = (unsigned)barlength * ratio / (unsigned)100; - memset(buf, ' ', barlength); - buf[barlength] = '\0'; - memset(buf, '*', stars); - fprintf(stderr, "|%s|", buf); + if (ENABLE_UNICODE_SUPPORT) + fprintf(stderr, "\r%s", p->curfile); + else + fprintf(stderr, "\r%-20.20s", p->curfile); + + beg_and_transferred = beg_size + transferred; + + if (totalsize != 0) { + unsigned ratio = 100 * beg_and_transferred / totalsize; + fprintf(stderr, "%4u%%", ratio); + + barlength = get_tty2_width() - 49; + if (barlength > 0) { + /* god bless gcc for variable arrays :) */ + char buf[barlength + 1]; + unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; + memset(buf, ' ', barlength); + buf[barlength] = '\0'; + memset(buf, '*', stars); + fprintf(stderr, " |%s|", buf); + } } - i = 0; while (beg_and_transferred >= 100000) { - i++; beg_and_transferred >>= 10; + kiloscale++; } /* see http://en.wikipedia.org/wiki/Tera */ - fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); -#define beg_and_transferred dont_use_beg_and_transferred_below + fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); +#define beg_and_transferred dont_use_beg_and_transferred_below() - if (transferred > p->lastsize) { - p->lastupdate_sec = elapsed; - p->lastsize = transferred; + since_last_update = elapsed - p->last_change_sec; + if ((unsigned)transferred != p->last_size) { + p->last_change_sec = elapsed; + p->last_size = (unsigned)transferred; if (since_last_update >= STALLTIME) { - /* We "cut off" these seconds from elapsed time + /* We "cut out" these seconds from elapsed time * by adjusting start time */ p->start_sec += since_last_update; } @@ -135,18 +175,25 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, elapsed -= p->start_sec; /* now it's "elapsed since start" */ if (since_last_update >= STALLTIME) { - fprintf(stderr, " - stalled -"); + fprintf(stderr, " - stalled -"); + } else if (!totalsize || !transferred || (int)elapsed < 0) { + fprintf(stderr, " --:--:-- ETA"); } else { - off_t to_download = totalsize - beg_range; - if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { - fprintf(stderr, "--:--:-- ETA"); - } else { - /* to_download / (transferred/elapsed) - elapsed: */ - /* (long long helps to have working ETA even if !LFS) */ - unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed; - unsigned secs = eta % 3600; - unsigned hours = eta / 3600; - fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); - } + unsigned eta, secs, hours; + + totalsize -= beg_size; /* now it's "total to upload" */ + + /* Estimated remaining time = + * estimated_sec_to_dl_totalsize_bytes - elapsed_sec = + * totalsize / average_bytes_sec_so_far - elapsed = + * totalsize / (transferred/elapsed) - elapsed = + * totalsize * elapsed / transferred - elapsed + */ + eta = totalsize * elapsed / transferred - elapsed; + if (eta >= 1000*60*60) + eta = 1000*60*60 - 1; + secs = eta % 3600; + hours = eta / 3600; + fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60); } } diff --git a/release/src/router/busybox/libbb/pw_encrypt.c b/release/src/router/busybox/libbb/pw_encrypt.c index c6c04d44a6..39ffa084f2 100644 --- a/release/src/router/busybox/libbb/pw_encrypt.c +++ b/release/src/router/busybox/libbb/pw_encrypt.c @@ -27,9 +27,10 @@ static int i64c(int i) return ('a' - 38 + i); } -int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) +int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */) { - x += getpid() + time(NULL); + /* was: x += ... */ + int x = getpid() + monotonic_us(); do { /* x = (x*1664525 + 1013904223) % 2^32 generator is lame * (low-order bit is not "random", etc...), @@ -47,6 +48,26 @@ int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) return x; } +char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) +{ + int len = 2/2; + char *salt_ptr = salt; + if (algo[0] != 'd') { /* not des */ + len = 8/2; /* so far assuming md5 */ + *salt_ptr++ = '$'; + *salt_ptr++ = '1'; + *salt_ptr++ = '$'; +#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA + if (algo[0] == 's') { /* sha */ + salt[1] = '5' + (strcmp(algo, "sha512") == 0); + len = 16/2; + } +#endif + } + crypt_make_salt(salt_ptr, len); + return salt_ptr; +} + #if ENABLE_USE_BB_CRYPT static char* diff --git a/release/src/router/busybox/libbb/read_key.c b/release/src/router/busybox/libbb/read_key.c index 840325c99e..8d72d2a63c 100644 --- a/release/src/router/busybox/libbb/read_key.c +++ b/release/src/router/busybox/libbb/read_key.c @@ -40,13 +40,14 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) '[','C' |0x80,KEYCODE_RIGHT , '[','D' |0x80,KEYCODE_LEFT , /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift- */ - /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt- */ + /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt- - implemented below */ /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift- */ /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl- - implemented below */ /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift- */ '[','H' |0x80,KEYCODE_HOME , /* xterm */ - /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */ '[','F' |0x80,KEYCODE_END , /* xterm */ + /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */ + /* '[','Z' |0x80,KEYCODE_SHIFT_TAB, */ '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ '[','2','~' |0x80,KEYCODE_INSERT , /* ESC [ 2 ; 3 ~ - Alt-Insert */ @@ -86,8 +87,12 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */ '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT, '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT , + /* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP , - unused */ + /* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN , - unused */ + '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT, + '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT , + /* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */ 0 - /* ESC [ Z - Shift-Tab */ }; pfd.fd = fd; @@ -214,7 +219,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) } n++; /* Try to decipher "ESC [ NNN ; NNN R" sequence */ - if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL) + if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL + || ENABLE_FEATURE_VI_ASK_TERMINAL + || ENABLE_FEATURE_LESS_ASK_TERMINAL + ) && n >= 5 && buffer[0] == '[' && buffer[n-1] == 'R' diff --git a/release/src/router/busybox/libbb/read_printf.c b/release/src/router/busybox/libbb/read_printf.c index 8664bc6254..5ed6e36328 100644 --- a/release/src/router/busybox/libbb/read_printf.c +++ b/release/src/router/busybox/libbb/read_printf.c @@ -8,16 +8,6 @@ */ #include "libbb.h" -#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ - || ENABLE_FEATURE_SEAMLESS_BZ2 \ - || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ \ -) - -#if ZIPPED -# include "archive.h" -#endif - /* Suppose that you are a shell. You start child processes. * They work and eventually exit. You want to get user input. @@ -55,32 +45,35 @@ * which detects EAGAIN and uses poll() to wait on the fd. * Thankfully, poll() doesn't care about O_NONBLOCK flag. */ -ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count) +ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) { struct pollfd pfd[1]; ssize_t n; while (1) { - n = safe_read(fd, buf, count); + n = loop_on_EINTR ? safe_read(fd, buf, count) : 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); /* note: this pulls in printf */ + /* note: safe_poll pulls in printf */ + loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1); } } // 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* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) +char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p) { char *p; - size_t sz = buf ? strlen(buf) : 0; + char *buf = NULL; + size_t sz = 0; size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095); goto jump_in; + while (sz < maxsz) { if ((size_t)(p - buf) == sz) { jump_in: @@ -88,8 +81,8 @@ char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) 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 (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 1) != 1) { + /* EOF/error */ if (p == buf) { /* we read nothing */ free(buf); return NULL; @@ -241,132 +234,3 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) bb_perror_msg_and_die("can't read '%s'", filename); return buf; } - -/* Used by e.g. rpm which gives us a fd without filename, - * thus we can't guess the format from filename's extension. - */ -#if ZIPPED -void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) -{ - const int fail_if_not_detected = 1; - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - int offset = -2; -# if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -# else - enum { xformer = 0 }; - const char *xformer_prog; -# endif - - /* .gz and .bz2 both have 2-byte signature, and their - * unpack_XXX_stream wants this header skipped. */ - xread(fd, magic.b16, sizeof(magic.b16[0])); - if (ENABLE_FEATURE_SEAMLESS_GZ - && magic.b16[0] == GZIP_MAGIC - ) { -# if BB_MMU - xformer = unpack_gz_stream; -# else - xformer_prog = "gunzip"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { -# if BB_MMU - xformer = unpack_bz2_stream; -# else - xformer_prog = "bunzip2"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - offset = -6; - xread(fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] == XZ_MAGIC2) { -# if BB_MMU - xformer = unpack_xz_stream; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(fd, offset, SEEK_CUR); -# else - xformer_prog = "unxz"; -# endif - goto found_magic; - } - } - - /* No known magic seen */ - if (fail_if_not_detected) - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - xlseek(fd, offset, SEEK_CUR); - return; - - found_magic: -# if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, offset, SEEK_CUR); -# endif - open_transformer(fd, xformer, xformer_prog); -} -#endif /* ZIPPED */ - -int FAST_FUNC open_zipped(const char *fname) -{ -#if !ZIPPED - return open(fname, O_RDONLY); -#else - char *sfx; - int fd; - - fd = open(fname, O_RDONLY); - if (fd < 0) - return fd; - - sfx = strrchr(fname, '.'); - if (sfx) { - sfx++; - if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) - /* .lzma has no header/signature, just trust it */ - open_transformer(fd, unpack_lzma_stream, "unlzma"); - else - if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) - || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) - || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) - ) { - setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); - } - } - - return fd; -#endif -} - -void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) -{ - int fd; - char *image; - - fd = open_zipped(fname); - if (fd < 0) - return NULL; - - image = xmalloc_read(fd, maxsz_p); - if (!image) - bb_perror_msg("read error from '%s'", fname); - close(fd); - - return image; -} diff --git a/release/src/router/busybox/libbb/setup_environment.c b/release/src/router/busybox/libbb/setup_environment.c index a95fbc5bfc..73229ca6ce 100644 --- a/release/src/router/busybox/libbb/setup_environment.c +++ b/release/src/router/busybox/libbb/setup_environment.c @@ -32,6 +32,9 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw) { + if (!shell || !shell[0]) + shell = DEFAULT_SHELL; + /* Change the current working directory to be the home directory * of the user */ if (chdir(pw->pw_dir)) { diff --git a/release/src/router/busybox/libbb/single_argv.c b/release/src/router/busybox/libbb/single_argv.c index 85137b40fe..64844ddf8f 100644 --- a/release/src/router/busybox/libbb/single_argv.c +++ b/release/src/router/busybox/libbb/single_argv.c @@ -10,6 +10,8 @@ char* FAST_FUNC single_argv(char **argv) { + if (argv[1] && strcmp(argv[1], "--") == 0) + argv++; if (!argv[1] || argv[2]) bb_show_usage(); return argv[1]; diff --git a/release/src/router/busybox/libbb/systemd_support.c b/release/src/router/busybox/libbb/systemd_support.c new file mode 100644 index 0000000000..542a3efffc --- /dev/null +++ b/release/src/router/busybox/libbb/systemd_support.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Davide Cavalca + * + * Based on http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.c + * Copyright 2010 Lennart Poettering + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "libbb.h" + +//config:config FEATURE_SYSTEMD +//config: bool "Enable systemd support" +//config: default y +//config: help +//config: If you plan to use busybox daemons on a system where daemons +//config: are controlled by systemd, enable this option. +//config: If you don't use systemd, it is still safe to enable it, +//config: but the downside is increased code size. + +//kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o + +int sd_listen_fds(void) +{ + const char *e; + int n; + int fd; + + e = getenv("LISTEN_PID"); + if (!e) + return 0; + n = xatoi_positive(e); + /* Is this for us? */ + if (getpid() != (pid_t) n) + return 0; + + e = getenv("LISTEN_FDS"); + if (!e) + return 0; + n = xatoi_positive(e); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) + close_on_exec_on(fd); + + return n; +} diff --git a/release/src/router/busybox/libbb/time.c b/release/src/router/busybox/libbb/time.c index 2a74d34c2c..e2b9384713 100644 --- a/release/src/router/busybox/libbb/time.c +++ b/release/src/router/busybox/libbb/time.c @@ -91,8 +91,15 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) * .SS Seconds, a number from 0 to 61 (with leap seconds) * Everything but the minutes is optional * - * This coincides with the format of "touch -t TIME" + * "touch -t DATETIME" format: [[[[[YY]YY]MM]DD]hh]mm[.ss] + * Some, but not all, Unix "date DATETIME" commands + * move [[YY]YY] past minutes mm field (!). + * Coreutils date does it, and SUS mandates it. + * (date -s DATETIME does not support this format. lovely!) + * In bbox, this format is special-cased in date applet + * (IOW: this function assumes "touch -t" format). */ + unsigned cur_year = ptm->tm_year; int len = strchrnul(date_str, '.') - date_str; /* MM[.SS] */ @@ -133,6 +140,17 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) &end) >= 5) { /* Adjust month from 1-12 to 0-11 */ ptm->tm_mon -= 1; + if ((int)cur_year >= 50) { /* >= 1950 */ + /* Adjust year: */ + /* 1. Put it in the current century */ + ptm->tm_year += (cur_year / 100) * 100; + /* 2. If too far in the past, +100 years */ + if (ptm->tm_year < cur_year - 50) + ptm->tm_year += 100; + /* 3. If too far in the future, -100 years */ + if (ptm->tm_year > cur_year + 50) + ptm->tm_year -= 100; + } } else /* ccyymmddHHMM[.SS] */ if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c", diff --git a/release/src/router/busybox/libbb/u_signal_names.c b/release/src/router/busybox/libbb/u_signal_names.c index 9263859f52..8c78f5e20c 100644 --- a/release/src/router/busybox/libbb/u_signal_names.c +++ b/release/src/router/busybox/libbb/u_signal_names.c @@ -7,6 +7,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config FEATURE_RTMINMAX +//config: bool "Support RTMIN[+n] and RTMAX[-n] signal names" +//config: default y +//config: help +//config: Support RTMIN[+n] and RTMAX[-n] signal names +//config: in kill, killall etc. This costs ~250 bytes. + #include "libbb.h" /* Believe it or not, but some arches have more than 32 SIGs! @@ -117,6 +124,16 @@ static const char signals[][7] = { #ifdef SIGSYS [SIGSYS ] = "SYS", #endif +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMIN + [__SIGRTMIN] = "RTMIN", +# endif +// This makes array about x2 bigger. +// More compact approach is to special-case SIGRTMAX in print_signames() +//# ifdef __SIGRTMAX +// [__SIGRTMAX] = "RTMAX", +//# endif +#endif }; // Convert signal name to number. @@ -134,20 +151,54 @@ int FAST_FUNC get_signum(const char *name) if (strcasecmp(name, signals[i]) == 0) return i; -#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO)) +#if ENABLE_DESKTOP +# if 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 +# ifdef SIGIO if (!name[2]) return SIGIO; -#endif -#ifdef SIGIOT +# endif +# ifdef SIGIOT if ((name[2] | 0x20) == 't' && !name[3]) return SIGIOT; -#endif +# endif } +# endif +#endif + +#if ENABLE_FEATURE_RTMINMAX +# if defined(SIGRTMIN) && defined(SIGRTMAX) +/* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX, + * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide + * them. If they don't exist, fall back to non-underscored ones: */ +# if !defined(__SIGRTMIN) +# define __SIGRTMIN SIGRTMIN +# endif +# if !defined(__SIGRTMAX) +# define __SIGRTMAX SIGRTMAX +# endif + if (strncasecmp(name, "RTMIN", 5) == 0) { + if (!name[5]) + return __SIGRTMIN; + if (name[5] == '+') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMIN + i; + } + } + else if (strncasecmp(name, "RTMAX", 5) == 0) { + if (!name[5]) + return __SIGRTMAX; + if (name[5] == '-') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMAX - i; + } + } +# endif #endif return -1; @@ -175,6 +226,11 @@ void FAST_FUNC print_signames(void) for (signo = 1; signo < ARRAY_SIZE(signals); signo++) { const char *name = signals[signo]; if (name[0]) - puts(name); + printf("%2u) %s\n", signo, name); } +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMAX + printf("%2u) %s\n", __SIGRTMAX, "RTMAX"); +# endif +#endif } diff --git a/release/src/router/busybox/libbb/udp_io.c b/release/src/router/busybox/libbb/udp_io.c index 1f23bfc1ef..ef7ff1de60 100644 --- a/release/src/router/busybox/libbb/udp_io.c +++ b/release/src/router/busybox/libbb/udp_io.c @@ -13,18 +13,13 @@ * We don't check for errors here. Not supported == won't be used */ void FAST_FUNC -socket_want_pktinfo(int fd) +socket_want_pktinfo(int fd UNUSED_PARAM) { #ifdef IP_PKTINFO setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); #endif -#if ENABLE_FEATURE_IPV6 -# ifdef IPV6_RECVPKTINFO - setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &const_int_1, sizeof(int)); - setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &const_int_1, sizeof(int)); -# elif defined(IPV6_PKTINFO) +#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int)); -# endif #endif } diff --git a/release/src/router/busybox/libbb/unicode.c b/release/src/router/busybox/libbb/unicode.c index 08a4c74273..99dc1dfa6a 100644 --- a/release/src/router/busybox/libbb/unicode.c +++ b/release/src/router/busybox/libbb/unicode.c @@ -23,37 +23,44 @@ uint8_t unicode_status; /* Unicode support using libc locale support. */ -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG) { static const char unicode_0x394[] = { 0xce, 0x94, 0 }; size_t width; - if (unicode_status != UNICODE_UNKNOWN) - return; +//TODO: avoid repeated calls by caching last string? + setlocale(LC_ALL, (LANG && LANG[0]) ? LANG : "C"); + /* In unicode, this is a one character string */ // can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused width = mbstowcs(NULL, unicode_0x394, INT_MAX); unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF); } +void FAST_FUNC init_unicode(void) +{ + if (unicode_status == UNICODE_UNKNOWN) + reinit_unicode(getenv("LANG")); +} + #else /* Homegrown Unicode support. It knows only C and Unicode locales. */ # if ENABLE_FEATURE_CHECK_UNICODE_IN_ENV -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG) { - char *lang; - - if (unicode_status != UNICODE_UNKNOWN) - return; - unicode_status = UNICODE_OFF; - lang = getenv("LANG"); - if (!lang || !(strstr(lang, ".utf") || strstr(lang, ".UTF"))) + if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF"))) return; unicode_status = UNICODE_ON; } + +void FAST_FUNC init_unicode(void) +{ + if (unicode_status == UNICODE_UNKNOWN) + reinit_unicode(getenv("LANG")); +} # endif static size_t wcrtomb_internal(char *s, wchar_t wc) diff --git a/release/src/router/busybox/libbb/utmp.c b/release/src/router/busybox/libbb/utmp.c index 2bf9c11f24..09443fb6c4 100644 --- a/release/src/router/busybox/libbb/utmp.c +++ b/release/src/router/busybox/libbb/utmp.c @@ -7,7 +7,6 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" -#include static void touch(const char *filename) { diff --git a/release/src/router/busybox/libbb/uuencode.c b/release/src/router/busybox/libbb/uuencode.c index 03e708fd55..f7b2484928 100644 --- a/release/src/router/busybox/libbb/uuencode.c +++ b/release/src/router/busybox/libbb/uuencode.c @@ -10,7 +10,7 @@ #include "libbb.h" /* Conversion table. for base 64 */ -const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { +const char bb_uuenc_tbl_base64[65 + 1] 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', @@ -20,7 +20,7 @@ const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' /* termination character */, - '\n', '\0' /* needed for uudecode.c */ + '\0' /* needed for uudecode.c only */ }; const char bb_uuenc_tbl_std[65] ALIGN1 = { @@ -73,23 +73,23 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl } /* - * Decode base64 encoded stream. - * Can stop on EOF, specified char, or on uuencode-style "====" line: - * flags argument controls it. + * Decode base64 encoded string. Stops on '\0'. + * + * Returns: pointer to the undecoded part of source. + * If points to '\0', then the source was fully decoded. + * (*pp_dst): advanced past the last written byte. */ -void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) +const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) { -/* Note that EOF _can_ be passed as exit_char too */ -#define exit_char ((int)(signed char)flags) -#define uu_style_end (flags & BASE64_FLAG_UU_STOP) - - int term_count = 0; + char *dst = *pp_dst; + const char *src_tail; while (1) { - unsigned char translated[4]; + unsigned char six_bit[4]; int count = 0; - /* Process one group of 4 chars */ + /* Fetch up to four 6-bit values */ + src_tail = src; while (count < 4) { char *table_ptr; int ch; @@ -97,49 +97,128 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) /* Get next _valid_ character. * bb_uuenc_tbl_base64[] contains this string: * 0 1 2 3 4 5 6 - * 012345678901234567890123456789012345678901234567890123456789012345 - * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" + * 01234567890123456789012345678901234567890123456789012345678901234 + * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" */ do { - ch = fgetc(src_stream); - if (ch == exit_char && count == 0) - return; - if (ch == EOF) - bb_error_msg_and_die("truncated base64 input"); + ch = *src; + if (ch == '\0') { + if (count == 0) { + /* Example: + * If we decode "QUJD ", we want + * to return ptr to NUL, not to ' ', + * because we did fully decode + * the string (to "ABC"). + */ + src_tail = src; + } + goto ret; + } + src++; table_ptr = strchr(bb_uuenc_tbl_base64, ch); //TODO: add BASE64_FLAG_foo to die on bad char? -//Note that then we may need to still allow '\r' (for mail processing) } while (!table_ptr); /* Convert encoded character to decimal */ ch = table_ptr - bb_uuenc_tbl_base64; - if (ch == 65 /* '\n' */) { - /* Terminating "====" line? */ - if (uu_style_end && term_count == 4) - return; /* yes */ - term_count = 0; - continue; - } /* ch is 64 if char was '=', otherwise 0..63 */ - translated[count] = ch & 63; /* 64 -> 0 */ - if (ch == 64) { - term_count++; + if (ch == 64) break; - } + six_bit[count] = ch; count++; - term_count = 0; } - /* Merge 6 bit chars to 8 bit. + /* Transform 6-bit values to 8-bit ones. * count can be < 4 when we decode the tail: - * "eQ==" -> "y", not "y NUL NUL" + * "eQ==" -> "y", not "y NUL NUL". + * Note that (count > 1) is always true, + * "x===" encoding is not valid: + * even a single zero byte encodes as "AA==". + * However, with current logic we come here with count == 1 + * when we decode "==" tail. */ if (count > 1) - fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); + *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; if (count > 2) - fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); + *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; if (count > 3) - fputc(translated[2] << 6 | translated[3], dst_stream); + *dst++ = six_bit[2] << 6 | six_bit[3]; + /* Note that if we decode "AA==" and ate first '=', + * we just decoded one char (count == 2) and now we'll + * do the loop once more to decode second '='. + */ } /* while (1) */ + ret: + *pp_dst = dst; + return src_tail; +} + +/* + * Decode base64 encoded stream. + * Can stop on EOF, specified char, or on uuencode-style "====" line: + * flags argument controls it. + */ +void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) +{ +/* Note that EOF _can_ be passed as exit_char too */ +#define exit_char ((int)(signed char)flags) +#define uu_style_end (flags & BASE64_FLAG_UU_STOP) + + /* uuencoded files have 61 byte lines. Use 64 byte buffer + * to process line at a time. + */ + enum { BUFFER_SIZE = 64 }; + + char in_buf[BUFFER_SIZE + 2]; + char out_buf[BUFFER_SIZE / 4 * 3 + 2]; + char *out_tail; + const char *in_tail; + int term_seen = 0; + int in_count = 0; + + while (1) { + while (in_count < BUFFER_SIZE) { + int ch = fgetc(src_stream); + if (ch == exit_char) { + if (in_count == 0) + return; + term_seen = 1; + break; + } + if (ch == EOF) { + term_seen = 1; + break; + } + /* Prevent "====" line to be split: stop if we see '\n'. + * We can also skip other whitespace and skirt the problem + * of files with NULs by stopping on any control char or space: + */ + if (ch <= ' ') + break; + in_buf[in_count++] = ch; + } + in_buf[in_count] = '\0'; + + /* Did we encounter "====" line? */ + if (uu_style_end && strcmp(in_buf, "====") == 0) + return; + + out_tail = out_buf; + in_tail = decode_base64(&out_tail, in_buf); + + fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); + + if (term_seen) { + /* Did we consume ALL characters? */ + if (*in_tail == '\0') + return; + /* No */ + bb_error_msg_and_die("truncated base64 input"); + } + + /* It was partial decode */ + in_count = strlen(in_tail); + memmove(in_buf, in_tail, in_count); + } } diff --git a/release/src/router/busybox/libbb/vdprintf.c b/release/src/router/busybox/libbb/vdprintf.c index feeb403a08..05426873e5 100644 --- a/release/src/router/busybox/libbb/vdprintf.c +++ b/release/src/router/busybox/libbb/vdprintf.c @@ -12,10 +12,10 @@ #if defined(__GLIBC__) && __GLIBC__ < 2 int FAST_FUNC vdprintf(int d, const char *format, va_list ap) { - char buf[BUF_SIZE]; + char buf[8 * 1024]; int len; - len = vsnprintf(buf, BUF_SIZE, format, ap); + len = vsnprintf(buf, sizeof(buf), format, ap); return write(d, buf, len); } #endif diff --git a/release/src/router/busybox/libbb/vfork_daemon_rexec.c b/release/src/router/busybox/libbb/vfork_daemon_rexec.c index 0c879f68fb..ed1f86f0c5 100644 --- a/release/src/router/busybox/libbb/vfork_daemon_rexec.c +++ b/release/src/router/busybox/libbb/vfork_daemon_rexec.c @@ -69,17 +69,22 @@ pid_t FAST_FUNC xspawn(char **argv) } #if ENABLE_FEATURE_PREFER_APPLETS -void FAST_FUNC save_nofork_data(struct nofork_save_area *save) +struct nofork_save_area { + jmp_buf die_jmp; + const char *applet_name; + uint32_t option_mask32; + int die_sleep; + uint8_t xfunc_error_retval; +}; +static 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 FAST_FUNC restore_nofork_data(struct nofork_save_area *save) +static void restore_nofork_data(struct nofork_save_area *save) { memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); applet_name = save->applet_name; @@ -88,19 +93,17 @@ void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) die_sleep = save->die_sleep; } -int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) +int FAST_FUNC run_nofork_applet(int applet_no, char **argv) { int rc, argc; + struct nofork_save_area old; + + save_nofork_data(&old); 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; - /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. * @@ -130,6 +133,11 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n while (argv[argc]) argc++; + /* 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; + rc = setjmp(die_jmp); if (!rc) { /* Some callers (xargs) @@ -138,15 +146,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n 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 _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 _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) @@ -154,7 +153,7 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n } /* Restoring some globals */ - restore_nofork_data(old); + restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ #ifdef __GLIBC__ @@ -165,15 +164,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } - -int FAST_FUNC 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 FAST_FUNC spawn_and_wait(char **argv) @@ -183,17 +173,17 @@ int FAST_FUNC spawn_and_wait(char **argv) int a = find_applet_by_name(argv[0]); if (a >= 0 && (APPLET_IS_NOFORK(a) -#if BB_MMU +# if BB_MMU || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ -#endif +# endif )) { -#if BB_MMU +# if BB_MMU if (APPLET_IS_NOFORK(a)) -#endif +# endif { return run_nofork_applet(a, argv); } -#if BB_MMU +# if BB_MMU /* MMU only */ /* a->noexec is true */ rc = fork(); @@ -202,7 +192,7 @@ int FAST_FUNC spawn_and_wait(char **argv) /* child */ xfunc_error_retval = EXIT_FAILURE; run_applet_no_and_exit(a, argv); -#endif +# endif } #endif /* FEATURE_PREFER_APPLETS */ rc = spawn(argv); @@ -263,11 +253,19 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) if (!(flags & DAEMON_ONLY_SANITIZE)) { if (fork_or_rexec(argv)) exit(EXIT_SUCCESS); /* parent */ - /* if daemonizing, make sure we detach from stdio & ctty */ + /* if daemonizing, detach from stdio & ctty */ setsid(); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); + if (flags & DAEMON_DOUBLE_FORK) { + /* On Linux, session leader can acquire ctty + * unknowingly, by opening a tty. + * Prevent this: stop being a session leader. + */ + if (fork_or_rexec(argv)) + exit(EXIT_SUCCESS); /* parent */ + } } while (fd > 2) { close(fd--); diff --git a/release/src/router/busybox/libbb/xconnect.c b/release/src/router/busybox/libbb/xconnect.c index 3a6585caa8..1c8bb2b730 100644 --- a/release/src/router/busybox/libbb/xconnect.c +++ b/release/src/router/busybox/libbb/xconnect.c @@ -134,16 +134,18 @@ int FAST_FUNC get_nport(const struct sockaddr *sa) return -1; } -void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port) +void FAST_FUNC set_nport(struct sockaddr *sa, unsigned port) { #if ENABLE_FEATURE_IPV6 - if (lsa->u.sa.sa_family == AF_INET6) { - lsa->u.sin6.sin6_port = port; + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (void*) sa; + sin6->sin6_port = port; return; } #endif - if (lsa->u.sa.sa_family == AF_INET) { - lsa->u.sin.sin_port = port; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (void*) sa; + sin->sin_port = port; return; } /* What? UNIX socket? IPX?? :) */ @@ -255,7 +257,7 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) memset(&hint, 0 , sizeof(hint)); hint.ai_family = af; - /* Needed. Or else we will get each address thrice (or more) + /* Need SOCK_STREAM, or else we 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; @@ -283,9 +285,10 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen); set_port: - set_nport(r, htons(port)); + set_nport(&r->u.sa, htons(port)); ret: - freeaddrinfo(result); + if (result) + freeaddrinfo(result); return r; } #if !ENABLE_FEATURE_IPV6 @@ -319,26 +322,28 @@ len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port) return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); } -#undef xsocket_type -int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type) +int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type) { - IF_NOT_FEATURE_IPV6(enum { family = AF_INET };) len_and_sockaddr *lsa; int fd; int len; -#if ENABLE_FEATURE_IPV6 if (family == AF_UNSPEC) { +#if ENABLE_FEATURE_IPV6 fd = socket(AF_INET6, sock_type, 0); if (fd >= 0) { family = AF_INET6; goto done; } +#endif family = AF_INET; } -#endif + fd = xsocket(family, sock_type, 0); + len = sizeof(struct sockaddr_in); + if (family == AF_UNIX) + len = sizeof(struct sockaddr_un); #if ENABLE_FEATURE_IPV6 if (family == AF_INET6) { done: @@ -354,7 +359,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) { - return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); + return xsocket_type(lsap, AF_UNSPEC, SOCK_STREAM); } static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) @@ -367,8 +372,8 @@ static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) /* user specified bind addr dictates family */ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0); } else { - fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type); - set_nport(lsa, htons(port)); + fd = xsocket_type(&lsa, AF_UNSPEC, sock_type); + set_nport(&lsa->u.sa, htons(port)); } setsockopt_reuseaddr(fd); xbind(fd, &lsa->u.sa, lsa->len); diff --git a/release/src/router/busybox/libbb/xfuncs.c b/release/src/router/busybox/libbb/xfuncs.c index 8f093b708f..fdf8bc9b5f 100644 --- a/release/src/router/busybox/libbb/xfuncs.c +++ b/release/src/router/busybox/libbb/xfuncs.c @@ -25,19 +25,25 @@ #include "libbb.h" /* Turn on nonblocking I/O on a fd */ -int FAST_FUNC ndelay_on(int fd) +void FAST_FUNC ndelay_on(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (flags & O_NONBLOCK) + return; + fcntl(fd, F_SETFL, flags | O_NONBLOCK); } -int FAST_FUNC ndelay_off(int fd) +void FAST_FUNC ndelay_off(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (!(flags & O_NONBLOCK)) + return; + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } -int FAST_FUNC close_on_exec_on(int fd) +void FAST_FUNC close_on_exec_on(int fd) { - return fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFD, FD_CLOEXEC); } char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) @@ -234,7 +240,7 @@ static int wh_helper(int value, int def_val, const char *env_name, int *err) char *s = getenv(env_name); if (s) { value = atoi(s); - /* If LINES/COLUMNS are set, pretent that there is + /* If LINES/COLUMNS are set, pretend that there is * no error getting w/h, this prevents some ugly * cursor tricks by our callers */ *err = 0; diff --git a/release/src/router/busybox/libbb/xfuncs_printf.c b/release/src/router/busybox/libbb/xfuncs_printf.c index 56ee459e45..d8a42ba0bc 100644 --- a/release/src/router/busybox/libbb/xfuncs_printf.c +++ b/release/src/router/busybox/libbb/xfuncs_printf.c @@ -362,6 +362,7 @@ void FAST_FUNC xchroot(const char *path) { if (chroot(path)) bb_perror_msg_and_die("can't change root directory to %s", path); + xchdir("/"); } // Print a warning message if opendir() fails, but don't die. diff --git a/release/src/router/busybox/libpwdgrp/pwd_grp.c b/release/src/router/busybox/libpwdgrp/pwd_grp.c index abb6f189ad..edf53f350b 100644 --- a/release/src/router/busybox/libpwdgrp/pwd_grp.c +++ b/release/src/router/busybox/libpwdgrp/pwd_grp.c @@ -20,21 +20,9 @@ #include "libbb.h" #include -#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 @@ -59,46 +47,24 @@ static int FAST_FUNC bb__parsespent(void *sp, char *line); 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 + /* It's ok to use one buffer for getpwuid and getpwnam. Manpage says: + * "The return value may point to a static area, and may be overwritten + * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." + */ + struct passwd getpw_resultbuf; + struct group getgr_resultbuf; + + char getpw_buffer[PWD_BUFFER_SIZE]; + char getgr_buffer[GRP_BUFFER_SIZE]; #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]; + struct spwd getsp_resultbuf; + char getsp_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; @@ -192,22 +158,22 @@ int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf, struct passwd *fgetpwent(FILE *stream) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(fgetpwent); - char *buffer = BUFFER(fgetpwent); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result); + fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } struct group *fgetgrent(FILE *stream) { struct statics *S; - struct group *resultbuf = RESULTBUF(fgetgrent); - char *buffer = BUFFER(fgetgrent); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result); + fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } #endif @@ -217,11 +183,11 @@ struct group *fgetgrent(FILE *stream) struct spwd *fgetspent(FILE *stream) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(fgetspent); - char *buffer = BUFFER(fgetspent); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result); + fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -309,11 +275,11 @@ int sgetspent_r(const char *string, struct spwd *result_buf, struct passwd *getpwuid(uid_t uid) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwuid); - char *buffer = BUFFER(getpwuid); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result); + getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -321,11 +287,11 @@ struct passwd *getpwuid(uid_t uid) struct group *getgrgid(gid_t gid) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrgid); - char *buffer = BUFFER(getgrgid); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result); + getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -356,11 +322,11 @@ int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf, struct spwd *getspuid(uid_t uid) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspuid); - char *buffer = BUFFER(getspuid); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result); + getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -369,11 +335,11 @@ struct spwd *getspuid(uid_t uid) struct passwd *getpwnam(const char *name) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwnam); - char *buffer = BUFFER(getpwnam); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result); + getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -381,11 +347,11 @@ struct passwd *getpwnam(const char *name) struct group *getgrnam(const char *name) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrnam); - char *buffer = BUFFER(getgrnam); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result); + getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -393,11 +359,11 @@ struct group *getgrnam(const char *name) struct spwd *getspnam(const char *name) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspnam); - char *buffer = BUFFER(getspnam); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result); + getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -451,6 +417,7 @@ int getpwent_r(struct passwd *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(pwf)); } rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf); @@ -498,6 +465,7 @@ int getgrent_r(struct group *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(grf)); } rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf); @@ -546,6 +514,7 @@ int getspent_r(struct spwd *resultbuf, char *buffer, rv = errno; goto ERR; } + close_on_exec_on(fileno(spf)); } rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf); diff --git a/release/src/router/busybox/libpwdgrp/uidgid_get.c b/release/src/router/busybox/libpwdgrp/uidgid_get.c index 92290bfdb6..8388be0dad 100644 --- a/release/src/router/busybox/libpwdgrp/uidgid_get.c +++ b/release/src/router/busybox/libpwdgrp/uidgid_get.c @@ -71,7 +71,8 @@ int FAST_FUNC get_uidgid(struct bb_uidgid_t *u, const char *ug, int numeric_ok) } } gr = getgrnam(group); - if (!gr) return 0; + if (!gr) + return 0; u->gid = gr->gr_gid; } return 1; diff --git a/release/src/router/busybox/loginutils/Config.src b/release/src/router/busybox/loginutils/Config.src index 4c771bbc41..9bf79afee2 100644 --- a/release/src/router/busybox/loginutils/Config.src +++ b/release/src/router/busybox/loginutils/Config.src @@ -181,7 +181,19 @@ config GETTY default y select FEATURE_SYSLOG help - getty lets you log in on a tty, it is normally invoked by init. + getty lets you log in on a tty. It is normally invoked by init. + + Note that you can save a few bytes by disabling it and + using login applet directly. + If you need to reset tty attributes before calling login, + this script approximates getty: + + exec /dev/$1 2>&1 || exit 1 + reset + stty sane; stty ispeed 38400; stty ospeed 38400 + printf "%s login: " "`hostname`" + read -r login + exec /bin/login "$login" config LOGIN bool "login" @@ -193,6 +205,17 @@ config LOGIN Note that Busybox binary must be setuid root for this applet to work properly. +config LOGIN_SESSION_AS_CHILD + bool "Run logged in session in a child process" + default y if PAM + depends on LOGIN + help + Run the logged in session in a child process. This allows + login to clean up things such as utmp entries or PAM sessions + when the login session is complete. If you use PAM, you + almost always would want this to be set to Y, else PAM session + will not be cleaned up. + config PAM bool "Support for PAM (Pluggable Authentication Modules)" default n @@ -260,6 +283,13 @@ config 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 FEATURE_DEFAULT_PASSWD_ALGO + string "Default password encryption method (passwd -a, cryptpw -m parameter)" + default "des" + depends on PASSWD || CRYPTPW + help + Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". + config SU bool "su" default y diff --git a/release/src/router/busybox/loginutils/README b/release/src/router/busybox/loginutils/README new file mode 100644 index 0000000000..ce8851097d --- /dev/null +++ b/release/src/router/busybox/loginutils/README @@ -0,0 +1,70 @@ + Getty + +??? Should getty open tty with or without O_NONBLOCK? +For serial lines, it means "should getty wait for Carrier Detect pin?" +I checked other getties: + +- agetty always uses O_NONBLOCK +- mgetty uses O_NONBLOCK unless run with -b, or as "getty" + +??? If we decided to use O_NONBLOCK (perhaps optionally with -b), +when getty should send -I INITSTR data to tty? After open succeeds? +What if we also want to initialize *modem* with some AT commands? + +??? Should we check/create /var/lock/LCK..ttyPFX lockfiles? + +??? mgetty opens tty but does NOT lock it, then waits for input via +select/poll, and when input is available, it checks lock file. +If it exists, mgetty exits (it assumes someone else uses the line). +If no, it creates the file (lock the tty). Sounds like a good algorithm +to use if we are called with -w... + +Getty should establish a new session and process group, and ensure +that tty is a ctty. + +??? Should getty ensure that other processes which might have opened +fds to this tty be dusconnected? agetty has a -R option which makes +agetty call vhangup() after tty is opened. (Then agetty opens it again, +since it probably vhangup'ed its own fd too). + +Getty should leave the tty in approximately the same state as "stty sane" +before it execs login program. Minor things we do conditionally are: + c_iflag |= ICRNL; // if '\r' was used to end username + +??? mgetty uses per-tty file to ignore connects, /etc/nologin.ttyxx - +is it useful? + +It should be possible to run "getty 0 -" from a shell prompt. +[This currently doesn't work from interactive shell since setsid() +fails in process group leader. The workaround is to run it as a child +of something. sh -c 'getty - 0; true' usually works. Should we fix this?] +It should leave tty in a sane state when it exits (Ctrl-D, -t SEC timeout): +echo should be on, speed, control chars properly set, etc. +(However, it can't restore ctty. The symptom is that "pw_uid == max) { bb_error_msg_and_die("no %cids left", 'u'); + /* this format string is reused in adduser and addgroup */ } p->pw_uid++; } @@ -67,22 +82,42 @@ static void passwd_study(struct passwd *p) static void addgroup_wrapper(struct passwd *p, const char *group_name) { - char *cmd; - - if (group_name) /* Add user to existing group */ - cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name); - else /* Add user to his own group with the first free gid found in passwd_study */ - cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name); - /* Warning: to be compatible with external addgroup programs we should use --gid instead */ - system(cmd); - free(cmd); + char *argv[6]; + + argv[0] = (char*)"addgroup"; + if (group_name) { + /* Add user to existing group */ + argv[1] = (char*)"--"; + argv[2] = p->pw_name; + argv[3] = (char*)group_name; + argv[4] = NULL; + } else { + /* Add user to his own group with the first free gid + * found in passwd_study. + */ +#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS || !ENABLE_ADDGROUP + /* We try to use --gid, not -g, because "standard" addgroup + * has no short option -g, it has only long --gid. + */ + argv[1] = (char*)"--gid"; +#else + /* Breaks if system in fact does NOT use busybox addgroup */ + argv[1] = (char*)"-g"; +#endif + argv[2] = utoa(p->pw_gid); + argv[3] = (char*)"--"; + argv[4] = p->pw_name; + argv[5] = NULL; + } + + spawn_and_wait(argv); } -static void passwd_wrapper(const char *login) NORETURN; +static void passwd_wrapper(const char *login_name) NORETURN; -static void passwd_wrapper(const char *login) +static void passwd_wrapper(const char *login_name) { - BB_EXECLP("passwd", "passwd", login, NULL); + BB_EXECLP("passwd", "passwd", "--", login_name, NULL); bb_error_msg_and_die("can't execute passwd, you must set password manually"); } @@ -123,7 +158,8 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) } pw.pw_gecos = (char *)"Linux User,,,"; - pw.pw_shell = (char *)DEFAULT_SHELL; + /* We assume that newly created users "inherit" root's shell setting */ + pw.pw_shell = (char *)get_shell_name(); pw.pw_dir = NULL; /* exactly one non-option arg */ @@ -203,9 +239,11 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) if (mkdir_err == 0) { /* New home. Copy /etc/skel to it */ const char *args[] = { - "chown", "-R", + "chown", + "-R", xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid), - pw.pw_dir, NULL + pw.pw_dir, + NULL }; /* Be silent on any errors (like: no /etc/skel) */ logmode = LOGMODE_NONE; diff --git a/release/src/router/busybox/loginutils/chpasswd.c b/release/src/router/busybox/loginutils/chpasswd.c index 48cf9b1303..54ed73795a 100644 --- a/release/src/router/busybox/loginutils/chpasswd.c +++ b/release/src/router/busybox/loginutils/chpasswd.c @@ -7,6 +7,21 @@ */ #include "libbb.h" +//usage:#define chpasswd_trivial_usage +//usage: IF_LONG_OPTS("[--md5|--encrypted]") IF_NOT_LONG_OPTS("[-m|-e]") +//usage:#define chpasswd_full_usage "\n\n" +//usage: "Read user:password from stdin and update /etc/passwd\n" +//usage: IF_LONG_OPTS( +//usage: "\n -e,--encrypted Supplied passwords are in encrypted form" +//usage: "\n -m,--md5 Use MD5 encryption instead of DES" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -e Supplied passwords are in encrypted form" +//usage: "\n -m Use MD5 encryption instead of DES" +//usage: ) + +//TODO: implement -c ALGO + #if ENABLE_LONG_OPTS static const char chpasswd_longopts[] ALIGN1 = "encrypted\0" No_argument "e" @@ -20,12 +35,10 @@ static const char chpasswd_longopts[] ALIGN1 = int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chpasswd_main(int argc UNUSED_PARAM, char **argv) { - char *name, *pass; - char salt[sizeof("$N$XXXXXXXX")]; - int opt, rc; - int rnd = rnd; /* we *want* it to be non-initialized! */ + char *name; + int opt; - if (getuid()) + if (getuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); opt_complementary = "m--e:e--m"; @@ -33,6 +46,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "em"); while ((name = xmalloc_fgetline(stdin)) != NULL) { + char *free_me; + char *pass; + int rc; + pass = strchr(name, ':'); if (!pass) bb_error_msg_and_die("missing new password"); @@ -40,20 +57,28 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) xuname2uid(name); /* dies if there is no such user */ + free_me = NULL; if (!(opt & OPT_ENC)) { - rnd = crypt_make_salt(salt, 1, rnd); + char salt[sizeof("$N$XXXXXXXX")]; + + crypt_make_salt(salt, 1); if (opt & OPT_MD5) { - strcpy(salt, "$1$"); - rnd = crypt_make_salt(salt + 3, 4, rnd); + salt[0] = '$'; + salt[1] = '1'; + salt[2] = '$'; + crypt_make_salt(salt + 3, 4); } - pass = pw_encrypt(pass, salt, 0); + free_me = 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, NULL); - if (rc == 0) /* no lines updated, no errors detected */ + if (rc > 0) /* password in /etc/shadow was updated */ + pass = (char*)"x"; + if (rc >= 0) + /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ #endif rc = update_passwd(bb_path_passwd_file, name, pass, NULL); /* LOGMODE_BOTH logs to syslog also */ @@ -64,8 +89,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) bb_info_msg("Password for '%s' changed", name); logmode = LOGMODE_STDIO; free(name); - if (!(opt & OPT_ENC)) - free(pass); + free(free_me); } return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/loginutils/cryptpw.c b/release/src/router/busybox/loginutils/cryptpw.c index 6c801f9fab..a36f920f40 100644 --- a/release/src/router/busybox/loginutils/cryptpw.c +++ b/release/src/router/busybox/loginutils/cryptpw.c @@ -10,6 +10,43 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define cryptpw_trivial_usage +//usage: "[OPTIONS] [PASSWORD] [SALT]" +/* We do support -s, we just don't mention it */ +//usage:#define cryptpw_full_usage "\n\n" +//usage: "Crypt PASSWORD using crypt(3)\n" +//usage: IF_LONG_OPTS( +//usage: "\n -P,--password-fd=N Read password from fd N" +/* //usage: "\n -s,--stdin Use stdin; like -P0" */ +//usage: "\n -m,--method=TYPE Encryption method" +//usage: "\n -S,--salt=SALT" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -P N Read password from fd N" +/* //usage: "\n -s Use stdin; like -P0" */ +//usage: "\n -m TYPE Encryption method TYPE" +//usage: "\n -S SALT" +//usage: ) + +/* mkpasswd is an alias to cryptpw */ +//usage:#define mkpasswd_trivial_usage +//usage: "[OPTIONS] [PASSWORD] [SALT]" +/* We do support -s, we just don't mention it */ +//usage:#define mkpasswd_full_usage "\n\n" +//usage: "Crypt PASSWORD using crypt(3)\n" +//usage: IF_LONG_OPTS( +//usage: "\n -P,--password-fd=N Read password from fd N" +/* //usage: "\n -s,--stdin Use stdin; like -P0" */ +//usage: "\n -m,--method=TYPE Encryption method" +//usage: "\n -S,--salt=SALT" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -P N Read password from fd N" +/* //usage: "\n -s Use stdin; like -P0" */ +//usage: "\n -m TYPE Encryption method TYPE" +//usage: "\n -S SALT" +//usage: ) + #include "libbb.h" /* Debian has 'mkpasswd' utility, manpage says: @@ -53,11 +90,9 @@ to cryptpw. -a option (alias for -m) came from cryptpw. int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cryptpw_main(int argc UNUSED_PARAM, char **argv) { - /* $N$ + sha_salt_16_bytes + NUL */ - char salt[3 + 16 + 1]; + char salt[MAX_PW_SALT_LEN]; char *salt_ptr; const char *opt_m, *opt_S; - int len; int fd; #if ENABLE_LONG_OPTS @@ -70,7 +105,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; - opt_m = "d"; + opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2:P+"; @@ -82,24 +117,9 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) if (argv[0] && !opt_S) opt_S = argv[1]; - len = 2/2; - salt_ptr = salt; - if (opt_m[0] != 'd') { /* not des */ - len = 8/2; /* so far assuming md5 */ - *salt_ptr++ = '$'; - *salt_ptr++ = '1'; - *salt_ptr++ = '$'; -#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA - if (opt_m[0] == 's') { /* sha */ - salt[1] = '5' + (strcmp(opt_m, "sha512") == 0); - len = 16/2; - } -#endif - } + salt_ptr = crypt_make_pw_salt(salt, opt_m); if (opt_S) - safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3); - else - crypt_make_salt(salt_ptr, len, 0); + safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); xmove_fd(fd, STDIN_FILENO); diff --git a/release/src/router/busybox/loginutils/deluser.c b/release/src/router/busybox/loginutils/deluser.c index 47a10fe148..e39ac55069 100644 --- a/release/src/router/busybox/loginutils/deluser.c +++ b/release/src/router/busybox/loginutils/deluser.c @@ -9,6 +9,18 @@ * Licensed under GPLv2, see file LICENSE in this source tree. * */ + +//usage:#define deluser_trivial_usage +//usage: "USER" +//usage:#define deluser_full_usage "\n\n" +//usage: "Delete USER from the system" + +//usage:#define delgroup_trivial_usage +//usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" +//usage:#define delgroup_full_usage "\n\n" +//usage: "Delete group GROUP from the system" +//usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") + #include "libbb.h" int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/loginutils/getty.c b/release/src/router/busybox/loginutils/getty.c dissimilarity index 72% index 76b0de4499..bbb5a96b42 100644 --- a/release/src/router/busybox/loginutils/getty.c +++ b/release/src/router/busybox/loginutils/getty.c @@ -1,723 +1,693 @@ -/* vi: set sw=4 ts=4: */ -/* agetty.c - another getty program for Linux. By W. Z. Venema 1989 - * Ported to Linux by Peter Orbaek - * 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 - 12/28/95 - * - * 1999-02-22 Arkadiusz Mickiewicz - * - added Native Language Support - * - * 1999-05-05 Thorsten Kranzkowski - * - enable hardware flow control before displaying /etc/issue - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include - -#if ENABLE_FEATURE_UTMP -# include /* LOGIN_PROCESS */ -#endif - -#ifndef IUCLC -# define IUCLC 0 -#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 -#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); - /* note: arg "0" turns into speed B0 */ - 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) { - op->initstring = xstrdup(op->initstring); - /* decode \ddd octal codes into chars */ - strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring); - } - 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); - applet_name = xasprintf("getty: %s", op->tty); - - 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 (!S_ISCHR(st.st_mode)) -// bb_error_msg_and_die("not a character device"); - - 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) -{ - speed_t ispeed, ospeed; - /* - * 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. - */ - /* flush input and output queues, important for modems! */ - tcflush(0, TCIOFLUSH); - ispeed = ospeed = speed; - if (speed == B0) { - /* Speed was specified as "0" on command line. - * Just leave it unchanged */ - ispeed = cfgetispeed(tp); - ospeed = cfgetospeed(tp); - } - tp->c_cflag = CS8 | HUPCL | CREAD; - if (op->flags & F_LOCAL) - tp->c_cflag |= CLOCAL; - cfsetispeed(tp, ispeed); - cfsetospeed(tp, ospeed); - - tp->c_iflag = tp->c_lflag = 0; - tp->c_oflag = OPOST | ONLCR; - tp->c_cc[VMIN] = 1; - tp->c_cc[VTIME] = 0; -#ifdef __linux__ - tp->c_line = 0; -#endif - - /* Optionally enable hardware flow control */ -#ifdef CRTSCTS - if (op->flags & F_RTSCTS) - tp->c_cflag |= CRTSCTS; -#endif - - tcsetattr_stdin_TCSANOW(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: - * - * - * - * 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 */ - tcsetattr_stdin_TCSANOW(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) - cfsetspeed(tp, speed); - break; - } - } - } - - /* Restore terminal settings. Errors will be dealt with later on. */ - tp->c_iflag = iflag; - tp->c_cc[VMIN] = vmin; - tcsetattr_stdin_TCSANOW(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); - tcflush(0, TCIOFLUSH); - - /* 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. */ - errno = EINTR; /* make read of 0 bytes be silent too */ - if (read(STDIN_FILENO, &c, 1) < 1) { - if (errno == EINTR || errno == EIO) - exit(EXIT_SUCCESS); - bb_perror_msg_and_die(bb_msg_read_error); - } - - /* 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 (ascval < ' ') { - /* ignore garbage characters */ - } else if ((int)(bp - logname) >= size_logname - 1) { - bb_error_msg_and_die("input overrun"); - } 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; -#ifdef VSWTC - tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ -#endif - - /* 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 */ - if (tcsetattr_stdin_TCSANOW(tp) < 0) - bb_perror_msg_and_die("tcsetattr"); -} - -int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int getty_main(int argc UNUSED_PARAM, char **argv) -{ - int n; - pid_t pid; - 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_for_write(DEBUGTERM); - 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. - */ - if (tcgetattr(0, &termios) < 0) - bb_perror_msg_and_die("tcgetattr"); - - pid = getpid(); -#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, pid); -#endif - - /* Update the utmp file. This tty is ours now! */ - update_utmp(pid, LOGIN_PROCESS, options.tty, "LOGIN", fakehost); - - /* 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_write1_str(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; - cfsetispeed(&termios, options.speeds[baud_index]); - cfsetospeed(&termios, options.speeds[baud_index]); - tcsetattr_stdin_TCSANOW(&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("can't execute '%s'", options.login); -} +/* vi: set sw=4 ts=4: */ +/* + * Based on agetty - another getty program for Linux. By W. Z. Venema 1989 + * Ported to Linux by Peter Orbaek + * This program is freely distributable. + * + * option added by Eric Rasmussen - 12/28/95 + * + * 1999-02-22 Arkadiusz Mickiewicz + * - Added Native Language Support + * + * 1999-05-05 Thorsten Kranzkowski + * - Enabled hardware flow control before displaying /etc/issue + * + * 2011-01 Venys Vlasenko + * - Removed parity detection code. It can't work reliably: + * if all chars received have bit 7 cleared and odd (or even) parity, + * it is impossible to determine whether other side is 8-bit,no-parity + * or 7-bit,odd(even)-parity. It also interferes with non-ASCII usernames. + * - From now on, we assume that parity is correctly set. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include +#ifndef IUCLC +# define IUCLC 0 +#endif + +#ifndef LOGIN_PROCESS +# undef ENABLE_FEATURE_UTMP +# undef ENABLE_FEATURE_WTMP +# define ENABLE_FEATURE_UTMP 0 +# define ENABLE_FEATURE_WTMP 0 +#endif + + +/* 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 + + +/* + * 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. + */ +#undef _PATH_LOGIN +#define _PATH_LOGIN "/bin/login" + +/* Displayed before the login prompt. + * 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" + +/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */ +#define CTL(x) ((x) ^ 0100) + +/* + * 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 */ + +struct globals { + unsigned timeout; + const char *login; /* login program */ + const char *fakehost; + const char *tty_name; + 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 */ + unsigned char eol; /* end-of-line char seen (CR or NL) */ + struct termios tty_attrs; + char line_buf[128]; +}; + +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +//usage:#define getty_trivial_usage +//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]" +//usage:#define getty_full_usage "\n\n" +//usage: "Open TTY, prompt for login name, then invoke /bin/login\n" +//usage: "\n -h Enable hardware RTS/CTS flow control" +//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)" +//usage: "\n -m Get baud rate from modem's CONNECT status message" +//usage: "\n -n Don't prompt for login name" +//usage: "\n -w Wait for CR or LF before sending /etc/issue" +//usage: "\n -i Don't display /etc/issue" +//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" +//usage: "\n -l LOGIN Invoke LOGIN instead of /bin/login" +//usage: "\n -t SEC Terminate after SEC if no login name is read" +//usage: "\n -I INITSTR Send INITSTR before anything else" +//usage: "\n -H HOST Log HOST into the utmp file as the hostname" +//usage: "\n" +//usage: "\nBAUD_RATE of 0 leaves it unchanged" + +static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn"; +#define F_INITSTRING (1 << 0) /* -I */ +#define F_LOCAL (1 << 1) /* -L */ +#define F_FAKEHOST (1 << 2) /* -H */ +#define F_CUSTISSUE (1 << 3) /* -f */ +#define F_RTSCTS (1 << 4) /* -h */ +#define F_NOISSUE (1 << 5) /* -i */ +#define F_LOGIN (1 << 6) /* -l */ +#define F_PARSE (1 << 7) /* -m */ +#define F_TIMEOUT (1 << 8) /* -t */ +#define F_WAITCRLF (1 << 9) /* -w */ +#define F_NOPROMPT (1 << 10) /* -n */ + + +/* 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 alternate baud rates */ +static void parse_speeds(char *arg) +{ + char *cp; + + /* NB: at least one iteration is always done */ + debug("entered parse_speeds\n"); + while ((cp = strsep(&arg, ",")) != NULL) { + G.speeds[G.numspeed] = bcode(cp); + if (G.speeds[G.numspeed] < 0) + bb_error_msg_and_die("bad speed: %s", cp); + /* note: arg "0" turns into speed B0 */ + G.numspeed++; + if (G.numspeed > MAX_SPEED) + bb_error_msg_and_die("too many alternate speeds"); + } + debug("exiting parse_speeds\n"); +} + +/* parse command-line arguments */ +static void parse_args(char **argv) +{ + char *ts; + int flags; + + opt_complementary = "-2:t+"; /* at least 2 args; -t N */ + flags = getopt32(argv, opt_string, + &G.initstring, &G.fakehost, &G.issue, + &G.login, &G.timeout + ); + if (flags & F_INITSTRING) { + G.initstring = xstrdup(G.initstring); + /* decode \ddd octal codes into chars */ + strcpy_and_process_escape_sequences(G.initstring, G.initstring); + } + argv += optind; + debug("after getopt\n"); + + /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ + G.tty_name = argv[0]; + ts = argv[1]; /* baud rate(s) */ + if (isdigit(argv[0][0])) { + /* A number first, assume it's a speed (BSD style) */ + G.tty_name = ts; /* tty name is in argv[1] */ + ts = argv[0]; /* baud rate(s) */ + } + parse_speeds(ts); + + if (argv[2]) + xsetenv("TERM", argv[2]); + + debug("exiting parse_args\n"); +} + +/* set up tty as standard input, output, error */ +static void open_tty(void) +{ + /* Set up new standard input, unless we are given an already opened port */ + if (NOT_LONE_DASH(G.tty_name)) { + if (G.tty_name[0] != '/') + G.tty_name = xasprintf("/dev/%s", G.tty_name); /* will leak it */ + + /* Open the tty as standard input */ + debug("open(2)\n"); + close(0); + xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */ + + /* Set proper protections and ownership */ + fchown(0, 0, 0); /* 0:0 */ + fchmod(0, 0620); /* crw--w---- */ + } else { + char *n; + /* + * 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_RDONLY|O_WRONLY)) != O_RDWR) + bb_error_msg_and_die("stdin is not open for read/write"); + + /* Try to get real tty name instead of "-" */ + n = xmalloc_ttyname(0); + if (n) + G.tty_name = n; + } + applet_name = xasprintf("getty: %s", skip_dev_pfx(G.tty_name)); +} + +static void set_tty_attrs(void) +{ + if (tcsetattr_stdin_TCSANOW(&G.tty_attrs) < 0) + bb_perror_msg_and_die("tcsetattr"); +} + +/* We manipulate tty_attrs this way: + * - first, we read existing tty_attrs + * - init_tty_attrs modifies some parts and sets it + * - auto_baud and/or BREAK processing can set different speed and set tty attrs + * - finalize_tty_attrs again modifies some parts and sets tty attrs before + * execing login + */ +static void init_tty_attrs(int speed) +{ + /* Try to drain output buffer, with 5 sec timeout. + * Added on request from users of ~600 baud serial interface + * with biggish buffer on a 90MHz CPU. + * They were losing hundreds of bytes of buffered output + * on tcflush. + */ + signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo); + alarm(5); + tcdrain(STDIN_FILENO); + alarm(0); + + /* Flush input and output queues, important for modems! */ + tcflush(STDIN_FILENO, TCIOFLUSH); + + /* Set speed if it wasn't specified as "0" on command line */ + if (speed != B0) + cfsetspeed(&G.tty_attrs, speed); + + /* Initial 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. + */ + /* Clear all bits except: */ + G.tty_attrs.c_cflag &= (0 + /* 2 stop bits (1 otherwise) + * Enable parity bit (both on input and output) + * Odd parity (else even) + */ + | CSTOPB | PARENB | PARODD +#ifdef CMSPAR + | CMSPAR /* mark or space parity */ +#endif +#ifdef CBAUD + | CBAUD /* (output) baud rate */ +#endif +#ifdef CBAUDEX + | CBAUDEX /* (output) baud rate */ +#endif +#ifdef CIBAUD + | CIBAUD /* input baud rate */ +#endif + ); + /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */ + G.tty_attrs.c_cflag |= CS8 | HUPCL | CREAD; + if (option_mask32 & F_LOCAL) { + /* ignore Carrier Detect pin: + * opens don't block when CD is low, + * losing CD doesn't hang up processes whose ctty is this tty + */ + G.tty_attrs.c_cflag |= CLOCAL; + } +#ifdef CRTSCTS + if (option_mask32 & F_RTSCTS) + G.tty_attrs.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ +#endif + G.tty_attrs.c_iflag = 0; + G.tty_attrs.c_lflag = 0; + /* non-raw output; add CR to each NL */ + G.tty_attrs.c_oflag = OPOST | ONLCR; + + /* reads would block only if < 1 char is available */ + G.tty_attrs.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + G.tty_attrs.c_cc[VTIME] = 0; +#ifdef __linux__ + G.tty_attrs.c_line = 0; +#endif + + set_tty_attrs(); + + debug("term_io 2\n"); +} + +static void finalize_tty_attrs(void) +{ + /* software flow control on output (stop sending if XOFF is recvd); + * and on input (send XOFF when buffer is full) + */ + G.tty_attrs.c_iflag |= IXON | IXOFF; + if (G.eol == '\r') { + G.tty_attrs.c_iflag |= ICRNL; /* map CR on input to NL */ + } + /* Other bits in c_iflag: + * IXANY Any recvd char enables output (any char is also a XON) + * INPCK Enable parity check + * IGNPAR Ignore parity errors (drop bad bytes) + * PARMRK Mark parity errors with 0xff, 0x00 prefix + * (else bad byte is received as 0x00) + * ISTRIP Strip parity bit + * IGNBRK Ignore break condition + * BRKINT Send SIGINT on break - maybe set this? + * INLCR Map NL to CR + * IGNCR Ignore CR + * ICRNL Map CR to NL + * IUCLC Map uppercase to lowercase + * IMAXBEL Echo BEL on input line too long + * IUTF8 Appears to affect tty's idea of char widths, + * observed to improve backspacing through Unicode chars + */ + + /* line buffered input (NL or EOL or EOF chars end a line); + * recognize INT/QUIT/SUSP chars; + * echo input chars; + * echo BS-SP-BS on erase character; + * echo kill char specially, not as ^c (ECHOKE controls how exactly); + * erase all input via BS-SP-BS on kill char (else go to next line) + */ + G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; + /* Other bits in c_lflag: + * XCASE Map uppercase to \lowercase [tried, doesn't work] + * ECHONL Echo NL even if ECHO is not set + * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this? + * ECHOPRT On erase, echo erased chars + * [qwe input looks like "qwe\ewq/" on screen] + * NOFLSH Don't flush input buffer after interrupt or quit chars + * IEXTEN Enable extended functions (??) + * [glibc says it enables c_cc[LNEXT] "enter literal char" + * and c_cc[VDISCARD] "toggle discard buffered output" chars] + * FLUSHO Output being flushed (c_cc[VDISCARD] is in effect) + * PENDIN Retype pending input at next read or input char + * (c_cc[VREPRINT] is being processed) + * TOSTOP Send SIGTTOU for background output + * (why "stty sane" unsets this bit?) + */ + + G.tty_attrs.c_cc[VINTR] = CTL('C'); + G.tty_attrs.c_cc[VQUIT] = CTL('\\'); + G.tty_attrs.c_cc[VEOF] = CTL('D'); + G.tty_attrs.c_cc[VEOL] = '\n'; +#ifdef VSWTC + G.tty_attrs.c_cc[VSWTC] = 0; +#endif +#ifdef VSWTCH + G.tty_attrs.c_cc[VSWTCH] = 0; +#endif + G.tty_attrs.c_cc[VKILL] = CTL('U'); + /* Other control chars: + * VEOL2 + * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname + * VREPRINT - reprint current input buffer + * VLNEXT, VDISCARD, VSTATUS + * VSUSP, VDSUSP - send (delayed) SIGTSTP + * VSTART, VSTOP - chars used for IXON/IXOFF + */ + + set_tty_attrs(); + + /* Now the newline character should be properly written */ + full_write(STDOUT_FILENO, "\n", 1); +} + +/* extract baud rate from modem status message */ +static void auto_baud(void) +{ + 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: + * + * + * + * 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. + */ + + G.tty_attrs.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */ + set_tty_attrs(); + + /* + * 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, G.line_buf, sizeof(G.line_buf) - 1); + if (nread > 0) { + int speed; + char *bp; + G.line_buf[nread] = '\0'; + for (bp = G.line_buf; bp < G.line_buf + nread; bp++) { + if (isdigit(*bp)) { + speed = bcode(bp); + if (speed > 0) + cfsetspeed(&G.tty_attrs, speed); + break; + } + } + } + + /* Restore terminal settings */ + G.tty_attrs.c_cc[VMIN] = 1; /* restore to value set by init_tty_attrs */ + set_tty_attrs(); +} + +/* get user name, establish parity, speed, erase, kill, eol; + * return NULL on BREAK, logname on success + */ +static char *get_logname(void) +{ + char *bp; + char c; + + /* Flush pending input (esp. after parsing or switching the baud rate) */ + usleep(100*1000); /* 0.1 sec */ + tcflush(STDIN_FILENO, TCIFLUSH); + + /* Prompt for and read a login name */ + do { + /* Write issue file and prompt */ +#ifdef ISSUE + if (!(option_mask32 & F_NOISSUE)) + print_login_issue(G.issue, G.tty_name); +#endif + print_login_prompt(); + + /* Read name, watch for break, erase, kill, end-of-line */ + bp = G.line_buf; + while (1) { + /* Do not report trivial EINTR/EIO errors */ + errno = EINTR; /* make read of 0 bytes be silent too */ + if (read(STDIN_FILENO, &c, 1) < 1) { + finalize_tty_attrs(); + if (errno == EINTR || errno == EIO) + exit(EXIT_SUCCESS); + bb_perror_msg_and_die(bb_msg_read_error); + } + + switch (c) { + case '\r': + case '\n': + *bp = '\0'; + G.eol = c; + goto got_logname; + case CTL('H'): + case 0x7f: + G.tty_attrs.c_cc[VERASE] = c; + if (bp > G.line_buf) { + full_write(STDOUT_FILENO, "\010 \010", 3); + bp--; + } + break; + case CTL('U'): + while (bp > G.line_buf) { + full_write(STDOUT_FILENO, "\010 \010", 3); + bp--; + } + break; + case CTL('C'): + case CTL('D'): + finalize_tty_attrs(); + exit(EXIT_SUCCESS); + case '\0': + /* BREAK. If we have speeds to try, + * return NULL (will switch speeds and return here) */ + if (G.numspeed > 1) + return NULL; + /* fall through and ignore it */ + default: + if ((unsigned char)c < ' ') { + /* ignore garbage characters */ + } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) { + /* echo and store the character */ + full_write(STDOUT_FILENO, &c, 1); + *bp++ = c; + } + break; + } + } /* end of get char loop */ + got_logname: ; + } while (G.line_buf[0] == '\0'); /* while logname is empty */ + + return G.line_buf; +} + +static void alarm_handler(int sig UNUSED_PARAM) +{ + finalize_tty_attrs(); + _exit(EXIT_SUCCESS); +} + +int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int getty_main(int argc UNUSED_PARAM, char **argv) +{ + int n; + pid_t pid, tsid; + char *logname; + + INIT_G(); + G.login = _PATH_LOGIN; /* default login program */ +#ifdef ISSUE + G.issue = ISSUE; /* default issue file */ +#endif + G.eol = '\r'; + + /* Parse command-line arguments */ + parse_args(argv); + + /* Create new session and pgrp, lose controlling tty */ + pid = setsid(); /* this also gives us our pid :) */ + if (pid < 0) { + int fd; + /* :( + * docs/ctty.htm says: + * "This is allowed only when the current process + * is not a process group leader". + * Thus, setsid() will fail if we _already_ are + * a session leader - which is quite possible for getty! + */ + pid = getpid(); + if (getsid(0) != pid) + bb_perror_msg_and_die("setsid"); + /* Looks like we are already a session leader. + * In this case (setsid failed) we may still have ctty, + * and it may be different from tty we need to control! + * If we still have ctty, on Linux ioctl(TIOCSCTTY) + * (which we are going to use a bit later) always fails - + * even if we try to take ctty which is already ours! + * Try to drop old ctty now to prevent that. + * Use O_NONBLOCK: old ctty may be a serial line. + */ + fd = open("/dev/tty", O_RDWR | O_NONBLOCK); + if (fd >= 0) { + /* TIOCNOTTY sends SIGHUP to the foreground + * process group - which may include us! + * Make sure to not die on it: + */ + sighandler_t old = signal(SIGHUP, SIG_IGN); + ioctl(fd, TIOCNOTTY); + close(fd); + signal(SIGHUP, old); + } + } + + /* 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_for_write(DEBUGTERM); + for (n = 1; argv[n]; n++) { + debug(argv[n]); + debug("\n"); + } +#endif + + /* Open the tty as standard input, if it is not "-" */ + debug("calling open_tty\n"); + open_tty(); + ndelay_off(STDIN_FILENO); + debug("duping\n"); + xdup2(STDIN_FILENO, 1); + xdup2(STDIN_FILENO, 2); + + /* Steal ctty if we don't have it yet */ + tsid = tcgetsid(STDIN_FILENO); + if (tsid < 0 || pid != tsid) { + if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) < 0) + bb_perror_msg_and_die("TIOCSCTTY"); + } + +#ifdef __linux__ + /* Make ourself a foreground process group within our session */ + if (tcsetpgrp(STDIN_FILENO, pid) < 0) + bb_perror_msg_and_die("tcsetpgrp"); +#endif + + /* + * 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. + */ + if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0) + bb_perror_msg_and_die("tcgetattr"); + + /* Update the utmp file. This tty is ours now! */ + update_utmp(pid, LOGIN_PROCESS, G.tty_name, "LOGIN", G.fakehost); + + /* Initialize tty attrs (raw mode, eight-bit, blocking i/o) */ + debug("calling init_tty_attrs\n"); + init_tty_attrs(G.speeds[0]); + + /* Write the modem init string and DON'T flush the buffers */ + if (option_mask32 & F_INITSTRING) { + debug("writing init string\n"); + full_write1_str(G.initstring); + } + + /* Optionally detect the baud rate from the modem status message */ + debug("before autobaud\n"); + if (option_mask32 & F_PARSE) + auto_baud(); + + /* Set the optional timer */ + signal(SIGALRM, alarm_handler); + alarm(G.timeout); /* if 0, alarm is not set */ + + /* Optionally wait for CR or LF before writing /etc/issue */ + if (option_mask32 & 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); + if (ch == '\n' || ch == '\r') + break; + } + } + + logname = NULL; + if (!(option_mask32 & F_NOPROMPT)) { + /* NB: init_tty_attrs already set line speed + * to G.speeds[0] */ + int baud_index = 0; + + while (1) { + /* Read the login name */ + debug("reading login name\n"); + logname = get_logname(); + if (logname) + break; + /* We are here only if G.numspeed > 1 */ + baud_index = (baud_index + 1) % G.numspeed; + cfsetspeed(&G.tty_attrs, G.speeds[baud_index]); + set_tty_attrs(); + } + } + + /* Disable timer */ + alarm(0); + + finalize_tty_attrs(); + + /* 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(G.login, G.login, "--", logname, NULL); + bb_error_msg_and_die("can't execute '%s'", G.login); +} diff --git a/release/src/router/busybox/loginutils/login.c b/release/src/router/busybox/loginutils/login.c index 9a624df9af..bf43f3aba7 100644 --- a/release/src/router/busybox/loginutils/login.c +++ b/release/src/router/busybox/loginutils/login.c @@ -2,11 +2,17 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define login_trivial_usage +//usage: "[-p] [-h HOST] [[-f] USER]" +//usage:#define login_full_usage "\n\n" +//usage: "Begin a new session on the system\n" +//usage: "\n -f Don't authenticate (user already authenticated)" +//usage: "\n -h Name of the remote host" +//usage: "\n -p Preserve environment" + #include "libbb.h" #include -#if ENABLE_FEATURE_UTMP -# include /* USER_PROCESS */ -#endif #include #if ENABLE_SELINUX @@ -35,7 +41,12 @@ enum { TTYNAME_SIZE = 32, }; -static char* short_tty; +struct globals { + struct termios tty_attrs; +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) + #if ENABLE_FEATURE_NOLOGIN static void die_if_nologin(void) @@ -68,7 +79,7 @@ static void die_if_nologin(void) #endif #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM -static int check_securetty(void) +static int check_securetty(const char *short_tty) { char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ parser_t *parser = config_open2("/etc/securetty", fopen_for_read); @@ -83,7 +94,7 @@ static int check_securetty(void) return buf != NULL; } #else -static ALWAYS_INLINE int check_securetty(void) { return 1; } +static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } #endif #if ENABLE_SELINUX @@ -136,6 +147,29 @@ static void run_login_script(struct passwd *pw, char *full_tty) void run_login_script(struct passwd *pw, char *full_tty); #endif +#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM +static void login_pam_end(pam_handle_t *pamh) +{ + int pamret; + + pamret = pam_setcred(pamh, PAM_DELETE_CRED); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "setcred", + pam_strerror(pamh, pamret), pamret); + } + pamret = pam_close_session(pamh, 0); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "close_session", + pam_strerror(pamh, pamret), pamret); + } + pamret = pam_end(pamh, pamret); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "end", + pam_strerror(pamh, pamret), pamret); + } +} +#endif /* ENABLE_PAM */ + static void get_username_or_die(char *buf, int size_buf) { int c, cntdown; @@ -179,15 +213,21 @@ static void motd(void) static void alarm_handler(int sig UNUSED_PARAM) { - /* This is the escape hatch! Poor serial line users and the like + /* 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); + ndelay_on(STDOUT_FILENO); + /* Test for correct attr restoring: + * run "getty 0 -" from a shell, enter bogus username, stop at + * password prompt, let it time out. Without the tcsetattr below, + * when you are back at shell prompt, echo will be still off. + */ + tcsetattr_stdin_TCSANOW(&G.tty_attrs); + printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT); fflush_all(); /* unix API is brain damaged regarding O_NONBLOCK, * we should undo it, or else we can affect other processes */ - ndelay_off(1); + ndelay_off(STDOUT_FILENO); _exit(EXIT_SUCCESS); } @@ -201,7 +241,6 @@ int login_main(int argc UNUSED_PARAM, char **argv) }; char *fromhost; char username[USERNAME_SIZE]; - const char *shell; int run_by_root; unsigned opt; int count = 0; @@ -209,6 +248,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) char *opt_host = NULL; char *opt_user = opt_user; /* for compiler */ char *full_tty; + char *short_tty; IF_SELINUX(security_context_t user_sid = NULL;) #if ENABLE_PAM int pamret; @@ -217,11 +257,13 @@ int login_main(int argc UNUSED_PARAM, char **argv) const char *failed_msg; struct passwd pwdstruct; char pwdbuf[256]; + char **pamenv; +#endif +#if ENABLE_LOGIN_SESSION_AS_CHILD + pid_t child_pid; #endif - username[0] = '\0'; - signal(SIGALRM, alarm_handler); - alarm(TIMEOUT); + INIT_G(); /* More of suid paranoia if called by non-root: */ /* Clear dangerous stuff, set PATH */ @@ -233,6 +275,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) * (The name of the function is misleading. Not daemonizing here.) */ bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); + username[0] = '\0'; opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); if (opt & LOGIN_OPT_f) { if (!run_by_root) @@ -243,9 +286,19 @@ int login_main(int argc UNUSED_PARAM, char **argv) 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(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) + /* Save tty attributes - and by doing it, check that it's indeed a tty */ + if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0 + || !isatty(STDOUT_FILENO) + /*|| !isatty(STDERR_FILENO) - no, guess some people might want to redirect this */ + ) { return EXIT_FAILURE; /* Must be a terminal */ + } + + /* We install timeout handler only _after_ we saved G.tty_attrs */ + signal(SIGALRM, alarm_handler); + alarm(TIMEOUT); + + /* Find out and memorize our tty name */ full_tty = xmalloc_ttyname(STDIN_FILENO); if (!full_tty) full_tty = xstrdup("UNKNOWN"); @@ -281,14 +334,24 @@ int login_main(int argc UNUSED_PARAM, char **argv) 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) - */ + /* set RHOST */ + if (opt_host) { + pamret = pam_set_item(pamh, PAM_RHOST, opt_host); + if (pamret != PAM_SUCCESS) { + failed_msg = "set_item(RHOST)"; + goto pam_auth_failed; + } + } + if (!(opt & LOGIN_OPT_f)) { + 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); @@ -345,20 +408,23 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (opt & LOGIN_OPT_f) break; /* -f USER: success without asking passwd */ - if (pw->pw_uid == 0 && !check_securetty()) + if (pw->pw_uid == 0 && !check_securetty(short_tty)) 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 */ + /* Password reading and authorization takes place here. + * Note that reads (in no-echo mode) trash tty attributes. + * If we get interrupted by SIGALRM, we need to restore attrs. + */ if (correct_password(pw)) break; #endif /* ENABLE_PAM */ auth_failed: opt &= ~LOGIN_OPT_f; - bb_do_delay(FAIL_DELAY); + bb_do_delay(LOGIN_FAIL_DELAY); /* TODO: doesn't sound like correct English phrase to me */ puts("Login incorrect"); if (++count == 3) { @@ -379,7 +445,22 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (pw->pw_uid != 0) die_if_nologin(); - IF_SELINUX(initselinux(username, full_tty, &user_sid)); +#if ENABLE_LOGIN_SESSION_AS_CHILD + child_pid = vfork(); + if (child_pid != 0) { + if (child_pid < 0) + bb_perror_msg("vfork"); + else { + if (safe_waitpid(child_pid, NULL, 0) == -1) + bb_perror_msg("waitpid"); + update_utmp(child_pid, DEAD_PROCESS, NULL, NULL, NULL); + } + IF_PAM(login_pam_end(pamh);) + return 0; + } +#endif + + IF_SELINUX(initselinux(username, full_tty, &user_sid);) /* Try these, but don't complain if they fail. * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ @@ -393,13 +474,20 @@ int login_main(int argc UNUSED_PARAM, char **argv) run_login_script(pw, full_tty); change_identity(pw); - shell = pw->pw_shell; - if (!shell || !shell[0]) - shell = DEFAULT_SHELL; - setup_environment(shell, + setup_environment(pw->pw_shell, (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, pw); +#if ENABLE_PAM + /* Modules such as pam_env will setup the PAM environment, + * which should be copied into the new environment. */ + pamenv = pam_getenvlist(pamh); + if (pamenv) while (*pamenv) { + putenv(*pamenv); + pamenv++; + } +#endif + motd(); if (pw->pw_uid == 0) @@ -434,7 +522,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, SIG_DFL); /* Exec login shell with no additional parameters */ - run_shell(shell, 1, NULL, NULL); + run_shell(pw->pw_shell, 1, NULL, NULL); /* return EXIT_FAILURE; - not reached */ } diff --git a/release/src/router/busybox/loginutils/passwd.c b/release/src/router/busybox/loginutils/passwd.c index 728e618676..b83db00836 100644 --- a/release/src/router/busybox/loginutils/passwd.c +++ b/release/src/router/busybox/loginutils/passwd.c @@ -2,6 +2,17 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define passwd_trivial_usage +//usage: "[OPTIONS] [USER]" +//usage:#define passwd_full_usage "\n\n" +//usage: "Change USER's password (default: current user)" +//usage: "\n" +//usage: "\n -a ALG Encryption method" +//usage: "\n -d Set password to ''" +//usage: "\n -l Lock (disable) account" +//usage: "\n -u Unlock (enable) account" + #include "libbb.h" #include @@ -10,15 +21,15 @@ 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) +static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo) { - char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ + char salt[MAX_PW_SALT_LEN]; char *orig = (char*)""; char *newp = NULL; char *cp = NULL; char *ret = NULL; /* failure so far */ - if (myuid && pw->pw_passwd[0]) { + if (myuid != 0 && pw->pw_passwd[0]) { char *encrypted; orig = bb_ask_stdin("Old password: "); /* returns ptr to static */ @@ -26,13 +37,13 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) 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); + syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name); + bb_do_delay(LOGIN_FAIL_DELAY); puts("Incorrect password"); goto err_ret; } - if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); + if (ENABLE_FEATURE_CLEAN_UP) + free(encrypted); } orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ newp = bb_ask_stdin("New password: "); /* returns ptr to static */ @@ -40,22 +51,22 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) goto err_ret; newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */ if (ENABLE_FEATURE_PASSWD_WEAK_CHECK - && obscure(orig, newp, pw) && myuid) + && obscure(orig, newp, pw) + && myuid != 0 + ) { goto err_ret; /* non-root is not allowed to have weak passwd */ + } cp = bb_ask_stdin("Retype password: "); if (!cp) goto err_ret; - if (strcmp(cp, newp)) { + if (strcmp(cp, newp) != 0) { 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); - } + crypt_make_pw_salt(salt, algo); + /* pw_encrypt returns malloced str */ ret = pw_encrypt(newp, salt, 1); /* whee, success! */ @@ -63,8 +74,10 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) 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; } @@ -73,17 +86,15 @@ int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int passwd_main(int argc UNUSED_PARAM, 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 + OPT_algo = (1 << 0), /* -a - password algorithm */ + OPT_lock = (1 << 1), /* -l - lock account */ + OPT_unlock = (1 << 2), /* -u - unlock account */ + OPT_delete = (1 << 3), /* -d - delete password */ + OPT_lud = OPT_lock | OPT_unlock | OPT_delete, }; unsigned opt; int rc; - const char *opt_a = ""; + const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; const char *filename; char *myname; char *name; @@ -104,13 +115,9 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) //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])) + if ((opt & OPT_lud) && (myuid != 0 || !argv[0])) bb_show_usage(); /* Will complain and die if username not found */ @@ -118,7 +125,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) name = argv[0] ? argv[0] : myname; pw = xgetpwnam(name); - if (myuid && pw->pw_uid != myuid) { + if (myuid != 0 && pw->pw_uid != myuid) { /* LOGMODE_BOTH */ bb_error_msg_and_die("%s can't change password for %s", myname, name); } @@ -152,27 +159,28 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) newp = NULL; c = pw->pw_passwd[0] - '!'; if (!(opt & OPT_lud)) { - if (myuid && !c) { /* passwd starts with '!' */ + if (myuid != 0 && !c) { /* passwd starts with '!' */ /* LOGMODE_BOTH */ bb_error_msg_and_die("can't change " "locked password for %s", name); } printf("Changing password for %s\n", name); - newp = new_password(pw, myuid, opt & STATE_ALGO_md5); + newp = new_password(pw, myuid, opt_a); 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 '!' */ + if (!c) + goto skip; /* passwd starts with '!' */ newp = xasprintf("!%s", pw->pw_passwd); } else if (opt & OPT_unlock) { - if (c) goto skip; /* not '!' */ + 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*)""; } @@ -189,7 +197,11 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_SHADOWPASSWDS filename = bb_path_shadow_file; rc = update_passwd(bb_path_shadow_file, name, newp, NULL); - if (rc == 0) /* no lines updated, no errors detected */ + if (rc > 0) + /* password in /etc/shadow was updated */ + newp = (char*) "x"; + if (rc >= 0) + /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ #endif { filename = bb_path_passwd_file; @@ -197,16 +209,17 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) } /* LOGMODE_BOTH */ if (rc < 0) - bb_error_msg_and_die("can't update password file %s", - filename); + bb_error_msg_and_die("can't update password file %s", filename); bb_info_msg("Password for %s changed by %s", name, myname); - //if (ENABLE_FEATURE_CLEAN_UP) free(newp); + /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */ 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); + + if (ENABLE_FEATURE_CLEAN_UP) + free(myname); return 0; } diff --git a/release/src/router/busybox/loginutils/su.c b/release/src/router/busybox/loginutils/su.c index 5bec4bc8b3..57ea738f4c 100644 --- a/release/src/router/busybox/loginutils/su.c +++ b/release/src/router/busybox/loginutils/su.c @@ -8,6 +8,15 @@ #include "libbb.h" #include +//usage:#define su_trivial_usage +//usage: "[OPTIONS] [-] [USER]" +//usage:#define su_full_usage "\n\n" +//usage: "Run shell under USER (by default, root)\n" +//usage: "\n -,-l Clear environment, run shell as login shell" +//usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME" +//usage: "\n -c CMD Command to pass to 'sh -c'" +//usage: "\n -s SH Shell to use instead of user's default" + #if ENABLE_FEATURE_SU_CHECKS_SHELLS /* Return 1 if SHELL is a restricted shell (one not returned by * getusershell), else 0, meaning it is a standard shell. */ @@ -42,7 +51,9 @@ int su_main(int argc UNUSED_PARAM, char **argv) struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; +#if ENABLE_FEATURE_UTMP char user_buf[64]; +#endif const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); @@ -102,20 +113,14 @@ int su_main(int argc UNUSED_PARAM, char **argv) opt_shell = getenv("SHELL"); } - /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER - * is a username that is retrieved via NIS (YP), that doesn't have - * a default shell listed. */ - if (!pw->pw_shell || !pw->pw_shell[0]) - pw->pw_shell = (char *)DEFAULT_SHELL; - #if ENABLE_FEATURE_SU_CHECKS_SHELLS - if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { + if (opt_shell && cur_uid != 0 && pw->pw_shell && 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; + opt_shell = NULL; /* ignore -s PROG */ } /* else: user can run whatever he wants via "su -s PROG USER". * This is safe since PROG is run under user's uid/gid. */ diff --git a/release/src/router/busybox/loginutils/sulogin.c b/release/src/router/busybox/loginutils/sulogin.c index 3075367213..bd2b09eed8 100644 --- a/release/src/router/busybox/loginutils/sulogin.c +++ b/release/src/router/busybox/loginutils/sulogin.c @@ -5,6 +5,12 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define sulogin_trivial_usage +//usage: "[-t N] [TTY]" +//usage:#define sulogin_full_usage "\n\n" +//usage: "Single user login\n" +//usage: "\n -t N Timeout" + #include "libbb.h" #include @@ -88,8 +94,8 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) if (r == 0) { break; } - bb_do_delay(FAIL_DELAY); - bb_error_msg("login incorrect"); + bb_do_delay(LOGIN_FAIL_DELAY); + bb_info_msg("Login incorrect"); } memset(cp, 0, strlen(cp)); // signal(SIGALRM, SIG_DFL); diff --git a/release/src/router/busybox/loginutils/vlock.c b/release/src/router/busybox/loginutils/vlock.c index 216b317f10..75af9390e1 100644 --- a/release/src/router/busybox/loginutils/vlock.c +++ b/release/src/router/busybox/loginutils/vlock.c @@ -15,6 +15,12 @@ /* Fixed by Erik Andersen to do passwords the tinylogin way... * It now works with md5, sha1, etc passwords. */ +//usage:#define vlock_trivial_usage +//usage: "[-a]" +//usage:#define vlock_full_usage "\n\n" +//usage: "Lock a virtual terminal. A password is required to unlock.\n" +//usage: "\n -a Lock all VTs" + #include "libbb.h" #ifdef __linux__ @@ -93,16 +99,17 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) term.c_lflag &= ~(ECHO | ECHOCTL); tcsetattr_stdin_TCSANOW(&term); - do { + while (1) { printf("Virtual console%s locked by %s.\n", - option_mask32 /*o_lock_all*/ ? "s" : "", - pw->pw_name); + /* "s" if -a, else "": */ "s" + !option_mask32, + pw->pw_name + ); if (correct_password(pw)) { break; } - bb_do_delay(FAIL_DELAY); - puts("Password incorrect"); - } while (1); + bb_do_delay(LOGIN_FAIL_DELAY); + puts("Incorrect password"); + } #ifdef __linux__ ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); diff --git a/release/src/router/busybox/mailutils/Kbuild.src b/release/src/router/busybox/mailutils/Kbuild.src index 20220dac87..6b4fb74700 100644 --- a/release/src/router/busybox/mailutils/Kbuild.src +++ b/release/src/router/busybox/mailutils/Kbuild.src @@ -7,7 +7,3 @@ lib-y:= INSERT -lib-$(CONFIG_MAKEMIME) += mime.o mail.o -lib-$(CONFIG_POPMAILDIR) += popmaildir.o mail.o -lib-$(CONFIG_REFORMIME) += mime.o mail.o -lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o diff --git a/release/src/router/busybox/mailutils/mail.c b/release/src/router/busybox/mailutils/mail.c index 9b4bebce53..199f644077 100644 --- a/release/src/router/busybox/mailutils/mail.c +++ b/release/src/router/busybox/mailutils/mail.c @@ -57,10 +57,13 @@ void FAST_FUNC launch_helper(const char **argv) G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 - close(pipes[i + 1]); // 1 or 3 - closing one write end - close(pipes[2 - i]); // 2 or 0 - closing one read end - xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end - xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - other write end + close(pipes[i + 1]); // 1 or 3 - closing one write end + close(pipes[2 - i]); // 2 or 0 - closing one read end + xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end + xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end + // End result: + // parent stdout [3] -> child stdin [2] + // child stdout [1] -> parent stdin [0] if (!G.helper_pid) { // child: try to execute connection helper @@ -75,13 +78,16 @@ void FAST_FUNC launch_helper(const char **argv) atexit(kill_helper); } -const FAST_FUNC char *command(const char *fmt, const char *param) +char* FAST_FUNC send_mail_command(const char *fmt, const char *param) { - const char *msg = fmt; + char *msg; if (timeout) alarm(timeout); - if (msg) { + msg = (char*)fmt; + if (fmt) { msg = xasprintf(fmt, param); + if (verbose) + bb_error_msg("send:'%s'", msg); printf("%s\r\n", msg); } fflush_all(); @@ -90,7 +96,7 @@ const FAST_FUNC char *command(const char *fmt, const char *param) // NB: parse_url can modify url[] (despite const), but only if '@' is there /* -static char FAST_FUNC *parse_url(char *url, char **user, char **pass) +static char* FAST_FUNC parse_url(char *url, char **user, char **pass) { // parse [user[:pass]@]host // return host @@ -113,7 +119,7 @@ static char FAST_FUNC *parse_url(char *url, char **user, char **pass) void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) { enum { - SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ + SRC_BUF_SIZE = 57, /* This *MUST* be a multiple of 3 */ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), }; #define src_buf text @@ -169,8 +175,8 @@ void FAST_FUNC get_cred_or_die(int fd) G.user = xstrdup(bb_ask(fd, /* timeout: */ 0, "User: ")); G.pass = xstrdup(bb_ask(fd, /* timeout: */ 0, "Password: ")); } else { - G.user = xmalloc_reads(fd, /* pfx: */ NULL, /* maxsize: */ NULL); - G.pass = xmalloc_reads(fd, /* pfx: */ NULL, /* maxsize: */ NULL); + G.user = xmalloc_reads(fd, /* maxsize: */ NULL); + G.pass = xmalloc_reads(fd, /* maxsize: */ NULL); } if (!G.user || !*G.user || !G.pass) bb_error_msg_and_die("no username or password"); diff --git a/release/src/router/busybox/mailutils/mail.h b/release/src/router/busybox/mailutils/mail.h index e0048fbfae..fa0c5b3785 100644 --- a/release/src/router/busybox/mailutils/mail.h +++ b/release/src/router/busybox/mailutils/mail.h @@ -1,34 +1,37 @@ +/* vi: set sw=4 ts=4: */ +/* + * helper routines + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ struct globals { pid_t helper_pid; unsigned timeout; + unsigned verbose; unsigned opts; char *user; char *pass; FILE *fp0; // initial stdin char *opt_charset; - char *content_type; }; #define G (*ptr_to_globals) #define timeout (G.timeout ) +#define verbose (G.verbose ) #define opts (G.opts ) -//#define user (G.user ) -//#define pass (G.pass ) -//#define fp0 (G.fp0 ) -//#define opt_charset (G.opt_charset) -//#define content_type (G.content_type) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \ - G.content_type = (char *)"text/plain"; \ } while (0) //char FAST_FUNC *parse_url(char *url, char **user, char **pass); -void FAST_FUNC launch_helper(const char **argv); -void FAST_FUNC get_cred_or_die(int fd); +void launch_helper(const char **argv) FAST_FUNC; +void get_cred_or_die(int fd) FAST_FUNC; -const FAST_FUNC char *command(const char *fmt, const char *param); +char *send_mail_command(const char *fmt, const char *param) FAST_FUNC; -void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); +void encode_base64(char *fname, const char *text, const char *eol) FAST_FUNC; diff --git a/release/src/router/busybox/mailutils/makemime.c b/release/src/router/busybox/mailutils/makemime.c new file mode 100644 index 0000000000..1dadd715f4 --- /dev/null +++ b/release/src/router/busybox/mailutils/makemime.c @@ -0,0 +1,239 @@ +/* vi: set sw=4 ts=4: */ +/* + * makemime: create MIME-encoded message + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-$(CONFIG_MAKEMIME) += makemime.o mail.o + +#include "libbb.h" +#include "mail.h" + +#if 0 +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg_error_msg(...) ((void)0) +#endif + +/* + makemime -c type [-o file] [-e encoding] [-C charset] [-N name] \ + [-a "Header: Contents"] file + -m [ type ] [-o file] [-e encoding] [-a "Header: Contents"] file + -j [-o file] file1 file2 + @file + + file: filename - read or write from filename + - - read or write from stdin or stdout + &n - read or write from file descriptor n + \( opts \) - read from child process, that generates [ opts ] + +Options: + -c type - create a new MIME section from "file" with this + Content-Type: (default is application/octet-stream). + -C charset - MIME charset of a new text/plain section. + -N name - MIME content name of the new mime section. + -m [ type ] - create a multipart mime section from "file" of this + Content-Type: (default is multipart/mixed). + -e encoding - use the given encoding (7bit, 8bit, quoted-printable, + or base64), instead of guessing. Omit "-e" and use + -c auto to set Content-Type: to text/plain or + application/octet-stream based on picked encoding. + -j file1 file2 - join mime section file2 to multipart section file1. + -o file - write the result to file, instead of stdout (not + allowed in child processes). + -a header - prepend an additional header to the output. + + @file - read all of the above options from file, one option or + value on each line. + {which version of makemime is this? What do we support?} +*/ +/* man makemime: + + * -c TYPE: create a (non-multipart) MIME section with Content-Type: TYPE + * makemime -c TYPE [-e ENCODING] [-o OUTFILE] [-C CHARSET] [-N NAME] [-a HEADER...] FILE + * The -C option sets the MIME charset attribute for text/plain content. + * The -N option sets the name attribute for Content-Type: + * Encoding must be one of the following: 7bit, 8bit, quoted-printable, or base64. + + * -m multipart/TYPE: create a multipart MIME collection with Content-Type: multipart/TYPE + * makemime -m multipart/TYPE [-e ENCODING] [-o OUTFILE] [-a HEADER...] FILE + * Type must be either "multipart/mixed", "multipart/alternative", or some other MIME multipart content type. + * Additionally, encoding can only be "7bit" or "8bit", and will default to "8bit" if not specified. + * Finally, filename must be a MIME-formatted section, NOT a regular file. + * The -m option creates an initial multipart MIME collection, that contains only one MIME section, taken from filename. + * The collection is written to standard output, or the pipe or to outputfile. + + * -j FILE1: add a section to a multipart MIME collection + * makemime -j FILE1 [-o OUTFILE] FILE2 + * FILE1 must be a MIME collection that was previously created by the -m option. + * FILE2 must be a MIME section that was previously created by the -c option. + * The -j options adds the MIME section in FILE2 to the MIME collection in FILE1. + */ + + +/* In busybox 1.15.0.svn, makemime generates output like this + * (empty lines are shown exactly!): +{headers added with -a HDR} +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="24269534-2145583448-1655890676" + +--24269534-2145583448-1655890676 +Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} +Content-Disposition: inline; filename="A" +Content-Transfer-Encoding: base64 + +...file A contents... +--24269534-2145583448-1655890676 +Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} +Content-Disposition: inline; filename="B" +Content-Transfer-Encoding: base64 + +...file B contents... +--24269534-2145583448-1655890676-- + + * + * For reference: here is an example email to LKML which has + * 1st unnamed part (so it serves as an email body) + * and one attached file: +...other headers... +Content-Type: multipart/mixed; boundary="=-tOfTf3byOS0vZgxEWcX+" +...other headers... +Mime-Version: 1.0 +...other headers... + + +--=-tOfTf3byOS0vZgxEWcX+ +Content-Type: text/plain +Content-Transfer-Encoding: 7bit + +...email text... +...email text... + + +--=-tOfTf3byOS0vZgxEWcX+ +Content-Disposition: attachment; filename="xyz" +Content-Type: text/plain; name="xyz"; charset="UTF-8" +Content-Transfer-Encoding: 7bit + +...file contents... +...file contents... + +--=-tOfTf3byOS0vZgxEWcX+-- + +...random junk added by mailing list robots and such... +*/ + +//usage:#define makemime_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define makemime_full_usage "\n\n" +//usage: "Create multipart MIME-encoded message from FILEs\n" +/* //usage: "Transfer encoding is base64, disposition is inline (not attachment)\n" */ +//usage: "\n -o FILE Output. Default: stdout" +//usage: "\n -a HDR Add header(s). Examples:" +//usage: "\n \"From: user@host.org\", \"Date: `date -R`\"" +//usage: "\n -c CT Content type. Default: application/octet-stream" +//usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET +/* //usage: "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ +//usage: "\n" +//usage: "\nOther options are silently ignored" + +/* + * -c [Content-Type] should create just one MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR". + * NB: without "Content-Disposition:" auto-added, unlike we do now + * NB2: -c has *optional* param which nevertheless _can_ be specified after a space :( + * + * -m [multipart/mixed] should create multipart MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR", + * and add FILE to it _verbatim_: + * HEADERS + * + * --=_1_1321709112_1605 + * FILE_CONTENTS + * --=_1_1321709112_1605 + * without any encoding of FILE_CONTENTS. (Basically, it expects that FILE + * is the result of "makemime -c"). + * + * -j MULTIPART_FILE1 SINGLE_FILE2 should output MULTIPART_FILE1 + SINGLE_FILE2 + * + * Our current behavior is a mutant "-m + -c + -j" one: we create multipart MIME + * and we put "-c" encoded FILEs into many multipart sections. + */ + +int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int makemime_main(int argc UNUSED_PARAM, char **argv) +{ + llist_t *opt_headers = NULL, *l; + const char *opt_output; + const char *content_type = "application/octet-stream"; +#define boundary opt_output + enum { + OPT_c = 1 << 0, // create (non-multipart) section + OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 + OPT_o = 1 << 2, // output to + OPT_C = 1 << 3, // charset + OPT_N = 1 << 4, // COMPAT + OPT_a = 1 << 5, // additional headers + //OPT_m = 1 << 6, // create mutipart section + //OPT_j = 1 << 7, // join section to multipart section + }; + + INIT_G(); + + // parse options + opt_complementary = "a::"; + opts = getopt32(argv, + "c:e:o:C:N:a:", // "m:j:", + &content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL + ); + //argc -= optind; + argv += optind; + + // respect -o output + if (opts & OPT_o) + freopen(opt_output, "w", stdout); + + // no files given on command line? -> use stdin + if (!*argv) + *--argv = (char *)"-"; + + // put additional headers + for (l = opt_headers; l; l = l->link) + puts(l->data); + + // make a random string -- it will delimit message parts + srand(monotonic_us()); + boundary = xasprintf("%u-%u-%u", + (unsigned)rand(), (unsigned)rand(), (unsigned)rand()); + + // put multipart header + printf( + "Mime-Version: 1.0\n" + "Content-Type: multipart/mixed; boundary=\"%s\"\n" + , boundary + ); + + // put attachments + while (*argv) { + printf( + "\n--%s\n" + "Content-Type: %s; charset=%s\n" + "Content-Disposition: inline; filename=\"%s\"\n" + "Content-Transfer-Encoding: base64\n" + , boundary + , content_type + , G.opt_charset + , bb_get_last_path_component_strip(*argv) + ); + encode_base64(*argv++, (const char *)stdin, ""); + } + + // put multipart footer + printf("\n--%s--\n" "\n", boundary); + + return EXIT_SUCCESS; +#undef boundary +} diff --git a/release/src/router/busybox/mailutils/popmaildir.c b/release/src/router/busybox/mailutils/popmaildir.c index 77ec71129a..62030331e0 100644 --- a/release/src/router/busybox/mailutils/popmaildir.c +++ b/release/src/router/busybox/mailutils/popmaildir.c @@ -9,14 +9,50 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//kbuild:lib-$(CONFIG_POPMAILDIR) += popmaildir.o mail.o + +//usage:#define popmaildir_trivial_usage +//usage: "[OPTIONS] MAILDIR [CONN_HELPER ARGS]" +//usage:#define popmaildir_full_usage "\n\n" +//usage: "Fetch content of remote mailbox to local maildir\n" +/* //usage: "\n -b Binary mode. Ignored" */ +/* //usage: "\n -d Debug. Ignored" */ +/* //usage: "\n -m Show used memory. Ignored" */ +/* //usage: "\n -V Show version. Ignored" */ +/* //usage: "\n -c Use tcpclient. Ignored" */ +/* //usage: "\n -a Use APOP protocol. Implied. If server supports APOP -> use it" */ +//usage: "\n -s Skip authorization" +//usage: "\n -T Get messages with TOP instead of RETR" +//usage: "\n -k Keep retrieved messages on the server" +//usage: "\n -t SEC Network timeout" +//usage: IF_FEATURE_POPMAILDIR_DELIVERY( +//usage: "\n -F \"PROG ARGS\" Filter program (may be repeated)" +//usage: "\n -M \"PROG ARGS\" Delivery program" +//usage: ) +//usage: "\n" +//usage: "\nFetch from plain POP3 server:" +//usage: "\npopmaildir -k DIR nc pop3.server.com 110 = BYTES. Ignored" */ +/* //usage: "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" */ +/* //usage: "\n -L BYTES Don't retrieve new messages >= BYTES. Ignored" */ +/* //usage: "\n -H LINES Type first LINES of a message. Ignored" */ +//usage: +//usage:#define popmaildir_example_usage +//usage: "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [ + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-$(CONFIG_REFORMIME) += reformime.o mail.o + +#include "libbb.h" +#include "mail.h" + +#if 0 +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg_error_msg(...) ((void)0) +#endif + +static const char *find_token(const char *const string_array[], const char *key, const char *defvalue) +{ + const char *r = NULL; + int i; + for (i = 0; string_array[i] != NULL; i++) { + if (strcasecmp(string_array[i], key) == 0) { + r = (char *)string_array[i+1]; + break; + } + } + return (r) ? r : defvalue; +} + +static const char *xfind_token(const char *const string_array[], const char *key) +{ + const char *r = find_token(string_array, key, NULL); + if (r) + return r; + bb_error_msg_and_die("not found: '%s'", key); +} + +enum { + OPT_x = 1 << 0, + OPT_X = 1 << 1, +#if ENABLE_FEATURE_REFORMIME_COMPAT + OPT_d = 1 << 2, + OPT_e = 1 << 3, + OPT_i = 1 << 4, + OPT_s = 1 << 5, + OPT_r = 1 << 6, + OPT_c = 1 << 7, + OPT_m = 1 << 8, + OPT_h = 1 << 9, + OPT_o = 1 << 10, + OPT_O = 1 << 11, +#endif +}; + +static int parse(const char *boundary, char **argv) +{ + int boundary_len = strlen(boundary); + char uniq[sizeof("%%llu.%u") + sizeof(int)*3]; + + dbg_error_msg("BOUNDARY[%s]", boundary); + + // prepare unique string pattern + sprintf(uniq, "%%llu.%u", (unsigned)getpid()); + dbg_error_msg("UNIQ[%s]", uniq); + + while (1) { + char *header; + const char *tokens[32]; /* 32 is enough */ + const char *type; + + /* Read the header (everything up to two \n) */ + { + unsigned header_idx = 0; + int last_ch = 0; + header = NULL; + while (1) { + int ch = fgetc(stdin); + if (ch == '\r') /* Support both line endings */ + continue; + if (ch == EOF) + break; + if (ch == '\n' && last_ch == ch) + break; + if (!(header_idx & 0xff)) + header = xrealloc(header, header_idx + 0x101); + header[header_idx++] = last_ch = ch; + } + if (!header) { + dbg_error_msg("EOF"); + break; + } + header[header_idx] = '\0'; + dbg_error_msg("H:'%s'", p); + } + + /* Split to tokens */ + { + char *s, *p; + unsigned ntokens; + const char *delims = ";=\" \t\n"; + + /* Skip to last Content-Type: */ + s = p = header; + while ((p = strchr(p, '\n')) != NULL) { + p++; + if (strncasecmp(p, "Content-Type:", sizeof("Content-Type:")-1) == 0) + s = p; + } + dbg_error_msg("L:'%s'", p); + ntokens = 0; + s = strtok(s, delims); + while (s) { + tokens[ntokens] = s; + if (ntokens < ARRAY_SIZE(tokens) - 1) + ntokens++; + dbg_error_msg("L[%d]='%s'", ntokens, s); + s = strtok(NULL, delims); + } + tokens[ntokens] = NULL; + dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens); + if (ntokens == 0) + break; + } + + /* Is it multipart? */ + type = find_token(tokens, "Content-Type:", "text/plain"); + dbg_error_msg("TYPE:'%s'", type); + if (0 == strncasecmp(type, "multipart/", 10)) { + /* Yes, recurse */ + if (strcasecmp(type + 10, "mixed") != 0) + bb_error_msg_and_die("no support of content type '%s'", type); + parse(xfind_token(tokens, "boundary"), argv); + + } else { + /* No, process one non-multipart section */ + char *end; + pid_t pid = pid; + FILE *fp; + + const char *charset = find_token(tokens, "charset", CONFIG_FEATURE_MIME_CHARSET); + const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit"); + + /* Compose target filename */ + char *filename = (char *)find_token(tokens, "filename", NULL); + if (!filename) + filename = xasprintf(uniq, monotonic_us()); + else + filename = bb_get_last_path_component_strip(xstrdup(filename)); + + if (opts & OPT_X) { + int fd[2]; + + /* start external helper */ + xpipe(fd); + pid = vfork(); + if (0 == pid) { + /* child reads from fd[0] */ + close(fd[1]); + xmove_fd(fd[0], STDIN_FILENO); + xsetenv("CONTENT_TYPE", type); + xsetenv("CHARSET", charset); + xsetenv("ENCODING", encoding); + xsetenv("FILENAME", filename); + BB_EXECVP_or_die(argv); + } + /* parent will write to fd[1] */ + close(fd[0]); + fp = xfdopen_for_write(fd[1]); + signal(SIGPIPE, SIG_IGN); + } else { + /* write to file */ + char *fname = xasprintf("%s%s", *argv, filename); + fp = xfopen_for_write(fname); + free(fname); + } + free(filename); + + /* write to fp */ + end = NULL; + if (0 == strcasecmp(encoding, "base64")) { + read_base64(stdin, fp, '-'); + } else + if (0 != strcasecmp(encoding, "7bit") + && 0 != strcasecmp(encoding, "8bit") + ) { + /* quoted-printable, binary, user-defined are unsupported so far */ + bb_error_msg_and_die("encoding '%s' not supported", encoding); + } else { + /* plain 7bit or 8bit */ + while ((end = xmalloc_fgets(stdin)) != NULL) { + if ('-' == end[0] + && '-' == end[1] + && strncmp(end + 2, boundary, boundary_len) == 0 + ) { + break; + } + fputs(end, fp); + } + } + fclose(fp); + + /* Wait for child */ + if (opts & OPT_X) { + int rc; + signal(SIGPIPE, SIG_DFL); + rc = (wait4pid(pid) & 0xff); + if (rc != 0) + return rc + 20; + } + + /* Multipart ended? */ + if (end && '-' == end[2 + boundary_len] && '-' == end[2 + boundary_len + 1]) { + dbg_error_msg("FINISHED MPART:'%s'", end); + break; + } + dbg_error_msg("FINISHED:'%s'", end); + free(end); + } /* end of "handle one non-multipart block" */ + + free(header); + } /* while (1) */ + + dbg_error_msg("ENDPARSE[%s]", boundary); + + return EXIT_SUCCESS; +} + +//usage:#define reformime_trivial_usage +//usage: "[OPTIONS]" +//usage:#define reformime_full_usage "\n\n" +//usage: "Parse MIME-encoded message on stdin\n" +//usage: "\n -x PREFIX Extract content of MIME sections to files" +//usage: "\n -X PROG ARGS Filter content of MIME sections through PROG" +//usage: "\n Must be the last option" +//usage: "\n" +//usage: "\nOther options are silently ignored" + +/* +Usage: reformime [options] + -d - parse a delivery status notification. + -e - extract contents of MIME section. + -x - extract MIME section to a file. + -X - pipe MIME section to a program. + -i - show MIME info. + -s n.n.n.n - specify MIME section. + -r - rewrite message, filling in missing MIME headers. + -r7 - also convert 8bit/raw encoding to quoted-printable, if possible. + -r8 - also convert quoted-printable encoding to 8bit, if possible. + -c charset - default charset for rewriting, -o, and -O. + -m [file] [file]... - create a MIME message digest. + -h "header" - decode RFC 2047-encoded header. + -o "header" - encode unstructured header using RFC 2047. + -O "header" - encode address list header using RFC 2047. +*/ + +int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int reformime_main(int argc UNUSED_PARAM, char **argv) +{ + const char *opt_prefix = ""; + + INIT_G(); + + // parse options + // N.B. only -x and -X are supported so far + opt_complementary = "x--X:X--x" IF_FEATURE_REFORMIME_COMPAT(":m::"); + opts = getopt32(argv, + "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"), + &opt_prefix + IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) + ); + argv += optind; + + return parse("", (opts & OPT_X) ? argv : (char **)&opt_prefix); +} diff --git a/release/src/router/busybox/mailutils/sendmail.c b/release/src/router/busybox/mailutils/sendmail.c index ec97cf8afc..aa381c60fe 100644 --- a/release/src/router/busybox/mailutils/sendmail.c +++ b/release/src/router/busybox/mailutils/sendmail.c @@ -6,6 +6,40 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//kbuild:lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o + +//usage:#define sendmail_trivial_usage +//usage: "[OPTIONS] [RECIPIENT_EMAIL]..." +//usage:#define sendmail_full_usage "\n\n" +//usage: "Read email from stdin and send it\n" +//usage: "\nStandard options:" +//usage: "\n -t Read additional recipients from message body" +//usage: "\n -f SENDER Sender (required)" +//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" +//usage: "\n -i -oi synonym. implied and ignored" +//usage: "\n" +//usage: "\nBusybox specific options:" +//usage: "\n -v Verbose" +//usage: "\n -w SECS Network timeout" +//usage: "\n -H 'PROG ARGS' Run connection helper" +//usage: "\n Examples:" +//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" +//usage: "\n -connect smtp.gmail.com:25' die saying msg - while ((answer = xmalloc_fgetline(stdin)) != NULL) + while ((answer = xmalloc_fgetline(stdin)) != NULL) { + if (verbose) + bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer); if (strlen(answer) <= 3 || '-' != answer[3]) break; + free(answer); + } if (answer) { int n = atoi(answer); if (timeout) alarm(0); free(answer); - if (-1 == code || n == code) + if (-1 == code || n == code) { + free(msg); return n; + } } bb_error_msg_and_die("%s failed", msg); } @@ -86,6 +133,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) OPT_H = 1 << 5, // use external connection helper OPT_S = 1 << 6, // specify connection string OPT_a = 1 << 7, // authentication tokens + OPT_v = 1 << 8, // verbosity }; // init global variables @@ -96,12 +144,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) G.fp0 = xfdopen_for_read(3); // parse options - // -f is required. -H and -S are mutually exclusive - opt_complementary = "f:w+:H--S:S--H:a::"; + // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list + opt_complementary = "vv:f:w+:H--S:S--H:a::"; // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, // it is still under development. - opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); + opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, + &timeout, &opt_connect, &opt_connect, &list, &verbose); //argc -= optind; argv += optind; @@ -128,11 +177,35 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) const char *args[] = { "sh", "-c", opt_connect, NULL }; // plug it in launch_helper(args); - // vanilla connection + // Now: + // our stdout will go to helper's stdin, + // helper's stdout will be available on our stdin. + + // Wait for initial server message. + // If helper (such as openssl) invokes STARTTLS, the initial 220 + // is swallowed by helper (and not repeated after TLS is initiated). + // We will send NOOP cmd to server and check the response. + // We should get 220+250 on plain connection, 250 on STARTTLSed session. + // + // The problem here is some servers delay initial 220 message, + // and consider client to be a spammer if it starts sending cmds + // before 220 reached it. The code below is unsafe in this regard: + // in non-STARTTLSed case, we potentially send NOOP before 220 + // is sent by server. + // Ideas? (--delay SECS opt? --assume-starttls-helper opt?) + code = smtp_check("NOOP", -1); + if (code == 220) + // we got 220 - this is not STARTTLSed connection, + // eat 250 response to our NOOP + smtp_check(NULL, 250); + else + if (code != 250) + bb_error_msg_and_die("SMTP init failed"); } else { + // vanilla connection int fd; // host[:port] not explicitly specified? -> use $SMTPHOST - // no $SMTPHOST ? -> use localhost + // no $SMTPHOST? -> use localhost if (!(opts & OPT_S)) { opt_connect = getenv("SMTPHOST"); if (!opt_connect) @@ -143,25 +216,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // and make ourselves a simple IO filter xmove_fd(fd, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); - } - // N.B. from now we know nothing about network :) - // wait for initial server OK - // N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure - // so we need to kick the server to see whether we are ok - code = smtp_check("NOOP", -1); - // 220 on plain connection, 250 on openssl-helped TLS session - if (220 == code) - smtp_check(NULL, 250); // reread the code to stay in sync - else if (250 != code) - bb_error_msg_and_die("INIT failed"); + // Wait for initial server 220 message + smtp_check(NULL, 220); + } // we should start with modern EHLO - if (250 != smtp_checkp("EHLO %s", domain, -1)) { + if (250 != smtp_checkp("EHLO %s", domain, -1)) smtp_checkp("HELO %s", domain, 250); - } - if (ENABLE_FEATURE_CLEAN_UP) - free(domain); // perform authentication if (opts & OPT_a) { @@ -176,7 +238,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) } // set sender - // N.B. we have here a very loosely defined algotythm + // N.B. we have here a very loosely defined algorythm // since sendmail historically offers no means to specify secrets on cmdline. // 1) server can require no authentication -> // we must just provide a (possibly fake) reply address. @@ -193,8 +255,6 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // G.user = xuid2uname(getuid()); // opt_from = xasprintf("%s@%s", G.user, domain); //} - //if (ENABLE_FEATURE_CLEAN_UP) - // free(domain); smtp_checkp("MAIL FROM:<%s>", opt_from, 250); // process message @@ -214,36 +274,38 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) if ('.' == s[0] /*&& '\0' == s[1] */) printf("."); // dump read line - printf("%s\r\n", s); + send_r_n(s); free(s); continue; } // analyze headers // To: or Cc: headers add recipients - if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { - rcptto(sane_address(s+3)); - goto addheader; - // Bcc: header adds blind copy (hidden) recipient - } else if (0 == strncasecmp("Bcc:", s, 4)) { - rcptto(sane_address(s+4)); - free(s); - // N.B. Bcc: vanishes from headers! - - // other headers go verbatim - - // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. - // Continuation is denoted by prefixing additional lines with whitespace(s). - // Thanks (stefan.seyfried at googlemail.com) for pointing this out. - } else if (strchr(s, ':') || (list && skip_whitespace(s) != s)) { + if (opts & OPT_t) { + if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { + rcptto(sane_address(s+3)); + goto addheader; + } + // Bcc: header adds blind copy (hidden) recipient + if (0 == strncasecmp("Bcc:", s, 4)) { + rcptto(sane_address(s+4)); + free(s); + continue; // N.B. Bcc: vanishes from headers! + } + } + if (strchr(s, ':') || (list && isspace(s[0]))) { + // other headers go verbatim + // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. + // Continuation is denoted by prefixing additional lines with whitespace(s). + // Thanks (stefan.seyfried at googlemail.com) for pointing this out. addheader: // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) goto bail; llist_add_to_end(&list, s); - // a line without ":" (an empty line too, by definition) doesn't look like a valid header - // so stop "analyze headers" mode } else { + // a line without ":" (an empty line too, by definition) doesn't look like a valid header + // so stop "analyze headers" mode reenter: // put recipients specified on cmdline while (*argv) { @@ -261,14 +323,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) goto bail; // dump the headers while (list) { - printf("%s\r\n", (char *) llist_pop(&list)); + send_r_n((char *) llist_pop(&list)); } // stop analyzing headers code++; // N.B. !s means: we read nothing, and nothing to be read in the future. // just dump empty line and break the loop if (!s) { - puts("\r"); + send_r_n(""); break; } // go dump message body diff --git a/release/src/router/busybox/miscutils/Config.src b/release/src/router/busybox/miscutils/Config.src index da52e14c6b..b9fc196d8d 100644 --- a/release/src/router/busybox/miscutils/Config.src +++ b/release/src/router/busybox/miscutils/Config.src @@ -10,7 +10,7 @@ INSERT config ADJTIMEX bool "adjtimex" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Adjtimex reads and optionally sets adjustment parameters for the Linux clock adjustment algorithm. @@ -39,7 +39,7 @@ config FEATURE_COMPRESS_BBCONFIG config BEEP bool "beep" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help The beep applets beeps in a given freq/Hz. @@ -194,7 +194,7 @@ config FEATURE_DC_LIBM config DEVFSD bool "devfsd (obsolete)" default n - depends on PLATFORM_LINUX + select PLATFORM_LINUX select FEATURE_SYSLOG help This is deprecated and should NOT be used anymore. @@ -238,7 +238,7 @@ config DEVFSD_VERBOSE config FEATURE_DEVFS bool "Use devfs names for all devices (obsolete)" default n - depends on PLATFORM_LINUX + select PLATFORM_LINUX help This is obsolete and should NOT be used anymore. Use linux >= 2.6 (optionally with hotplug) and mdev instead! @@ -258,7 +258,7 @@ config DEVMEM config EJECT bool "eject" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Used to eject cdroms. (defaults to /dev/cdrom) @@ -273,7 +273,7 @@ config FEATURE_EJECT_SCSI config FBSPLASH bool "fbsplash" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Shows splash image and progress bar on framebuffer device. Can be used during boot phase of an embedded device. ~2kb. @@ -323,7 +323,7 @@ config FLASH_ERASEALL config IONICE bool "ionice" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Set/set program io scheduling class and priority Requires kernel >= 2.6.13 @@ -360,76 +360,10 @@ config FEATURE_LAST_FANCY logged into the system (mimics sysvinit last). +900 bytes. endchoice -config LESS - bool "less" - default y - 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_MARKS - bool "Enable marks" - default y - 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 y - depends on LESS - help - Enable regular expressions, allowing complex file searches. - -config FEATURE_LESS_WINCH - bool "Enable automatic resizing on window size changes" - default y - depends on LESS - help - Makes less track window size changes. - -config FEATURE_LESS_DASHCMD - bool "Enable flag changes ('-' command)" - default y - depends on LESS - help - This enables the ability to change command-line flags within - less itself ('-' keyboard command). - -config FEATURE_LESS_LINENUMS - bool "Enable dynamic switching of line numbers" - default y - depends on FEATURE_LESS_DASHCMD - help - Enables "-N" command. - config HDPARM bool "hdparm" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Get/Set hard drive parameters. Primarily intended for ATA drives. Adds about 13k (or around 30k if you enable the @@ -546,7 +480,7 @@ config MT config RAIDAUTORUN bool "raidautorun" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help raidautorun tells the kernel md driver to search and start RAID arrays. @@ -554,7 +488,8 @@ config RAIDAUTORUN config READAHEAD bool "readahead" default y - depends on LFS && PLATFORM_LINUX + depends on LFS + select PLATFORM_LINUX 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. @@ -571,7 +506,7 @@ config READAHEAD config RFKILL bool "rfkill" default n # doesn't build on Ubuntu 9.04 - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Enable/disable wireless devices. @@ -583,6 +518,7 @@ config RFKILL config RUNLEVEL bool "runlevel" default y + depends on FEATURE_UTMP help find the current and previous system runlevel. @@ -592,7 +528,7 @@ config RUNLEVEL config RX bool "rx" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Receive files using the Xmodem protocol. @@ -658,13 +594,14 @@ config VOLNAME config WALL bool "wall" default y + depends on FEATURE_UTMP help Write a message to all users that are logged in. config WATCHDOG bool "watchdog" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help The watchdog utility is used with hardware or software watchdog device drivers. It opens the specified watchdog device special file diff --git a/release/src/router/busybox/miscutils/adjtimex.c b/release/src/router/busybox/miscutils/adjtimex.c index 8e8ff8c0a6..c8816e9e7c 100644 --- a/release/src/router/busybox/miscutils/adjtimex.c +++ b/release/src/router/busybox/miscutils/adjtimex.c @@ -11,8 +11,23 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define adjtimex_trivial_usage +//usage: "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]" +//usage:#define adjtimex_full_usage "\n\n" +//usage: "Read and optionally set system timebase parameters. See adjtimex(2)\n" +//usage: "\n -q Quiet" +//usage: "\n -o OFF Time offset, microseconds" +//usage: "\n -f FREQ Frequency adjust, integer kernel units (65536 is 1ppm)" +//usage: "\n (positive values make clock run faster)" +//usage: "\n -t TICK Microseconds per tick, usually 10000" +//usage: "\n -p TCONST" + #include "libbb.h" -#include +#ifdef __BIONIC__ +# include +#else +# include +#endif static const uint16_t statlist_bit[] = { STA_PLL, diff --git a/release/src/router/busybox/miscutils/bbconfig.c b/release/src/router/busybox/miscutils/bbconfig.c index 7c30669a33..e5f4eb379f 100644 --- a/release/src/router/busybox/miscutils/bbconfig.c +++ b/release/src/router/busybox/miscutils/bbconfig.c @@ -1,10 +1,16 @@ /* vi: set sw=4 ts=4: */ /* This file was released into the public domain by Paul Fox. */ + +//usage:#define bbconfig_trivial_usage +//usage: "" +//usage:#define bbconfig_full_usage "\n\n" +//usage: "Print the config file used by busybox build" + #include "libbb.h" #include "bbconfigopts.h" #if ENABLE_FEATURE_COMPRESS_BBCONFIG -# include "archive.h" +# include "bb_archive.h" # include "bbconfigopts_bz2.h" #endif diff --git a/release/src/router/busybox/miscutils/beep.c b/release/src/router/busybox/miscutils/beep.c index 013a72543e..910e03e1b4 100644 --- a/release/src/router/busybox/miscutils/beep.c +++ b/release/src/router/busybox/miscutils/beep.c @@ -7,6 +7,16 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. * */ + +//usage:#define beep_trivial_usage +//usage: "-f FREQ -l LEN -d DELAY -r COUNT -n" +//usage:#define beep_full_usage "\n\n" +//usage: " -f Frequency in Hz" +//usage: "\n -l Length in ms" +//usage: "\n -d Delay in ms" +//usage: "\n -r Repetitions" +//usage: "\n -n Start new tone" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/chat.c b/release/src/router/busybox/miscutils/chat.c index d8370a9633..ce994f870f 100644 --- a/release/src/router/busybox/miscutils/chat.c +++ b/release/src/router/busybox/miscutils/chat.c @@ -7,6 +7,15 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define chat_trivial_usage +//usage: "EXPECT [SEND [EXPECT [SEND...]]]" +//usage:#define chat_full_usage "\n\n" +//usage: "Useful for interacting with a modem connected to stdin/stdout.\n" +//usage: "A script consists of one or more \"expect-send\" pairs of strings,\n" +//usage: "each pair is a pair of arguments. Example:\n" +//usage: "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" + #include "libbb.h" // default timeout: 45 sec diff --git a/release/src/router/busybox/miscutils/chrt.c b/release/src/router/busybox/miscutils/chrt.c index c40277b393..91b5397c48 100644 --- a/release/src/router/busybox/miscutils/chrt.c +++ b/release/src/router/busybox/miscutils/chrt.c @@ -5,6 +5,22 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define chrt_trivial_usage +//usage: "[-prfom] [PRIO] [PID | PROG ARGS]" +//usage:#define chrt_full_usage "\n\n" +//usage: "Change scheduling priority and class for a process\n" +//usage: "\n -p Operate on PID" +//usage: "\n -r Set SCHED_RR class" +//usage: "\n -f Set SCHED_FIFO class" +//usage: "\n -o Set SCHED_OTHER class" +//usage: "\n -m Show min/max priorities" +//usage: +//usage:#define chrt_example_usage +//usage: "$ chrt -r 4 sleep 900; x=$!\n" +//usage: "$ chrt -f -p 3 $x\n" +//usage: "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" + #include #include "libbb.h" #ifndef _POSIX_PRIORITY_SCHEDULING @@ -53,23 +69,25 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) 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"; + /* only one policy accepted */ + opt_complementary = "r--fo:f--ro:o--rf"; opt = getopt32(argv, "+mprfo"); + if (opt & OPT_m) { /* print min/max and exit */ + show_min_max(SCHED_FIFO); + show_min_max(SCHED_RR); + show_min_max(SCHED_OTHER); + fflush_stdout_and_exit(EXIT_SUCCESS); + } 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 (!argv[0]) + bb_show_usage(); if (opt & OPT_p) { pid_str = *argv++; if (*argv) { /* "-p [...]" */ @@ -90,13 +108,13 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) print_rt_info: pol = sched_getscheduler(pid); if (pol < 0) - bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid); + bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)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); + bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid); printf("pid %d's %s scheduling priority: %d\n", - pid, current_new, sp.sched_priority); + (int)pid, current_new, sp.sched_priority); if (!*argv) { /* Either it was just "-p ", * or it was "-p " and we came here @@ -115,7 +133,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) 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); + bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid); if (!argv[0]) /* "-p [...]" */ goto print_rt_info; diff --git a/release/src/router/busybox/miscutils/conspy.c b/release/src/router/busybox/miscutils/conspy.c index 723b4208ae..1a46a4340a 100644 --- a/release/src/router/busybox/miscutils/conspy.c +++ b/release/src/router/busybox/miscutils/conspy.c @@ -10,14 +10,14 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_CONSPY(APPLET(conspy, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_CONSPY) += conspy.o //config:config CONSPY //config: bool "conspy" -//config: default n -//config: depends on PLATFORM_LINUX +//config: default y +//config: select PLATFORM_LINUX //config: help //config: A text-mode VNC like program for Linux virtual terminals. //config: example: conspy NUM shared access to console num @@ -25,26 +25,31 @@ //config: or conspy -cs NUM poor man's GNU screen like //usage:#define conspy_trivial_usage -//usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" +//usage: "[-vcsndfFQ] [-x COL] [-y LINE] [CONSOLE_NO]" //usage:#define conspy_full_usage "\n\n" //usage: "A text-mode VNC like program for Linux virtual consoles." //usage: "\nTo exit, quickly press ESC 3 times." //usage: "\n" -//usage: "\nOptions:" //usage: "\n -v Don't send keystrokes to the console" -//usage: "\n -c Create missing devices in /dev" +//usage: "\n -c Create missing /dev/{tty,vcsa}N" //usage: "\n -s Open a SHELL session" //usage: "\n -n Black & white" //usage: "\n -d Dump console to stdout" //usage: "\n -f Follow cursor" +//usage: "\n -F Assume console is on a framebuffer device" +//usage: "\n -Q Disable exit on ESC-ESC-ESC" //usage: "\n -x COL Starting column" //usage: "\n -y LINE Starting line" #include "libbb.h" #include - #define ESC "\033" +#define CURSOR_ON -1 +#define CURSOR_OFF 1 + +#define DEV_TTY "/dev/tty" +#define DEV_VCSA "/dev/vcsa" struct screen_info { unsigned char lines, cols, cursor_x, cursor_y; @@ -73,19 +78,17 @@ struct globals { unsigned col; unsigned line; smallint curoff; // unknown:0 cursor on:-1 cursor off:1 - char attrbuf[sizeof(ESC"[0;1;5;30;40m")]; + char attrbuf[sizeof("0;1;5;30;40m")]; // remote console struct screen_info remote; // saved local tty terminfo struct termios term_orig; - char vcsa_name[sizeof("/dev/vcsaNN")]; + char vcsa_name[sizeof(DEV_VCSA "NN")]; }; #define G (*ptr_to_globals) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ - G.attrbuf[0] = '\033'; \ - G.attrbuf[1] = '['; \ G.width = G.height = UINT_MAX; \ G.last_attr--; \ } while (0) @@ -93,18 +96,26 @@ struct globals { enum { FLAG_v, // view only FLAG_c, // create device if need + FLAG_Q, // never exit FLAG_s, // session FLAG_n, // no colors FLAG_d, // dump screen FLAG_f, // follow cursor + FLAG_F, // framebuffer }; #define FLAG(x) (1 << FLAG_##x) #define BW (option_mask32 & FLAG(n)) +static void putcsi(const char *s) +{ + fputs(ESC"[", stdout); + fputs(s, stdout); +} + static void clrscr(void) { // Home, clear till end of screen - fputs(ESC"[1;1H" ESC"[J", stdout); + putcsi("1;1H" ESC"[J"); G.col = G.line = 0; } @@ -112,7 +123,7 @@ static void set_cursor(int state) { if (G.curoff != state) { G.curoff = state; - fputs(ESC"[?25", stdout); + putcsi("?25"); bb_putchar("h?l"[1 + state]); } } @@ -126,18 +137,19 @@ static void gotoxy(int col, int line) } } +static void cleanup(int code) NORETURN; static void cleanup(int code) { - set_cursor(-1); // cursor on + set_cursor(CURSOR_ON); tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); if (ENABLE_FEATURE_CLEAN_UP) { close(G.kbd_fd); } // Reset attributes if (!BW) - fputs(ESC"[0m", stdout); + putcsi("0m"); bb_putchar('\n'); - if (code > 1) + if (code > EXIT_FAILURE) kill_myself_with_sig(code); exit(code); } @@ -158,8 +170,8 @@ static void screen_read_close(void) G.size = i; G.data = xzalloc(2 * i); } - else if (G.size != i) { - cleanup(1); + if (G.size != i) { + cleanup(EXIT_FAILURE); } data = G.data + G.current; xread(vcsa_fd, data, G.size); @@ -169,10 +181,15 @@ static void screen_read_close(void) unsigned x = j - G.x; // if will catch j < G.x too unsigned y = i - G.y; // if will catch i < G.y too - if (CHAR(data) < ' ') - CHAR(data) = ' '; if (y >= G.height || x >= G.width) DATA(data) = 0; + else { + uint8_t ch = CHAR(data); + if (ch < ' ') + CHAR(data) = ch | 0x40; + else if (ch > 0x7e) + CHAR(data) = '?'; + } } } } @@ -180,10 +197,13 @@ static void screen_read_close(void) static void screen_char(char *data) { if (!BW) { + uint8_t attr_diff; uint8_t attr = ATTR(data); - //uint8_t attr = ATTR(data) >> 1; // for framebuffer console - uint8_t attr_diff = G.last_attr ^ attr; + if (option_mask32 & FLAG(F)) { + attr >>= 1; + } + attr_diff = G.last_attr ^ attr; if (attr_diff) { // Attribute layout for VGA compatible text videobuffer: // blinking text @@ -214,7 +234,7 @@ static void screen_char(char *data) const uint8_t bg_mask = 0x70, blink_mask = 0x80; char *ptr; - ptr = G.attrbuf + 2; // skip "ESC [" + ptr = G.attrbuf; // (G.last_attr & ~attr) has 1 only where // G.last_attr has 1 but attr has 0. @@ -245,12 +265,12 @@ static void screen_char(char *data) if (attr_diff & bg_mask) { *ptr++ = '4'; *ptr++ = color[(attr & bg_mask) >> 4]; - *ptr++ = ';'; + ptr++; // last attribute } - if (ptr != G.attrbuf + 2) { + if (ptr != G.attrbuf) { ptr[-1] = 'm'; *ptr = '\0'; - fputs(G.attrbuf, stdout); + putcsi(G.attrbuf); } } } @@ -293,11 +313,11 @@ static void curmove(void) { unsigned cx = G.remote.cursor_x - G.x; unsigned cy = G.remote.cursor_y - G.y; - int cursor = 1; + int cursor = CURSOR_OFF; if (cx < G.width && cy < G.height) { gotoxy(cx, cy); - cursor = -1; + cursor = CURSOR_ON; } set_cursor(cursor); } @@ -316,10 +336,8 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int pid = xvfork(); if (pid == 0) { struct termios termchild; - char *shell = getenv("SHELL"); + const char *shell = get_shell_name(); - if (!shell) - shell = (char *) DEFAULT_SHELL; signal(SIGHUP, SIG_IGN); // set tty as a controlling tty setsid(); @@ -344,7 +362,7 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { - char tty_name[sizeof("/dev/ttyNN")]; + char tty_name[sizeof(DEV_TTY "NN")]; #define keybuf bb_common_bufsiz1 struct termios termbuf; unsigned opts; @@ -354,26 +372,28 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) static const char getopt_longopts[] ALIGN1 = "viewonly\0" No_argument "v" "createdevice\0" No_argument "c" + "neverquit\0" No_argument "Q" "session\0" No_argument "s" "nocolors\0" No_argument "n" "dump\0" No_argument "d" "follow\0" No_argument "f" + "framebuffer\0" No_argument "F" ; applet_long_options = getopt_longopts; #endif INIT_G(); - strcpy(G.vcsa_name, "/dev/vcsa"); + strcpy(G.vcsa_name, DEV_VCSA); opt_complementary = "x+:y+"; // numeric params - opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); + opts = getopt32(argv, "vcQsndfFx:y:", &G.x, &G.y); argv += optind; ttynum = 0; if (argv[0]) { ttynum = xatou_range(argv[0], 0, 63); - sprintf(G.vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); + sprintf(G.vcsa_name + sizeof(DEV_VCSA)-1, "%u", ttynum); } - sprintf(tty_name, "%s%u", "/dev/tty", ttynum); + sprintf(tty_name, "%s%u", DEV_TTY, ttynum); if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); @@ -484,7 +504,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) char *k; case -1: if (errno != EINTR) - cleanup(1); + goto abort; break; case 0: if (++G.nokeys >= 4) @@ -495,32 +515,36 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) k = keybuf + G.key_count; bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); if (bytes_read < 0) - cleanup(1); + goto abort; // Do exit processing - for (i = 0; i < bytes_read; i++) { - if (k[i] != '\033') - G.escape_count = 0; - else if (++G.escape_count >= 3) - cleanup(0); + if (!(option_mask32 & FLAG(Q))) { + for (i = 0; i < bytes_read; i++) { + if (k[i] != '\033') + G.escape_count = -1; + if (++G.escape_count >= 3) + cleanup(EXIT_SUCCESS); + } } } poll_timeout_ms = 250; + if (option_mask32 & FLAG(v)) continue; // Insert all keys pressed into the virtual console's input // buffer. Don't do this if the virtual console is in scan // code mode - giving ASCII characters to a program expecting // scan codes will confuse it. - if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) { + G.key_count += bytes_read; + if (G.escape_count == 0) { int handle, result; long kbd_mode; - G.key_count += bytes_read; handle = xopen(tty_name, O_WRONLY); result = ioctl(handle, KDGKBMODE, &kbd_mode); if (result >= 0) { char *p = keybuf; + G.ioerror_count = 0; if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) { G.key_count = 0; // scan code mode } @@ -536,16 +560,18 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) poll_timeout_ms = 20; } } + // We sometimes get spurious IO errors on the TTY + // as programs close and re-open it + else if (errno != EIO || ++G.ioerror_count > 4) { + if (ENABLE_FEATURE_CLEAN_UP) + close(handle); + goto abort; + } // Close & re-open tty in case they have // swapped virtual consoles close(handle); - - // We sometimes get spurious IO errors on the TTY - // as programs close and re-open it - if (result >= 0) - G.ioerror_count = 0; - else if (errno != EIO || ++G.ioerror_count > 4) - cleanup(1); } } /* while (1) */ + abort: + cleanup(EXIT_FAILURE); } diff --git a/release/src/router/busybox/miscutils/crond.c b/release/src/router/busybox/miscutils/crond.c index 5bf0536092..a0b73c7749 100644 --- a/release/src/router/busybox/miscutils/crond.c +++ b/release/src/router/busybox/miscutils/crond.c @@ -11,6 +11,19 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define crond_trivial_usage +//usage: "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" +//usage:#define crond_full_usage "\n\n" +//usage: " -f Foreground" +//usage: "\n -b Background (default)" +//usage: "\n -S Log to syslog (default)" +//usage: "\n -l Set log level. 0 is the most verbose, default 8" +//usage: IF_FEATURE_CROND_D( +//usage: "\n -d Set log level, log to stderr" +//usage: ) +//usage: "\n -L Log to file" +//usage: "\n -c Working dir" + #include "libbb.h" #include @@ -848,7 +861,8 @@ int crond_main(int argc UNUSED_PARAM, char **argv) /* "-b after -f is ignored", and so on for every pair a-b */ opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") - ":l+:d+"; /* -l and -d have numeric param */ + /* -l and -d have numeric param */ + ":l+" IF_FEATURE_CROND_D(":d+"); opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), &G.log_level, &G.log_filename, &G.crontab_dir_name IF_FEATURE_CROND_D(,&G.log_level)); diff --git a/release/src/router/busybox/miscutils/crontab.c b/release/src/router/busybox/miscutils/crontab.c index 163e15dce1..4731d8da60 100644 --- a/release/src/router/busybox/miscutils/crontab.c +++ b/release/src/router/busybox/miscutils/crontab.c @@ -10,6 +10,16 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define crontab_trivial_usage +//usage: "[-c DIR] [-u USER] [-ler]|[FILE]" +//usage:#define crontab_full_usage "\n\n" +//usage: " -c Crontab directory" +//usage: "\n -u User" +//usage: "\n -l List crontab" +//usage: "\n -e Edit crontab" +//usage: "\n -r Delete crontab" +//usage: "\n FILE Replace crontab by FILE ('-': stdin)" + #include "libbb.h" #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" @@ -20,8 +30,9 @@ static void edit_file(const struct passwd *pas, const char *file) { const char *ptr; - int pid = xvfork(); + pid_t pid; + pid = xvfork(); if (pid) { /* parent */ wait4pid(pid); return; @@ -30,7 +41,7 @@ static void edit_file(const struct passwd *pas, const char *file) /* CHILD - change user and run editor */ /* initgroups, setgid, setuid */ change_identity(pas); - setup_environment(DEFAULT_SHELL, + setup_environment(pas->pw_shell, SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP, pas); ptr = getenv("VISUAL"); @@ -41,7 +52,7 @@ static void edit_file(const struct passwd *pas, const char *file) } BB_EXECLP(ptr, ptr, file, NULL); - bb_perror_msg_and_die("exec %s", ptr); + bb_perror_msg_and_die("can't execute '%s'", ptr); } static int open_as_user(const struct passwd *pas, const char *file) diff --git a/release/src/router/busybox/miscutils/dc.c b/release/src/router/busybox/miscutils/dc.c index 777ec1654c..6903761e4f 100644 --- a/release/src/router/busybox/miscutils/dc.c +++ b/release/src/router/busybox/miscutils/dc.c @@ -11,11 +11,11 @@ //usage: //usage:#define dc_full_usage "\n\n" //usage: "Tiny RPN calculator. Operations:\n" -//usage: "+, add, -, sub, *, mul, /, div, %, mod, **, exp, and, or, not, eor,\n" +//usage: "+, add, -, sub, *, mul, /, div, %, mod, "IF_FEATURE_DC_LIBM("**, exp, ")"and, or, not, eor,\n" //usage: "p - print top of the stack (without popping),\n" //usage: "f - print entire stack,\n" //usage: "o - pop the value and set output radix (must be 10, 16, 8 or 2).\n" -//usage: "Examples: 'dc 2 2 add' -> 4, 'dc 8 8 * 2 2 + /' -> 16" +//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 * 2 2 + / p' -> 16" //usage: //usage:#define dc_example_usage //usage: "$ dc 2 2 + p\n" @@ -245,19 +245,6 @@ static void stack_machine(const char *argument) bb_error_msg_and_die("syntax error at '%s'", 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 UNUSED_PARAM, char **argv) { @@ -272,16 +259,18 @@ int dc_main(int argc UNUSED_PARAM, char **argv) while ((line = xmalloc_fgetline(stdin)) != NULL) { cursor = line; while (1) { - token = get_token(&cursor); - if (!token) + token = skip_whitespace(cursor); + if (*token == '\0') break; - *cursor++ = '\0'; + cursor = skip_non_whitespace(token); + if (*cursor != '\0') + *cursor++ = '\0'; stack_machine(token); } free(line); } } else { - // why? it breaks "dc -2 2 * p" + // why? it breaks "dc -2 2 + p" //if (argv[0][0] == '-') // bb_show_usage(); do { diff --git a/release/src/router/busybox/miscutils/devfsd.c b/release/src/router/busybox/miscutils/devfsd.c index 35e4319519..6493fe4f1c 100644 --- a/release/src/router/busybox/miscutils/devfsd.c +++ b/release/src/router/busybox/miscutils/devfsd.c @@ -53,6 +53,21 @@ The postal address is: Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. */ + +//usage:#define devfsd_trivial_usage +//usage: "mntpnt [-v]" IF_DEVFSD_FG_NP("[-fg][-np]") +//usage:#define devfsd_full_usage "\n\n" +//usage: "Manage devfs permissions and old device name symlinks\n" +//usage: "\n mntpnt The mount point where devfs is mounted" +//usage: "\n -v Print the protocol version numbers for devfsd" +//usage: "\n and the kernel-side protocol version and exit" +//usage: IF_DEVFSD_FG_NP( +//usage: "\n -fg Run in foreground" +//usage: "\n -np Exit after parsing the configuration file" +//usage: "\n and processing synthetic REGISTER events," +//usage: "\n don't poll for events" +//usage: ) + #include "libbb.h" #include "xregex.h" #include diff --git a/release/src/router/busybox/miscutils/devmem.c b/release/src/router/busybox/miscutils/devmem.c index 7a9f533af4..786a21bee0 100644 --- a/release/src/router/busybox/miscutils/devmem.c +++ b/release/src/router/busybox/miscutils/devmem.c @@ -4,6 +4,14 @@ * Copyright (C) 2008, BusyBox Team. -solar 4/26/08 */ +//usage:#define devmem_trivial_usage +//usage: "ADDRESS [WIDTH [VALUE]]" +//usage:#define devmem_full_usage "\n\n" +//usage: "Read/write from physical address\n" +//usage: "\n ADDRESS Address to act upon" +//usage: "\n WIDTH Width (8/16/...)" +//usage: "\n VALUE Data to be written" + #include "libbb.h" int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/eject.c b/release/src/router/busybox/miscutils/eject.c index 63d20d3ade..a20e04b7f4 100644 --- a/release/src/router/busybox/miscutils/eject.c +++ b/release/src/router/busybox/miscutils/eject.c @@ -13,6 +13,16 @@ * Most of the dirty work blatantly ripped off from cat.c =) */ +//usage:#define eject_trivial_usage +//usage: "[-t] [-T] [DEVICE]" +//usage:#define eject_full_usage "\n\n" +//usage: "Eject DEVICE or default /dev/cdrom\n" +//usage: IF_FEATURE_EJECT_SCSI( +//usage: "\n -s SCSI device" +//usage: ) +//usage: "\n -t Close tray" +//usage: "\n -T Open/close tray (toggle)" + #include #include "libbb.h" /* Must be after libbb.h: they need size_t */ diff --git a/release/src/router/busybox/miscutils/fbsplash.c b/release/src/router/busybox/miscutils/fbsplash.c index 6b84563a35..988439b25a 100644 --- a/release/src/router/busybox/miscutils/fbsplash.c +++ b/release/src/router/busybox/miscutils/fbsplash.c @@ -21,16 +21,24 @@ * "exit" (or just close fifo) - well you guessed it. */ +//usage:#define fbsplash_trivial_usage +//usage: "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" +//usage:#define fbsplash_full_usage "\n\n" +//usage: " -s Image" +//usage: "\n -c Hide cursor" +//usage: "\n -d Framebuffer device (default /dev/fb0)" +//usage: "\n -i Config file (var=value):" +//usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" +//usage: "\n BAR_R,BAR_G,BAR_B" +//usage: "\n -f Control pipe (else exit after drawing image)" +//usage: "\n commands: 'NN' (% for progress bar) or 'exit'" + #include "libbb.h" #include /* 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 @@ -41,6 +49,7 @@ struct globals { const char *image_filename; struct fb_var_screeninfo scr_var; struct fb_fix_screeninfo scr_fix; + unsigned bytes_per_pixel; }; #define G (*ptr_to_globals) #define INIT_G() do { \ @@ -65,9 +74,46 @@ struct globals { #define DEBUG_MESSAGE(...) ((void)0) #endif +/** + * Configure palette for RGB:332 + */ +static void fb_setpal(int fd) +{ + struct fb_cmap cmap; + /* fb colors are 16 bit */ + unsigned short red[256], green[256], blue[256]; + unsigned i; + + /* RGB:332 */ + for (i = 0; i < 256; i++) { + /* Color is encoded in pixel value as rrrgggbb. + * 3-bit color is mapped to 16-bit one as: + * 000 -> 00000000 00000000 + * 001 -> 00100100 10010010 + * ... + * 011 -> 01101101 10110110 + * 100 -> 10010010 01001001 + * ... + * 111 -> 11111111 11111111 + */ + red[i] = (( i >> 5 ) * 0x9249) >> 2; // rrr * 00 10010010 01001001 >> 2 + green[i] = (((i >> 2) & 0x7) * 0x9249) >> 2; // ggg * 00 10010010 01001001 >> 2 + /* 2-bit color is easier: */ + blue[i] = ( i & 0x3) * 0x5555; // bb * 01010101 01010101 + } + + cmap.start = 0; + cmap.len = 256; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = 0; + + xioctl(fd, FBIOPUTCMAP, &cmap); +} /** - * Open and initialize the framebuffer device + * Open and initialize the framebuffer device * \param *strfb_device pointer to framebuffer device */ static void fb_open(const char *strfb_device) @@ -78,59 +124,120 @@ static void fb_open(const char *strfb_device) 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"); + switch (G.scr_var.bits_per_pixel) { + case 8: + fb_setpal(fbfd); + break; + + case 16: + case 24: + case 32: + break; + + default: + bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel); + break; + } + + G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; // 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)*/, + G.scr_var.yres * G.scr_fix.line_length, PROT_WRITE, MAP_SHARED, fbfd, 0); if (G.addr == MAP_FAILED) bb_perror_msg_and_die("mmap"); + + // point to the start of the visible screen + G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel; close(fbfd); } /** - * Draw hollow rectangle on framebuffer + * Return pixel value of the passed RGB color + */ +static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b) +{ + if (G.bytes_per_pixel == 1) { + r = r & 0xe0; // 3-bit red + g = (g >> 3) & 0x1c; // 3-bit green + b = b >> 6; // 2-bit blue + return r + g + b; + } + if (G.bytes_per_pixel == 2) { + r = (r & 0xf8) << 8; // 5-bit red + g = (g & 0xfc) << 3; // 6-bit green + b = b >> 3; // 5-bit blue + return r + g + b; + } + // RGB 888 + return b + (g << 8) + (r << 16); +} + +/** + * Draw pixel on framebuffer + */ +static void fb_write_pixel(unsigned char *addr, unsigned pixel) +{ + switch (G.bytes_per_pixel) { + case 1: + *addr = pixel; + break; + case 2: + *(uint16_t *)addr = pixel; + break; + case 4: + *(uint32_t *)addr = pixel; + break; + default: // 24 bits per pixel + addr[0] = pixel; + addr[1] = pixel >> 8; + addr[2] = pixel >> 16; + } +} + + +/** + * Draw hollow rectangle on framebuffer */ static void fb_drawrectangle(void) { int cnt; - DATA thispix; - DATA *ptr1, *ptr2; + unsigned thispix; + unsigned char *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)); + thispix = fb_pixel_value(nred, ngreen, nblue); // 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); + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; cnt = G.nbar_width - 1; do { - *ptr1++ = thispix; - *ptr2++ = thispix; + fb_write_pixel(ptr1, thispix); + fb_write_pixel(ptr2, thispix); + ptr1 += G.bytes_per_pixel; + ptr2 += G.bytes_per_pixel; } 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); + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; cnt = G.nbar_height - 1; do { - *ptr1 = thispix; ptr1 += G.scr_var.xres; - *ptr2 = thispix; ptr2 += G.scr_var.xres; + fb_write_pixel(ptr1, thispix); + fb_write_pixel(ptr2, thispix); + ptr1 += G.scr_fix.line_length; + ptr2 += G.scr_fix.line_length; } while (--cnt >= 0); } /** - * Draw filled rectangle on framebuffer + * Draw filled rectangle on framebuffer * \param nx1pos,ny1pos upper left position * \param nx2pos,ny2pos down right position * \param nred,ngreen,nblue rgb color @@ -139,21 +246,19 @@ 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; + unsigned thispix; + unsigned char *ptr; - nred >>= 3; // 5-bit red - ngreen >>= 2; // 6-bit green - nblue >>= 3; // 5-bit blue - thispix = nblue + (ngreen << 5) + (nred << (5+6)); + thispix = fb_pixel_value(nred, ngreen, nblue); cnt1 = ny2pos - ny1pos; nypos = ny1pos; do { - ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL); + ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel; cnt2 = nx2pos - nx1pos; do { - *ptr++ = thispix; + fb_write_pixel(ptr, thispix); + ptr += G.bytes_per_pixel; } while (--cnt2 >= 0); nypos++; @@ -162,19 +267,20 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, /** - * Draw a progress bar on framebuffer + * 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; + int left_x, top_y, pos_x; + unsigned 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) + if ((int)(height | width) < 0) return; // NB: "width" of 1 actually makes rect with width of 2! fb_drawrectangle(); @@ -184,35 +290,42 @@ static void fb_drawprogressbar(unsigned percent) top_y++; width -= 2; height -= 2; - if ((height | width) < 0) + if ((int)(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); + pos_x = left_x; if (percent > 0) { + int y; + unsigned i; + // actual progress bar - width = width * percent / 100; + pos_x += (unsigned)(width * percent) / 100; + + y = top_y; 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; + unsigned gray_level = 100 + i*100 / height; fb_drawfullrectangle( - left_x, top_y, left_x + width, top_y, + left_x, y, pos_x, y, gray_level, gray_level, gray_level); - top_y++; + y++; i--; } } + + fb_drawfullrectangle( + pos_x, top_y, + left_x + width, top_y + height, + G.nbar_colr, G.nbar_colg, G.nbar_colb); } /** - * Draw image from PPM file + * Draw image from PPM file */ static void fb_drawimage(void) { @@ -273,18 +386,16 @@ static void fb_drawimage(void) height = G.scr_var.yres; for (j = 0; j < height; j++) { unsigned char *pixel; - DATA *src; + unsigned char *src; if (fread(pixline, 1, line_size, theme_file) != line_size) bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); pixel = pixline; - src = (DATA *)(G.addr + j * G.scr_fix.line_length); + src = G.addr + j * G.scr_fix.line_length; 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; + unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]); + fb_write_pixel(src, thispix); + src += G.bytes_per_pixel; pixel += 3; } } @@ -294,7 +405,7 @@ static void fb_drawimage(void) /** - * Parse configuration file + * Parse configuration file * \param *cfg_filename name of the configuration file */ static void init(const char *cfg_filename) diff --git a/release/src/router/busybox/miscutils/flash_eraseall.c b/release/src/router/busybox/miscutils/flash_eraseall.c index 68596e11b0..0598371d55 100644 --- a/release/src/router/busybox/miscutils/flash_eraseall.c +++ b/release/src/router/busybox/miscutils/flash_eraseall.c @@ -10,6 +10,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define flash_eraseall_trivial_usage +//usage: "[-jq] MTD_DEVICE" +//usage:#define flash_eraseall_full_usage "\n\n" +//usage: "Erase an MTD device\n" +//usage: "\n -j Format the device for jffs2" +//usage: "\n -q Don't display progress messages" + #include "libbb.h" #include #include diff --git a/release/src/router/busybox/miscutils/flash_lock_unlock.c b/release/src/router/busybox/miscutils/flash_lock_unlock.c index fcb836b075..1fefd95f99 100644 --- a/release/src/router/busybox/miscutils/flash_lock_unlock.c +++ b/release/src/router/busybox/miscutils/flash_lock_unlock.c @@ -3,6 +3,18 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define flash_lock_trivial_usage +//usage: "MTD_DEVICE OFFSET SECTORS" +//usage:#define flash_lock_full_usage "\n\n" +//usage: "Lock part or all of an MTD device. If SECTORS is -1, then all sectors\n" +//usage: "will be locked, regardless of the value of OFFSET" +//usage: +//usage:#define flash_unlock_trivial_usage +//usage: "MTD_DEVICE" +//usage:#define flash_unlock_full_usage "\n\n" +//usage: "Unlock an MTD device" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/flashcp.c b/release/src/router/busybox/miscutils/flashcp.c index fe37c39135..790f9c01f8 100644 --- a/release/src/router/busybox/miscutils/flashcp.c +++ b/release/src/router/busybox/miscutils/flashcp.c @@ -7,6 +7,12 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define flashcp_trivial_usage +//usage: "-v FILE MTD_DEVICE" +//usage:#define flashcp_full_usage "\n\n" +//usage: "Copy an image to MTD device\n" +//usage: "\n -v Verbose" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/hdparm.c b/release/src/router/busybox/miscutils/hdparm.c index 38b265d60a..a97f3e7b59 100644 --- a/release/src/router/busybox/miscutils/hdparm.c +++ b/release/src/router/busybox/miscutils/hdparm.c @@ -11,6 +11,57 @@ * hdparm.c - Command line interface to get/set hard disk parameters * - by Mark Lord (C) 1994-2002 -- freely distributable */ + +//usage:#define hdparm_trivial_usage +//usage: "[OPTIONS] [DEVICE]" +//usage:#define hdparm_full_usage "\n\n" +//usage: " -a Get/set fs readahead" +//usage: "\n -A Set drive read-lookahead flag (0/1)" +//usage: "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)" +//usage: "\n -B Set Advanced Power Management setting (1-255)" +//usage: "\n -c Get/set IDE 32-bit IO setting" +//usage: "\n -C Check IDE power mode status" +//usage: IF_FEATURE_HDPARM_HDIO_GETSET_DMA( +//usage: "\n -d Get/set using_dma flag") +//usage: "\n -D Enable/disable drive defect-mgmt" +//usage: "\n -f Flush buffer cache for device on exit" +//usage: "\n -g Display drive geometry" +//usage: "\n -h Display terse usage information" +//usage: IF_FEATURE_HDPARM_GET_IDENTITY( +//usage: "\n -i Display drive identification") +//usage: IF_FEATURE_HDPARM_GET_IDENTITY( +//usage: "\n -I Detailed/current information directly from drive") +//usage: "\n -k Get/set keep_settings_over_reset flag (0/1)" +//usage: "\n -K Set drive keep_features_over_reset flag (0/1)" +//usage: "\n -L Set drive doorlock (0/1) (removable harddisks only)" +//usage: "\n -m Get/set multiple sector count" +//usage: "\n -n Get/set ignore-write-errors flag (0/1)" +//usage: "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)" +//usage: "\n -P Set drive prefetch count" +/* //usage: "\n -q Change next setting quietly" - not supported ib bbox */ +//usage: "\n -Q Get/set DMA tagged-queuing depth (if supported)" +//usage: "\n -r Get/set readonly flag (DANGEROUS to set)" +//usage: IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( +//usage: "\n -R Register an IDE interface (DANGEROUS)") +//usage: "\n -S Set standby (spindown) timeout" +//usage: "\n -t Perform device read timings" +//usage: "\n -T Perform cache read timings" +//usage: "\n -u Get/set unmaskirq flag (0/1)" +//usage: IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( +//usage: "\n -U Unregister an IDE interface (DANGEROUS)") +//usage: "\n -v Defaults; same as -mcudkrag for IDE drives" +//usage: "\n -V Display program version and exit immediately" +//usage: IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( +//usage: "\n -w Perform device reset (DANGEROUS)") +//usage: "\n -W Set drive write-caching flag (0/1) (DANGEROUS)" +//usage: IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( +//usage: "\n -x Tristate device for hotswap (0/1) (DANGEROUS)") +//usage: "\n -X Set IDE xfer mode (DANGEROUS)" +//usage: "\n -y Put IDE drive in standby mode" +//usage: "\n -Y Put IDE drive to sleep" +//usage: "\n -Z Disable Seagate auto-powersaving mode" +//usage: "\n -z Reread partition table" + #include "libbb.h" /* must be _after_ libbb.h: */ #include @@ -382,6 +433,7 @@ struct BUG_G_too_big { #define hwif_data (G.hwif_data ) #define hwif_ctrl (G.hwif_ctrl ) #define hwif_irq (G.hwif_irq ) +#define INIT_G() do { } while (0) /* Busybox messages and functions */ @@ -2008,6 +2060,8 @@ int hdparm_main(int argc, char **argv) int c; int flagcount = 0; + INIT_G(); + while ((c = getopt(argc, argv, hdparm_options)) >= 0) { flagcount++; IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I')); diff --git a/release/src/router/busybox/miscutils/inotifyd.c b/release/src/router/busybox/miscutils/inotifyd.c index fe429b6364..7a1a6a2e53 100644 --- a/release/src/router/busybox/miscutils/inotifyd.c +++ b/release/src/router/busybox/miscutils/inotifyd.c @@ -27,6 +27,34 @@ * See below for mask names explanation. */ +//usage:#define inotifyd_trivial_usage +//usage: "PROG FILE1[:MASK]..." +//usage:#define inotifyd_full_usage "\n\n" +//usage: "Run PROG on filesystem changes." +//usage: "\nWhen a filesystem event matching MASK occurs on FILEn," +//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." +//usage: "\nIf PROG is -, events are sent to stdout." +//usage: "\nEvents:" +//usage: "\n a File is accessed" +//usage: "\n c File is modified" +//usage: "\n e Metadata changed" +//usage: "\n w Writable file is closed" +//usage: "\n 0 Unwritable file is closed" +//usage: "\n r File is opened" +//usage: "\n D File is deleted" +//usage: "\n M File is moved" +//usage: "\n u Backing fs is unmounted" +//usage: "\n o Event queue overflowed" +//usage: "\n x File can't be watched anymore" +//usage: "\nIf watching a directory:" +//usage: "\n m Subfile is moved into dir" +//usage: "\n y Subfile is moved out of dir" +//usage: "\n n Subfile is created" +//usage: "\n d Subfile is deleted" +//usage: "\n" +//usage: "\ninotifyd waits for PROG to exit." +//usage: "\nWhen x event happens for all FILEs, inotifyd exits." + #include "libbb.h" #include @@ -150,12 +178,20 @@ int inotifyd_main(int argc, char **argv) *s++ = mask_names[i]; } *s = '\0'; -// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], -// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); - args[1] = events; - args[2] = watches[ie->wd]; - args[3] = ie->len ? ie->name : NULL; - spawn_and_wait((char **)args); + if (LONE_CHAR(args[0], '-')) { + /* "inotifyd - FILE": built-in echo */ + printf(ie->len ? "%s\t%s\t%s\n" : "%s\t%s\n", events, + watches[ie->wd], + ie->name); + fflush(stdout); + } else { +// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], +// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); + args[1] = events; + args[2] = watches[ie->wd]; + args[3] = ie->len ? ie->name : NULL; + spawn_and_wait((char **)args); + } // we are done if all files got final x event if (ie->mask & 0x8000) { if (--argc <= 0) diff --git a/release/src/router/busybox/miscutils/ionice.c b/release/src/router/busybox/miscutils/ionice.c index 481a738ee4..bd300605fd 100644 --- a/release/src/router/busybox/miscutils/ionice.c +++ b/release/src/router/busybox/miscutils/ionice.c @@ -7,6 +7,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ionice_trivial_usage +//usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG]" +//usage:#define ionice_full_usage "\n\n" +//usage: "Change I/O priority and class\n" +//usage: "\n -c Class. 1:realtime 2:best-effort 3:idle" +//usage: "\n -n Priority" + #include #include #include "libbb.h" diff --git a/release/src/router/busybox/miscutils/last.c b/release/src/router/busybox/miscutils/last.c index fec5b70a8c..d527803743 100644 --- a/release/src/router/busybox/miscutils/last.c +++ b/release/src/router/busybox/miscutils/last.c @@ -7,8 +7,17 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define last_trivial_usage +//usage: ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]") +//usage:#define last_full_usage "\n\n" +//usage: "Show listing of the last users that logged into the system" +//usage: IF_FEATURE_LAST_FANCY( "\n" +/* //usage: "\n -H Show header line" */ +//usage: "\n -W Display with no host column truncation" +//usage: "\n -f FILE Read from FILE instead of /var/log/wtmp" +//usage: ) + #include "libbb.h" -#include /* NB: ut_name and ut_user are the same field, use only one name (ut_user) * to reduce confusion */ diff --git a/release/src/router/busybox/miscutils/last_fancy.c b/release/src/router/busybox/miscutils/last_fancy.c index 7e69fc2811..dc09b65fb6 100644 --- a/release/src/router/busybox/miscutils/last_fancy.c +++ b/release/src/router/busybox/miscutils/last_fancy.c @@ -8,7 +8,6 @@ */ #include "libbb.h" -#include /* NB: ut_name and ut_user are the same field, use only one name (ut_user) * to reduce confusion */ @@ -162,11 +161,10 @@ int last_main(int argc UNUSED_PARAM, char **argv) time_t boot_time; time_t down_time; int file; - unsigned opt; smallint going_down; smallint boot_down; - opt = getopt32(argv, "Wf:" /* "H" */, &filename); + /*opt =*/ getopt32(argv, "Wf:" /* "H" */, &filename); #ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT if (opt & LAST_OPT_H) { /* Print header line */ diff --git a/release/src/router/busybox/miscutils/less.c b/release/src/router/busybox/miscutils/less.c index 9e12c11a72..f0187bf8ae 100644 --- a/release/src/router/busybox/miscutils/less.c +++ b/release/src/router/busybox/miscutils/less.c @@ -21,6 +21,95 @@ * redirected input has been read from stdin */ +//config:config LESS +//config: bool "less" +//config: default y +//config: help +//config: 'less' is a pager, meaning that it displays text files. It possesses +//config: a wide array of features, and is an improvement over 'more'. +//config: +//config:config FEATURE_LESS_MAXLINES +//config: int "Max number of input lines less will try to eat" +//config: default 9999999 +//config: depends on LESS +//config: +//config:config FEATURE_LESS_BRACKETS +//config: bool "Enable bracket searching" +//config: default y +//config: depends on LESS +//config: help +//config: This option adds the capability to search for matching left and right +//config: brackets, facilitating programming. +//config: +//config:config FEATURE_LESS_FLAGS +//config: bool "Enable -m/-M" +//config: default y +//config: depends on LESS +//config: help +//config: The -M/-m flag enables a more sophisticated status line. +//config: +//config:config FEATURE_LESS_MARKS +//config: bool "Enable marks" +//config: default y +//config: depends on LESS +//config: help +//config: Marks enable positions in a file to be stored for easy reference. +//config: +//config:config FEATURE_LESS_REGEXP +//config: bool "Enable regular expressions" +//config: default y +//config: depends on LESS +//config: help +//config: Enable regular expressions, allowing complex file searches. +//config: +//config:config FEATURE_LESS_WINCH +//config: bool "Enable automatic resizing on window size changes" +//config: default y +//config: depends on LESS +//config: help +//config: Makes less track window size changes. +//config: +//config:config FEATURE_LESS_ASK_TERMINAL +//config: bool "Use 'tell me cursor position' ESC sequence to measure window" +//config: default y +//config: depends on FEATURE_LESS_WINCH +//config: help +//config: Makes less track window size changes. +//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, +//config: this option makes less perform a last-ditch effort to find it: +//config: position cursor to 999,999 and ask terminal to report real +//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. +//config: +//config: This is not clean but helps a lot on serial lines and such. +//config: +//config:config FEATURE_LESS_DASHCMD +//config: bool "Enable flag changes ('-' command)" +//config: default y +//config: depends on LESS +//config: help +//config: This enables the ability to change command-line flags within +//config: less itself ('-' keyboard command). +//config: +//config:config FEATURE_LESS_LINENUMS +//config: bool "Enable dynamic switching of line numbers" +//config: default y +//config: depends on FEATURE_LESS_DASHCMD +//config: help +//config: Enables "-N" command. + +//usage:#define less_trivial_usage +//usage: "[-E" IF_FEATURE_LESS_FLAGS("Mm") "Nh~I?] [FILE]..." +//usage:#define less_full_usage "\n\n" +//usage: "View FILE (or stdin) one screenful at a time\n" +//usage: "\n -E Quit once the end of a file is reached" +//usage: IF_FEATURE_LESS_FLAGS( +//usage: "\n -M,-m Display status line with line numbers" +//usage: "\n and percentage through the file" +//usage: ) +//usage: "\n -N Prefix line number to each line" +//usage: "\n -I Ignore case in all searches" +//usage: "\n -~ Suppress ~s displayed past EOF" + #include /* sched_yield() */ #include "libbb.h" @@ -97,6 +186,9 @@ struct globals { regex_t pattern; smallint pattern_valid; #endif +#if ENABLE_FEATURE_LESS_ASK_TERMINAL + smallint winsize_err; +#endif smallint terminated; struct termios term_orig, term_less; char kbd_input[KEYCODE_BUFFER_SIZE]; @@ -628,8 +720,8 @@ static void print_found(const char *line) while (match_status == 0) { char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL, growline ? growline : "", - match_structs.rm_so, str, - match_structs.rm_eo - match_structs.rm_so, + (int)match_structs.rm_so, str, + (int)(match_structs.rm_eo - match_structs.rm_so), str + match_structs.rm_so); free(growline); growline = new; @@ -804,12 +896,17 @@ static void reinitialize(void) cur_fline = 0; max_lineno = 0; open_file_and_read_lines(); +#if ENABLE_FEATURE_LESS_ASK_TERMINAL + if (G.winsize_err) + printf("\033[999;999H" "\033[6n"); +#endif buffer_fill_and_print(); } -static int getch_nowait(void) +static int64_t getch_nowait(void) { int rd; + int64_t key64; struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; @@ -857,8 +954,8 @@ static int getch_nowait(void) /* We have kbd_fd in O_NONBLOCK mode, read inside read_key() * would not block even if there is no input available */ - rd = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); - if (rd == -1) { + key64 = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); + if ((int)key64 == -1) { if (errno == EAGAIN) { /* No keyboard input available. Since poll() did return, * we should have input on stdin */ @@ -870,25 +967,30 @@ static int getch_nowait(void) less_exit(0); } set_tty_cooked(); - return rd; + return key64; } /* Grab a character from input without requiring the return key. * May return KEYCODE_xxx values. * Note that this function works best with raw input. */ -static int less_getch(int pos) +static int64_t less_getch(int pos) { - int i; + int64_t key64; + int key; again: less_gets_pos = pos; - i = getch_nowait(); + key = key64 = getch_nowait(); less_gets_pos = -1; - /* Discard Ctrl-something chars */ - if (i >= 0 && i < ' ' && i != 0x0d && i != 8) + /* Discard Ctrl-something chars. + * (checking only lower 32 bits is a size optimization: + * upper 32 bits are used only by KEYCODE_CURSOR_POS) + */ + if (key >= 0 && key < ' ' && key != 0x0d && key != 8) goto again; - return i; + + return key64; } static char* less_gets(int sz) @@ -1428,6 +1530,9 @@ static void keypress_process(int keypress) break; #endif case 'r': case 'R': + /* TODO: (1) also bind ^R, ^L to this? + * (2) re-measure window size? + */ buffer_print(); break; /*case 'R': @@ -1503,8 +1608,6 @@ static void sigwinch_handler(int sig UNUSED_PARAM) 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 */ @@ -1547,7 +1650,7 @@ int less_main(int argc, char **argv) term_less.c_cc[VMIN] = 1; term_less.c_cc[VTIME] = 0; - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) 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); @@ -1562,11 +1665,14 @@ int less_main(int argc, char **argv) buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); reinitialize(); while (1) { + int64_t keypress; + #if ENABLE_FEATURE_LESS_WINCH while (WINCH_COUNTER) { again: winch_counter--; - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(got_size:) /* 20: two tabstops + 4 */ if (width < 20) width = 20; @@ -1586,8 +1692,18 @@ int less_main(int argc, char **argv) /* This took some time. Loop back and check, * were there another SIGWINCH? */ } -#endif keypress = less_getch(-1); /* -1: do not position cursor */ +# if ENABLE_FEATURE_LESS_ASK_TERMINAL + if ((int32_t)keypress == KEYCODE_CURSOR_POS) { + uint32_t rc = (keypress >> 32); + width = (rc & 0x7fff); + max_displayed_line = ((rc >> 16) & 0x7fff); + goto got_size; + } +# endif +#else + keypress = less_getch(-1); /* -1: do not position cursor */ +#endif keypress_process(keypress); } } diff --git a/release/src/router/busybox/miscutils/makedevs.c b/release/src/router/busybox/miscutils/makedevs.c index e74c47c35c..c945a1352c 100644 --- a/release/src/router/busybox/miscutils/makedevs.c +++ b/release/src/router/busybox/miscutils/makedevs.c @@ -7,6 +7,66 @@ * known bugs: can't deal with alpha ranges */ +//usage:#if ENABLE_FEATURE_MAKEDEVS_LEAF +//usage:#define makedevs_trivial_usage +//usage: "NAME TYPE MAJOR MINOR FIRST LAST [s]" +//usage:#define makedevs_full_usage "\n\n" +//usage: "Create a range of block or character special files" +//usage: "\n" +//usage: "\nTYPE is:" +//usage: "\n b Block device" +//usage: "\n c Character device" +//usage: "\n f FIFO, MAJOR and MINOR are ignored" +//usage: "\n" +//usage: "\nFIRST..LAST specify numbers appended to NAME." +//usage: "\nIf 's' is the last argument, the base device is created as well." +//usage: "\n" +//usage: "\nExamples:" +//usage: "\n makedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63" +//usage: "\n makedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" +//usage: +//usage:#define makedevs_example_usage +//usage: "# makedevs /dev/ttyS c 4 66 2 63\n" +//usage: "[creates ttyS2-ttyS63]\n" +//usage: "# makedevs /dev/hda b 3 0 0 8 s\n" +//usage: "[creates hda,hda1-hda8]\n" +//usage:#endif +//usage: +//usage:#if ENABLE_FEATURE_MAKEDEVS_TABLE +//usage:#define makedevs_trivial_usage +//usage: "[-d device_table] rootdir" +//usage:#define makedevs_full_usage "\n\n" +//usage: "Create a range of special files as specified in a device table.\n" +//usage: "Device table entries take the form of:\n" +//usage: " \n" +//usage: "Where name is the file name, type can be one of:\n" +//usage: " f Regular file\n" +//usage: " d Directory\n" +//usage: " c Character device\n" +//usage: " b Block device\n" +//usage: " p Fifo (named pipe)\n" +//usage: "uid is the user id for the target file, gid is the group id for the\n" +//usage: "target file. The rest of the entries (major, minor, etc) apply to\n" +//usage: "to device special files. A '-' may be used for blank entries." +//usage: +//usage:#define makedevs_example_usage +//usage: "For example:\n" +//usage: " \n" +//usage: "/dev d 755 0 0 - - - - -\n" +//usage: "/dev/console c 666 0 0 5 1 - - -\n" +//usage: "/dev/null c 666 0 0 1 3 0 0 -\n" +//usage: "/dev/zero c 666 0 0 1 5 0 0 -\n" +//usage: "/dev/hda b 640 0 0 3 0 0 0 -\n" +//usage: "/dev/hda b 640 0 0 3 1 1 1 15\n\n" +//usage: "Will Produce:\n" +//usage: "/dev\n" +//usage: "/dev/console\n" +//usage: "/dev/null\n" +//usage: "/dev/zero\n" +//usage: "/dev/hda\n" +//usage: "/dev/hda[0-15]\n" +//usage:#endif + #include "libbb.h" #if ENABLE_FEATURE_MAKEDEVS_LEAF diff --git a/release/src/router/busybox/miscutils/man.c b/release/src/router/busybox/miscutils/man.c index b356e726fc..e380fdabaf 100644 --- a/release/src/router/busybox/miscutils/man.c +++ b/release/src/router/busybox/miscutils/man.c @@ -3,6 +3,13 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define man_trivial_usage +//usage: "[-aw] [MANPAGE]..." +//usage:#define man_full_usage "\n\n" +//usage: "Format and display manual page\n" +//usage: "\n -a Display all pages" +//usage: "\n -w Show page locations" + #include "libbb.h" enum { @@ -23,16 +30,6 @@ echo ".pl \n(nlu+10" */ -#if ENABLE_FEATURE_SEAMLESS_LZMA -#define Z_SUFFIX ".lzma" -#elif ENABLE_FEATURE_SEAMLESS_BZ2 -#define Z_SUFFIX ".bz2" -#elif ENABLE_FEATURE_SEAMLESS_GZ -#define Z_SUFFIX ".gz" -#else -#define Z_SUFFIX "" -#endif - static int show_manpage(const char *pager, char *man_filename, int man, int level); static int run_pipe(const char *pager, char *man_filename, int man, int level) @@ -95,7 +92,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) /* Links do not have .gz extensions, even if manpage * is compressed */ - man_filename = xasprintf("%s/%s" Z_SUFFIX, man_filename, linkname); + man_filename = xasprintf("%s/%s", man_filename, linkname); free(line); /* Note: we leak "new" man_filename string as well... */ if (show_manpage(pager, man_filename, man, level + 1)) @@ -117,37 +114,36 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) return 1; } -/* man_filename is of the form "/dir/dir/dir/name.s" Z_SUFFIX */ +/* man_filename is of the form "/dir/dir/dir/name.s" */ static int show_manpage(const char *pager, char *man_filename, int man, int level) { -#if ENABLE_FEATURE_SEAMLESS_LZMA - if (run_pipe(pager, man_filename, man, level)) - return 1; +#if SEAMLESS_COMPRESSION + /* We leak this allocation... */ + char *filename_with_zext = xasprintf("%s.lzma", man_filename); + char *ext = strrchr(filename_with_zext, '.') + 1; #endif -#if ENABLE_FEATURE_SEAMLESS_BZ2 #if ENABLE_FEATURE_SEAMLESS_LZMA - strcpy(strrchr(man_filename, '.') + 1, "bz2"); -#endif - if (run_pipe(pager, man_filename, man, level)) + if (run_pipe(pager, filename_with_zext, man, level)) return 1; #endif - -#if ENABLE_FEATURE_SEAMLESS_GZ -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 - strcpy(strrchr(man_filename, '.') + 1, "gz"); -#endif - if (run_pipe(pager, man_filename, man, level)) +#if ENABLE_FEATURE_SEAMLESS_XZ + strcpy(ext, "xz"); + if (run_pipe(pager, filename_with_zext, man, level)) return 1; #endif - -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 || ENABLE_FEATURE_SEAMLESS_GZ - *strrchr(man_filename, '.') = '\0'; +#if ENABLE_FEATURE_SEAMLESS_BZ2 + strcpy(ext, "bz2"); + if (run_pipe(pager, filename_with_zext, man, level)) + return 1; #endif - if (run_pipe(pager, man_filename, man, level)) +#if ENABLE_FEATURE_SEAMLESS_GZ + strcpy(ext, "gz"); + if (run_pipe(pager, filename_with_zext, man, level)) return 1; +#endif - return 0; + return run_pipe(pager, man_filename, man, level); } int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -255,7 +251,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) /* Search for cat, then man page */ while (cat0man1 < 2) { int found_here; - man_filename = xasprintf("%s/%s%.*s/%s.%.*s" Z_SUFFIX, + man_filename = xasprintf("%s/%s%.*s/%s.%.*s", cur_path, "cat\0man" + (cat0man1 * 4), sect_len, cur_sect, diff --git a/release/src/router/busybox/miscutils/microcom.c b/release/src/router/busybox/miscutils/microcom.c index 3acbe3023c..5e29a1acdd 100644 --- a/release/src/router/busybox/miscutils/microcom.c +++ b/release/src/router/busybox/miscutils/microcom.c @@ -7,6 +7,17 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define microcom_trivial_usage +//usage: "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY" +//usage:#define microcom_full_usage "\n\n" +//usage: "Copy bytes for stdin to TTY and from TTY to stdout\n" +//usage: "\n -d Wait up to DELAY ms for TTY output before sending every" +//usage: "\n next byte to it" +//usage: "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms" +//usage: "\n -s Set serial line to SPEED" +//usage: "\n -X Disable special meaning of NUL and Ctrl-X from stdin" + #include "libbb.h" // set raw tty mode diff --git a/release/src/router/busybox/miscutils/mountpoint.c b/release/src/router/busybox/miscutils/mountpoint.c index 784c3cbfcc..7041f7c59c 100644 --- a/release/src/router/busybox/miscutils/mountpoint.c +++ b/release/src/router/busybox/miscutils/mountpoint.c @@ -9,6 +9,21 @@ * Based on sysvinit's mountpoint */ +//usage:#define mountpoint_trivial_usage +//usage: "[-q] <[-dn] DIR | -x DEVICE>" +//usage:#define mountpoint_full_usage "\n\n" +//usage: "Check if the directory is a mountpoint\n" +//usage: "\n -q Quiet" +//usage: "\n -d Print major/minor device number of the filesystem" +//usage: "\n -n Print device name of the filesystem" +//usage: "\n -x Print major/minor device number of the blockdevice" +//usage: +//usage:#define mountpoint_example_usage +//usage: "$ mountpoint /proc\n" +//usage: "/proc is not a mountpoint\n" +//usage: "$ mountpoint /sys\n" +//usage: "/sys is a mountpoint\n" + #include "libbb.h" int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/mt.c b/release/src/router/busybox/miscutils/mt.c index 142901bb0e..20afd3a50b 100644 --- a/release/src/router/busybox/miscutils/mt.c +++ b/release/src/router/busybox/miscutils/mt.c @@ -3,6 +3,18 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define mt_trivial_usage +//usage: "[-f device] opcode value" +//usage:#define mt_full_usage "\n\n" +//usage: "Control magnetic tape drive operation\n" +//usage: "\n" +//usage: "Available Opcodes:\n" +//usage: "\n" +//usage: "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" +//usage: "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" +//usage: "ras3 reset retension rewind rewoffline seek setblk setdensity\n" +//usage: "setpart tell unload unlock weof wset" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/nandwrite.c b/release/src/router/busybox/miscutils/nandwrite.c index 831d2f76b9..2ba6e3fe55 100644 --- a/release/src/router/busybox/miscutils/nandwrite.c +++ b/release/src/router/busybox/miscutils/nandwrite.c @@ -8,39 +8,37 @@ * TODO: add support for large (>4GB) MTD devices */ -//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nanddump)) - -//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o -//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o - //config:config NANDWRITE //config: bool "nandwrite" -//config: default n -//config: depends on PLATFORM_LINUX +//config: default y +//config: select PLATFORM_LINUX //config: help //config: Write to the specified MTD device, with bad blocks awareness //config: //config:config NANDDUMP //config: bool "nanddump" -//config: default n -//config: depends on PLATFORM_LINUX +//config: default y +//config: select PLATFORM_LINUX //config: help //config: Dump the content of raw NAND chip +//applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) + +//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o +//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o + //usage:#define nandwrite_trivial_usage //usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" //usage:#define nandwrite_full_usage "\n\n" //usage: "Write to the specified MTD device\n" -//usage: "\nOptions:" //usage: "\n -p Pad to page size" //usage: "\n -s ADDR Start address" //usage:#define nanddump_trivial_usage //usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE" //usage:#define nanddump_full_usage "\n\n" -//usage: "Dump the sepcified MTD device\n" -//usage: "\nOptions:" +//usage: "Dump the specified MTD device\n" //usage: "\n -o Omit oob data" //usage: "\n -b Omit bad block from the dump" //usage: "\n -s ADDR Start address" diff --git a/release/src/router/busybox/miscutils/raidautorun.c b/release/src/router/busybox/miscutils/raidautorun.c index bbfa8577ce..b72d89058e 100644 --- a/release/src/router/busybox/miscutils/raidautorun.c +++ b/release/src/router/busybox/miscutils/raidautorun.c @@ -8,6 +8,14 @@ * */ +//usage:#define raidautorun_trivial_usage +//usage: "DEVICE" +//usage:#define raidautorun_full_usage "\n\n" +//usage: "Tell the kernel to automatically search and start RAID arrays" +//usage: +//usage:#define raidautorun_example_usage +//usage: "$ raidautorun /dev/md0" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/readahead.c b/release/src/router/busybox/miscutils/readahead.c index dd6de7c456..e22aaa4688 100644 --- a/release/src/router/busybox/miscutils/readahead.c +++ b/release/src/router/busybox/miscutils/readahead.c @@ -10,6 +10,11 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define readahead_trivial_usage +//usage: "[FILE]..." +//usage:#define readahead_full_usage "\n\n" +//usage: "Preload FILEs to RAM" + #include "libbb.h" int readahead_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/rfkill.c b/release/src/router/busybox/miscutils/rfkill.c index b150b2cae9..4671973713 100644 --- a/release/src/router/busybox/miscutils/rfkill.c +++ b/release/src/router/busybox/miscutils/rfkill.c @@ -6,6 +6,19 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define rfkill_trivial_usage +//usage: "COMMAND [INDEX|TYPE]" +//usage:#define rfkill_full_usage "\n\n" +//usage: "Enable/disable wireless devices\n" +//usage: "\nCommands:" +//usage: "\n list [INDEX|TYPE] List current state" +//usage: "\n block INDEX|TYPE Disable device" +//usage: "\n unblock INDEX|TYPE Enable device" +//usage: "\n" +//usage: "\n TYPE: all, wlan(wifi), bluetooth, uwb(ultrawideband)," +//usage: "\n wimax, wwan, gps, fm" + #include "libbb.h" #include diff --git a/release/src/router/busybox/miscutils/runlevel.c b/release/src/router/busybox/miscutils/runlevel.c index 363e450492..76231df228 100644 --- a/release/src/router/busybox/miscutils/runlevel.c +++ b/release/src/router/busybox/miscutils/runlevel.c @@ -11,8 +11,20 @@ * * initially busyboxified by Bernhard Reutner-Fischer */ + +//usage:#define runlevel_trivial_usage +//usage: "[FILE]" +//usage:#define runlevel_full_usage "\n\n" +//usage: "Find the current and previous system runlevel\n" +//usage: "\n" +//usage: "If no utmp FILE exists or if no runlevel record can be found,\n" +//usage: "print \"unknown\"" +//usage: +//usage:#define runlevel_example_usage +//usage: "$ runlevel /var/run/utmp\n" +//usage: "N 2" + #include "libbb.h" -#include int runlevel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int runlevel_main(int argc UNUSED_PARAM, char **argv) diff --git a/release/src/router/busybox/miscutils/rx.c b/release/src/router/busybox/miscutils/rx.c index de785d53ca..af597320ce 100644 --- a/release/src/router/busybox/miscutils/rx.c +++ b/release/src/router/busybox/miscutils/rx.c @@ -15,6 +15,14 @@ * This was originally written for blob and then adapted for busybox. */ +//usage:#define rx_trivial_usage +//usage: "FILE" +//usage:#define rx_full_usage "\n\n" +//usage: "Receive a file using the xmodem protocol" +//usage: +//usage:#define rx_example_usage +//usage: "$ rx /tmp/foo\n" + #include "libbb.h" #define SOH 0x01 @@ -100,12 +108,10 @@ static int receive(/*int read_fd, */int file_fd) } } /* Write previously received block */ - if (blockLength) { - errno = 0; - if (full_write(file_fd, blockBuf, blockLength) != blockLength) { - bb_perror_msg("can't write to file"); - goto fatal; - } + errno = 0; + if (full_write(file_fd, blockBuf, blockLength) != blockLength) { + bb_perror_msg(bb_msg_write_error); + goto fatal; } timeout = TIMEOUT; @@ -147,23 +153,20 @@ static int receive(/*int read_fd, */int file_fd) blockBuf[i] = cc; } + cksum_or_crc = read_byte(TIMEOUT); + if (cksum_or_crc < 0) + goto timeout; if (do_crc) { - cksum_or_crc = read_byte(TIMEOUT); - if (cksum_or_crc < 0) - goto timeout; cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT); if (cksum_or_crc < 0) goto timeout; - } else { - cksum_or_crc = read_byte(TIMEOUT); - if (cksum_or_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. */ + blockLength = 0; goto next; } if (blockNo != (wantBlockNo & 0xff)) { @@ -204,6 +207,7 @@ static int receive(/*int read_fd, */int file_fd) continue; error: timeout: + blockLength = 0; errors++; if (errors == MAXERRORS) { /* Abort */ diff --git a/release/src/router/busybox/miscutils/setserial.c b/release/src/router/busybox/miscutils/setserial.c new file mode 100644 index 0000000000..2a034e32c0 --- /dev/null +++ b/release/src/router/busybox/miscutils/setserial.c @@ -0,0 +1,763 @@ +/* vi: set sw=4 ts=4: */ +/* + * setserial implementation for busybox + * + * + * Copyright (C) 2011 Marek Bečka + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//config:config SETSERIAL +//config: bool "setserial" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Retrieve or set Linux serial port. + +//applet:IF_SETSERIAL(APPLET(setserial, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o + +#include "libbb.h" +#include + +#ifndef PORT_UNKNOWN +# define PORT_UNKNOWN 0 +#endif +#ifndef PORT_8250 +# define PORT_8250 1 +#endif +#ifndef PORT_16450 +# define PORT_16450 2 +#endif +#ifndef PORT_16550 +# define PORT_16550 3 +#endif +#ifndef PORT_16550A +# define PORT_16550A 4 +#endif +#ifndef PORT_CIRRUS +# define PORT_CIRRUS 5 +#endif +#ifndef PORT_16650 +# define PORT_16650 6 +#endif +#ifndef PORT_16650V2 +# define PORT_16650V2 7 +#endif +#ifndef PORT_16750 +# define PORT_16750 8 +#endif +#ifndef PORT_STARTECH +# define PORT_STARTECH 9 +#endif +#ifndef PORT_16C950 +# define PORT_16C950 10 +#endif +#ifndef PORT_16654 +# define PORT_16654 11 +#endif +#ifndef PORT_16850 +# define PORT_16850 12 +#endif +#ifndef PORT_RSA +# define PORT_RSA 13 +#endif +#ifndef PORT_NS16550A +# define PORT_NS16550A 14 +#endif +#ifndef PORT_XSCALE +# define PORT_XSCALE 15 +#endif +#ifndef PORT_RM9000 +# define PORT_RM9000 16 +#endif +#ifndef PORT_OCTEON +# define PORT_OCTEON 17 +#endif +#ifndef PORT_AR7 +# define PORT_AR7 18 +#endif +#ifndef PORT_U6_16550A +# define PORT_U6_16550A 19 +#endif + +#ifndef ASYNCB_HUP_NOTIFY +# define ASYNCB_HUP_NOTIFY 0 +#endif +#ifndef ASYNCB_FOURPORT +# define ASYNCB_FOURPORT 1 +#endif +#ifndef ASYNCB_SAK +# define ASYNCB_SAK 2 +#endif +#ifndef ASYNCB_SPLIT_TERMIOS +# define ASYNCB_SPLIT_TERMIOS 3 +#endif +#ifndef ASYNCB_SPD_HI +# define ASYNCB_SPD_HI 4 +#endif +#ifndef ASYNCB_SPD_VHI +# define ASYNCB_SPD_VHI 5 +#endif +#ifndef ASYNCB_SKIP_TEST +# define ASYNCB_SKIP_TEST 6 +#endif +#ifndef ASYNCB_AUTO_IRQ +# define ASYNCB_AUTO_IRQ 7 +#endif +#ifndef ASYNCB_SESSION_LOCKOUT +# define ASYNCB_SESSION_LOCKOUT 8 +#endif +#ifndef ASYNCB_PGRP_LOCKOUT +# define ASYNCB_PGRP_LOCKOUT 9 +#endif +#ifndef ASYNCB_CALLOUT_NOHUP +# define ASYNCB_CALLOUT_NOHUP 10 +#endif +#ifndef ASYNCB_SPD_SHI +# define ASYNCB_SPD_SHI 12 +#endif +#ifndef ASYNCB_LOW_LATENCY +# define ASYNCB_LOW_LATENCY 13 +#endif +#ifndef ASYNCB_BUGGY_UART +# define ASYNCB_BUGGY_UART 14 +#endif + +#ifndef ASYNC_HUP_NOTIFY +# define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) +#endif +#ifndef ASYNC_FOURPORT +# define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) +#endif +#ifndef ASYNC_SAK +# define ASYNC_SAK (1U << ASYNCB_SAK) +#endif +#ifndef ASYNC_SPLIT_TERMIOS +# define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) +#endif +#ifndef ASYNC_SPD_HI +# define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI) +#endif +#ifndef ASYNC_SPD_VHI +# define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI) +#endif +#ifndef ASYNC_SKIP_TEST +# define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST) +#endif +#ifndef ASYNC_AUTO_IRQ +# define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ) +#endif +#ifndef ASYNC_SESSION_LOCKOUT +# define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT) +#endif +#ifndef ASYNC_PGRP_LOCKOUT +# define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT) +#endif +#ifndef ASYNC_CALLOUT_NOHUP +# define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP) +#endif +#ifndef ASYNC_SPD_SHI +# define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI) +#endif +#ifndef ASYNC_LOW_LATENCY +# define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) +#endif +#ifndef ASYNC_BUGGY_UART +# define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) +#endif + +#ifndef ASYNC_SPD_CUST +# define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) +#endif +#ifndef ASYNC_SPD_WARP +# define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) +#endif +#ifndef ASYNC_SPD_MASK +# define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) +#endif + +#ifndef ASYNC_CLOSING_WAIT_INF +# define ASYNC_CLOSING_WAIT_INF 0 +#endif +#ifndef ASYNC_CLOSING_WAIT_NONE +# define ASYNC_CLOSING_WAIT_NONE 65535 +#endif + +#ifndef _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 */ +}; +#endif + +//usage:#define setserial_trivial_usage +//usage: "[-gabGvzV] DEVICE [PARAMETER [ARG]]..." +//usage:#define setserial_full_usage "\n\n" +//usage: "Request or set Linux serial port information\n" +//usage: "\n" +//usage: " -g Interpret parameters as list of devices for reporting\n" +//usage: " -a Print all available information\n" +//usage: " -b Print summary information\n" +//usage: " -G Print in form which can be fed back\n" +//usage: " to setserial as command line parameters\n" +//usage: " -z Zero out serial flags before setting\n" +//usage: " -v Verbose\n" +//usage: "\n" +//usage: "Parameters: (* = takes an argument, ^ = can be turned off by preceding ^)\n" +//usage: " *port, *irq, *divisor, *uart, *baund_base, *close_delay, *closing_wait,\n" +//usage: " ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,\n" +//usage: " ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,\n" +//usage: " spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust\n" +//usage: "\n" +//usage: "UART types:\n" +//usage: " unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,\n" +//usage: " 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,\n" +//usage: " U6_16550A" + +#define OPT_PRINT_SUMMARY (1 << 0) +#define OPT_PRINT_FEDBACK (1 << 1) +#define OPT_PRINT_ALL (1 << 2) +#define OPT_VERBOSE (1 << 3) +#define OPT_ZERO (1 << 4) +#define OPT_GET (1 << 5) + +#define OPT_MODE_MASK \ + (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) + +enum print_mode +{ + PRINT_NORMAL = 0, + PRINT_SUMMARY = (1 << 0), + PRINT_FEDBACK = (1 << 1), + PRINT_ALL = (1 << 2), +}; + +#define CTL_SET (1 << 0) +#define CTL_CONFIG (1 << 1) +#define CTL_GET (1 << 2) +#define CTL_CLOSE (1 << 3) +#define CTL_NODIE (1 << 4) + +static const char serial_types[] = + "unknown\0" /* 0 */ + "8250\0" /* 1 */ + "16450\0" /* 2 */ + "16550\0" /* 3 */ + "16550A\0" /* 4 */ + "Cirrus\0" /* 5 */ + "16650\0" /* 6 */ + "16650V2\0" /* 7 */ + "16750\0" /* 8 */ + "16950\0" /* 9 UNIMPLEMENTED: also know as "16950/954" */ + "16954\0" /* 10 */ + "16654\0" /* 11 */ + "16850\0" /* 12 */ + "RSA\0" /* 13 */ +#ifndef SETSERIAL_BASE + "NS16550A\0" /* 14 */ + "XSCALE\0" /* 15 */ + "RM9000\0" /* 16 */ + "OCTEON\0" /* 17 */ + "AR7\0" /* 18 */ + "U6_16550A\0" /* 19 */ +#endif +; + +#ifndef SETSERIAL_BASE +# define MAX_SERIAL_TYPE 19 +#else +# define MAX_SERIAL_TYPE 13 +#endif + +static const char commands[] = + "spd_normal\0" + "spd_hi\0" + "spd_vhi\0" + "spd_shi\0" + "spd_warp\0" + "spd_cust\0" + + "sak\0" + "fourport\0" + "hup_notify\0" + "skip_test\0" + "auto_irq\0" + "split_termios\0" + "session_lockout\0" + "pgrp_lockout\0" + "callout_nohup\0" + "low_latency\0" + + "port\0" + "irq\0" + "divisor\0" + "uart\0" + "baund_base\0" + "close_delay\0" + "closing_wait\0" + + "autoconfig\0" +; + +enum +{ + CMD_SPD_NORMAL = 0, + CMD_SPD_HI, + CMD_SPD_VHI, + CMD_SPD_SHI, + CMD_SPD_WARP, + CMD_SPD_CUST, + + CMD_FLAG_SAK, + CMD_FLAG_FOURPORT, + CMD_FLAG_NUP_NOTIFY, + CMD_FLAG_SKIP_TEST, + CMD_FLAG_AUTO_IRQ, + CMD_FLAG_SPLIT_TERMIOS, + CMD_FLAG_SESSION_LOCKOUT, + CMD_FLAG_PGRP_LOCKOUT, + CMD_FLAG_CALLOUT_NOHUP, + CMD_FLAG_LOW_LATENCY, + + CMD_PORT, + CMD_IRQ, + CMD_DIVISOR, + CMD_UART, + CMD_BASE, + CMD_DELAY, + CMD_WAIT, + + CMD_AUTOCONFIG, + + CMD_FLAG_FIRST = CMD_FLAG_SAK, + CMD_FLAG_LAST = CMD_FLAG_LOW_LATENCY, +}; + +static bool cmd_noprint(int cmd) +{ + return (cmd >= CMD_FLAG_SKIP_TEST && cmd <= CMD_FLAG_CALLOUT_NOHUP); +} + +static bool cmd_is_flag(int cmd) +{ + return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); +} + +static bool cmd_need_arg(int cmd) +{ + return (cmd >= CMD_PORT && cmd <= CMD_WAIT); +} + +#define ALL_SPD ( \ + ASYNC_SPD_HI | ASYNC_SPD_VHI | ASYNC_SPD_SHI | \ + ASYNC_SPD_WARP | ASYNC_SPD_CUST \ + ) + +#define ALL_FLAGS ( \ + ASYNC_SAK | ASYNC_FOURPORT | ASYNC_HUP_NOTIFY | \ + ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ | ASYNC_SPLIT_TERMIOS | \ + ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP | \ + ASYNC_LOW_LATENCY \ + ) + +#if (ALL_SPD | ALL_FLAGS) > 0xffff +# error "Unexpected flags size" +#endif + +static const uint16_t setbits[CMD_FLAG_LAST + 1] = +{ + 0, + ASYNC_SPD_HI, + ASYNC_SPD_VHI, + ASYNC_SPD_SHI, + ASYNC_SPD_WARP, + ASYNC_SPD_CUST, + + ASYNC_SAK, + ASYNC_FOURPORT, + ASYNC_HUP_NOTIFY, + ASYNC_SKIP_TEST, + ASYNC_AUTO_IRQ, + ASYNC_SPLIT_TERMIOS, + ASYNC_SESSION_LOCKOUT, + ASYNC_PGRP_LOCKOUT, + ASYNC_CALLOUT_NOHUP, + ASYNC_LOW_LATENCY +}; + +static const char STR_INFINITE[] = "infinite"; +static const char STR_NONE[] = "none"; + +static const char *uart_type(int type) +{ + if (type > MAX_SERIAL_TYPE) + return "undefined"; + + return nth_string(serial_types, type); +} + +/* libbb candidate */ +static int index_in_strings_case_insensitive(const char *strings, const char *key) +{ + int idx = 0; + + while (*strings) { + if (strcasecmp(strings, key) == 0) { + return idx; + } + strings += strlen(strings) + 1; /* skip NUL */ + idx++; + } + return -1; +} + +static int uart_id(const char *name) +{ + return index_in_strings_case_insensitive(serial_types, name); +} + +static const char *get_spd(int flags, enum print_mode mode) +{ + int idx; + + switch (flags & ASYNC_SPD_MASK) { + case ASYNC_SPD_HI: + idx = CMD_SPD_HI; + break; + case ASYNC_SPD_VHI: + idx = CMD_SPD_VHI; + break; + case ASYNC_SPD_SHI: + idx = CMD_SPD_SHI; + break; + case ASYNC_SPD_WARP: + idx = CMD_SPD_WARP; + break; + case ASYNC_SPD_CUST: + idx = CMD_SPD_CUST; + break; + default: + if (mode < PRINT_FEDBACK) + return NULL; + idx = CMD_SPD_NORMAL; + } + + return nth_string(commands, idx); +} + +static int get_numeric(const char *arg) +{ + return bb_strtol(arg, NULL, 0); +} + +static int get_wait(const char *arg) +{ + if (strcasecmp(arg, STR_NONE) == 0) + return ASYNC_CLOSING_WAIT_NONE; + + if (strcasecmp(arg, STR_INFINITE) == 0) + return ASYNC_CLOSING_WAIT_INF; + + return get_numeric(arg); +} + +static int get_uart(const char *arg) +{ + int uart = uart_id(arg); + + if (uart < 0) + bb_error_msg_and_die("illegal UART type: %s", arg); + + return uart; +} + +static int serial_open(const char *dev, bool quiet) +{ + int fd; + + fd = device_open(dev, O_RDWR | O_NONBLOCK); + if (fd < 0 && !quiet) + bb_simple_perror_msg(dev); + + return fd; +} + +static int serial_ctl(int fd, int ops, struct serial_struct *serinfo) +{ + int ret = 0; + const char *err; + + if (ops & CTL_SET) { + ret = ioctl(fd, TIOCSSERIAL, serinfo); + if (ret < 0) { + err = "can't set serial info"; + goto fail; + } + } + + if (ops & CTL_CONFIG) { + ret = ioctl(fd, TIOCSERCONFIG); + if (ret < 0) { + err = "can't autoconfigure port"; + goto fail; + } + } + + if (ops & CTL_GET) { + ret = ioctl(fd, TIOCGSERIAL, serinfo); + if (ret < 0) { + err = "can't get serial info"; + goto fail; + } + } + nodie: + if (ops & CTL_CLOSE) + close(fd); + + return ret; + fail: + bb_simple_perror_msg(err); + if (ops & CTL_NODIE) + goto nodie; + exit(EXIT_FAILURE); +} + +static void print_flag(const char **prefix, const char *flag) +{ + printf("%s%s", *prefix, flag); + *prefix = " "; +} + +static void print_serial_flags(int serial_flags, enum print_mode mode, + const char *prefix, const char *postfix) +{ + int i; + const char *spd, *pr; + + pr = prefix; + + spd = get_spd(serial_flags, mode); + if (spd) + print_flag(&pr, spd); + + for (i = CMD_FLAG_FIRST; i <= CMD_FLAG_LAST; i++) { + if ((serial_flags & setbits[i]) + && (mode > PRINT_SUMMARY || !cmd_noprint(i)) + ) { + print_flag(&pr, nth_string(commands, i)); + } + } + + puts(pr == prefix ? "" : postfix); +} + +static void print_closing_wait(unsigned int closing_wait) +{ + switch (closing_wait) { + case ASYNC_CLOSING_WAIT_NONE: + puts(STR_NONE); + break; + case ASYNC_CLOSING_WAIT_INF: + puts(STR_INFINITE); + break; + default: + printf("%u\n", closing_wait); + } +} + +static void serial_get(const char *device, enum print_mode mode) +{ + int fd, ret; + const char *uart, *prefix, *postfix; + struct serial_struct serinfo; + + fd = serial_open(device, /*quiet:*/ mode == PRINT_SUMMARY); + if (fd < 0) + return; + + ret = serial_ctl(fd, CTL_GET | CTL_CLOSE | CTL_NODIE, &serinfo); + if (ret < 0) + return; + + uart = uart_type(serinfo.type); + prefix = ", Flags: "; + postfix = ""; + + switch (mode) { + case PRINT_NORMAL: + printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d", + device, uart, serinfo.port, serinfo.irq); + break; + case PRINT_SUMMARY: + if (!serinfo.type) + return; + printf("%s at 0x%.4x (irq = %d) is a %s", + device, serinfo.port, serinfo.irq, uart); + prefix = " ("; + postfix = ")"; + break; + case PRINT_FEDBACK: + printf("%s uart %s port 0x%.4x irq %d baud_base %d", device, + uart, serinfo.port, serinfo.irq, serinfo.baud_base); + prefix = " "; + break; + case PRINT_ALL: + printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n", + device, serinfo.line, uart, serinfo.port, serinfo.irq); + printf("\tBaud_base: %d, close_delay: %u, divisor: %d\n", + serinfo.baud_base, serinfo.close_delay, + serinfo.custom_divisor); + printf("\tclosing_wait: "); + print_closing_wait(serinfo.closing_wait); + prefix = "\tFlags: "; + postfix = "\n"; + break; + default: + assert(0); + } + + print_serial_flags(serinfo.flags, mode, prefix, postfix); +} + +static int find_cmd(const char *cmd) +{ + int idx; + + idx = index_in_strings_case_insensitive(commands, cmd); + if (idx < 0) + bb_error_msg_and_die("invalid flag: %s", cmd); + + return idx; +} + +static void serial_set(char **arg, int opts) +{ + struct serial_struct serinfo; + int cmd; + const char *word; + int fd; + + fd = serial_open(*arg++, /*quiet:*/ false); + if (fd < 0) + exit(201); + + serial_ctl(fd, CTL_GET, &serinfo); + + if (opts & OPT_ZERO) + serinfo.flags = 0; + + while (*arg) { + int invert; + + word = *arg++; + invert = (*word == '^'); + word += invert; + + cmd = find_cmd(word); + + if (*arg == NULL && cmd_need_arg(cmd)) + bb_error_msg_and_die(bb_msg_requires_arg, word); + + if (invert && !cmd_is_flag(cmd)) + bb_error_msg_and_die("can't invert %s", word); + + switch (cmd) { + case CMD_SPD_NORMAL: + case CMD_SPD_HI: + case CMD_SPD_VHI: + case CMD_SPD_SHI: + case CMD_SPD_WARP: + case CMD_SPD_CUST: + serinfo.flags &= ~ASYNC_SPD_MASK; + /* fallthrough */ + case CMD_FLAG_SAK: + case CMD_FLAG_FOURPORT: + case CMD_FLAG_NUP_NOTIFY: + case CMD_FLAG_SKIP_TEST: + case CMD_FLAG_AUTO_IRQ: + case CMD_FLAG_SPLIT_TERMIOS: + case CMD_FLAG_SESSION_LOCKOUT: + case CMD_FLAG_PGRP_LOCKOUT: + case CMD_FLAG_CALLOUT_NOHUP: + case CMD_FLAG_LOW_LATENCY: + if (invert) + serinfo.flags &= ~setbits[cmd]; + else + serinfo.flags |= setbits[cmd]; + break; + case CMD_PORT: + serinfo.port = get_numeric(*arg++); + break; + case CMD_IRQ: + serinfo.irq = get_numeric(*arg++); + break; + case CMD_DIVISOR: + serinfo.custom_divisor = get_numeric(*arg++); + break; + case CMD_UART: + serinfo.type = get_uart(*arg++); + break; + case CMD_BASE: + serinfo.baud_base = get_numeric(*arg++); + break; + case CMD_DELAY: + serinfo.close_delay = get_numeric(*arg++); + break; + case CMD_WAIT: + serinfo.closing_wait = get_wait(*arg++); + break; + case CMD_AUTOCONFIG: + serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo); + break; + default: + assert(0); + } + } + + serial_ctl(fd, CTL_SET | CTL_CLOSE, &serinfo); +} + +int setserial_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setserial_main(int argc UNUSED_PARAM, char **argv) +{ + int opts; + + opt_complementary = "-1:b-aG:G-ab:a-bG"; + opts = getopt32(argv, "bGavzg"); + argv += optind; + + if (!argv[1]) /* one arg only? */ + opts |= OPT_GET; + + if (!(opts & OPT_GET)) { + serial_set(argv, opts); + argv[1] = NULL; + } + + if (opts & (OPT_VERBOSE | OPT_GET)) { + do { + serial_get(*argv++, opts & OPT_MODE_MASK); + } while (*argv); + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/setsid.c b/release/src/router/busybox/miscutils/setsid.c index c573fae343..ad2c8a4de5 100644 --- a/release/src/router/busybox/miscutils/setsid.c +++ b/release/src/router/busybox/miscutils/setsid.c @@ -14,6 +14,13 @@ * - busyboxed */ +//usage:#define setsid_trivial_usage +//usage: "PROG ARGS" +//usage:#define setsid_full_usage "\n\n" +//usage: "Run PROG in a new session. PROG will have no controlling terminal\n" +//usage: "and will not be affected by keyboard signals (Ctrl-C etc).\n" +//usage: "See setsid(2) for details." + #include "libbb.h" int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/strings.c b/release/src/router/busybox/miscutils/strings.c index 7ab0e227cb..9f50182444 100644 --- a/release/src/router/busybox/miscutils/strings.c +++ b/release/src/router/busybox/miscutils/strings.c @@ -7,6 +7,15 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define strings_trivial_usage +//usage: "[-afo] [-n LEN] [FILE]..." +//usage:#define strings_full_usage "\n\n" +//usage: "Display printable strings in a binary file\n" +//usage: "\n -a Scan whole file (default)" +//usage: "\n -f Precede strings with filenames" +//usage: "\n -n LEN At least LEN characters form a string (default 4)" +//usage: "\n -o Precede strings with decimal offsets" + #include "libbb.h" #define WHOLE_FILE 1 diff --git a/release/src/router/busybox/miscutils/taskset.c b/release/src/router/busybox/miscutils/taskset.c index 389ef43e48..4a9e3230d3 100644 --- a/release/src/router/busybox/miscutils/taskset.c +++ b/release/src/router/busybox/miscutils/taskset.c @@ -6,6 +6,23 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define taskset_trivial_usage +//usage: "[-p] [MASK] [PID | PROG ARGS]" +//usage:#define taskset_full_usage "\n\n" +//usage: "Set or get CPU affinity\n" +//usage: "\n -p Operate on an existing PID" +//usage: +//usage:#define taskset_example_usage +//usage: "$ taskset 0x7 ./dgemm_test&\n" +//usage: "$ taskset -p 0x1 $!\n" +//usage: "pid 4790's current affinity mask: 7\n" +//usage: "pid 4790's new affinity mask: 1\n" +//usage: "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n" +//usage: "pid 6671's current affinity mask: 1\n" +//usage: "pid 6671's new affinity mask: 1\n" +//usage: "$ taskset -p 1\n" +//usage: "pid 1's current affinity mask: 3\n" + #include #include "libbb.h" diff --git a/release/src/router/busybox/miscutils/time.c b/release/src/router/busybox/miscutils/time.c index 6b1c3c42c8..945f15f0d5 100644 --- a/release/src/router/busybox/miscutils/time.c +++ b/release/src/router/busybox/miscutils/time.c @@ -9,6 +9,12 @@ Heavily modified for busybox by Erik Andersen */ +//usage:#define time_trivial_usage +//usage: "[-v] PROG ARGS" +//usage:#define time_full_usage "\n\n" +//usage: "Run PROG, display resource usage when it exits\n" +//usage: "\n -v Verbose" + #include "libbb.h" /* Information on the resources used by a child process. */ diff --git a/release/src/router/busybox/miscutils/timeout.c b/release/src/router/busybox/miscutils/timeout.c index 48b8d8fc0f..9d56593bae 100644 --- a/release/src/router/busybox/miscutils/timeout.c +++ b/release/src/router/busybox/miscutils/timeout.c @@ -28,6 +28,12 @@ * rewrite 14-11-2008 vda */ +//usage:#define timeout_trivial_usage +//usage: "[-t SECS] [-s SIG] PROG ARGS" +//usage:#define timeout_full_usage "\n\n" +//usage: "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n" +//usage: "Defaults: SECS: 10, SIG: TERM." + #include "libbb.h" int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -83,7 +89,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) bb_daemonize_or_rexec(0, argv); /* Here we are grandchild. Sleep, then kill grandparent */ grandchild: - /* Just sleep(NUGE_NUM); kill(parent) may kill wrong process! */ + /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ while (1) { sleep(1); if (--timeout <= 0) diff --git a/release/src/router/busybox/miscutils/ttysize.c b/release/src/router/busybox/miscutils/ttysize.c index f93a506a2f..d2d48d0a9a 100644 --- a/release/src/router/busybox/miscutils/ttysize.c +++ b/release/src/router/busybox/miscutils/ttysize.c @@ -9,6 +9,12 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define ttysize_trivial_usage +//usage: "[w] [h]" +//usage:#define ttysize_full_usage "\n\n" +//usage: "Print dimension(s) of stdin's terminal, on error return 80x25" + #include "libbb.h" int ttysize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/ubi_tools.c b/release/src/router/busybox/miscutils/ubi_tools.c new file mode 100644 index 0000000000..dd99a44f4e --- /dev/null +++ b/release/src/router/busybox/miscutils/ubi_tools.c @@ -0,0 +1,276 @@ +/* Ported to busybox from mtd-utils. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UBIATTACH +//config: bool "ubiattach" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Attach MTD device to an UBI device. +//config: +//config:config UBIDETACH +//config: bool "ubidetach" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Detach MTD device from an UBI device. +//config: +//config:config UBIMKVOL +//config: bool "ubimkvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Create a UBI volume. +//config: +//config:config UBIRMVOL +//config: bool "ubirmvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Delete a UBI volume. +//config: +//config:config UBIRSVOL +//config: bool "ubirsvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Resize a UBI volume. +//config: +//config:config UBIUPDATEVOL +//config: bool "ubiupdatevol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Update a UBI volume. + +//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach)) +//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach)) +//applet:IF_UBIMKVOL(APPLET_ODDNAME(ubimkvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubimkvol)) +//applet:IF_UBIRMVOL(APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) +//applet:IF_UBIRSVOL(APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) +//applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) + +//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIMKVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIRMVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIRSVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o + +#include "libbb.h" +/* Some versions of kernel have broken headers, need this hack */ +#ifndef __packed +# define __packed __attribute__((packed)) +#endif +#include + +#define OPTION_M (1 << 0) +#define OPTION_D (1 << 1) +#define OPTION_n (1 << 2) +#define OPTION_N (1 << 3) +#define OPTION_s (1 << 4) +#define OPTION_a (1 << 5) +#define OPTION_t (1 << 6) + +#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') +#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') +#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') +#define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm') +#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') +#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') + +//usage:#define ubiattach_trivial_usage +//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" +//usage:#define ubiattach_full_usage "\n\n" +//usage: "Attach MTD device to UBI\n" +//usage: "\n -m MTD_NUM MTD device number to attach" +//usage: "\n -d UBI_NUM UBI device number to assign" +//usage: +//usage:#define ubidetach_trivial_usage +//usage: "-d UBI_NUM UBI_CTRL_DEV" +//usage:#define ubidetach_full_usage "\n\n" +//usage: "Detach MTD device from UBI\n" +//usage: "\n -d UBI_NUM UBI device number" +//usage: +//usage:#define ubimkvol_trivial_usage +//usage: "UBI_DEVICE -N NAME -s SIZE" +//usage:#define ubimkvol_full_usage "\n\n" +//usage: "Create UBI volume\n" +//usage: "\n -a ALIGNMENT Volume alignment (default 1)" +//usage: "\n -n VOLID Volume ID, if not specified, it" +//usage: "\n will be assigned automatically" +//usage: "\n -N NAME Volume name" +//usage: "\n -s SIZE Size in bytes" +//usage: "\n -t TYPE Volume type (static|dynamic)" +//usage: +//usage:#define ubirmvol_trivial_usage +//usage: "UBI_DEVICE -n VOLID" +//usage:#define ubirmvol_full_usage "\n\n" +//usage: "Remove UBI volume\n" +//usage: "\n -n VOLID Volume ID" +//usage: +//usage:#define ubirsvol_trivial_usage +//usage: "UBI_DEVICE -n VOLID -s SIZE" +//usage:#define ubirsvol_full_usage "\n\n" +//usage: "Resize UBI volume\n" +//usage: "\n -n VOLID Volume ID to resize" +//usage: "\n -s SIZE Size in bytes" +//usage: +//usage:#define ubiupdatevol_trivial_usage +//usage: "UBI_DEVICE [IMG_FILE]" +//usage:#define ubiupdatevol_full_usage "\n\n" +//usage: "Update UBI volume\n" +//usage: "\n -t Truncate UBI volume" +//usage: "\n -s SIZE Bytes in input (if reading stdin)" + + +int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ubi_tools_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + char *ubi_ctrl; + //struct stat st; + int fd; + int mtd_num; + int dev_num = UBI_DEV_NUM_AUTO; + int vol_id = UBI_VOL_NUM_AUTO; + char *vol_name = NULL; + int size_bytes; + int alignment = 1; + char *type = NULL; + + opt_complementary = "-1:m+:d+:n+:s+:a+"; + opts = getopt32(argv, "m:d:n:N:s:a:t::", + &mtd_num, &dev_num, &vol_id, + &vol_name, &size_bytes, &alignment, &type + ); + ubi_ctrl = argv[optind]; + + fd = xopen(ubi_ctrl, O_RDWR); + //xfstat(fd, &st, ubi_ctrl); + //if (!S_ISCHR(st.st_mode)) + // bb_error_msg_and_die("%s: not a char device", ubi_ctrl); + + if (do_attach) { + struct ubi_attach_req req; + if (!(opts & OPTION_M)) + bb_error_msg_and_die("%s device not specified", "MTD"); + + memset(&req, 0, sizeof(req)); + req.mtd_num = mtd_num; + req.ubi_num = dev_num; + + xioctl(fd, UBI_IOCATT, &req); + } else + if (do_detach) { + if (!(opts & OPTION_D)) + bb_error_msg_and_die("%s device not specified", "UBI"); + + xioctl(fd, UBI_IOCDET, &dev_num); + } else + if (do_mkvol) { + struct ubi_mkvol_req req; + int vol_name_len; + if (!(opts & OPTION_s)) + bb_error_msg_and_die("%s size not specified", "UBI"); + if (!(opts & OPTION_N)) + bb_error_msg_and_die("%s name not specified", "UBI"); + vol_name_len = strlen(vol_name); + if (vol_name_len > UBI_MAX_VOLUME_NAME) + bb_error_msg_and_die("%s volume name too long", "UBI"); + + memset(&req, 0, sizeof(req)); + req.vol_id = vol_id; + if ((opts & OPTION_t) && type) { + if (type[0] == 's') + req.vol_type = UBI_STATIC_VOLUME; + else + req.vol_type = UBI_DYNAMIC_VOLUME; + } else { + req.vol_type = UBI_DYNAMIC_VOLUME; + } + req.alignment = alignment; + req.bytes = size_bytes; + strncpy(req.name, vol_name, UBI_MAX_VOLUME_NAME); + req.name_len = vol_name_len; + + xioctl(fd, UBI_IOCMKVOL, &req); + } else + if (do_rmvol) { + if (!(opts & OPTION_n)) + bb_error_msg_and_die("%s volume id not specified", "UBI"); + + xioctl(fd, UBI_IOCRMVOL, &vol_id); + } else + if (do_rsvol) { + struct ubi_rsvol_req req; + if (!(opts & OPTION_s)) + bb_error_msg_and_die("%s size not specified", "UBI"); + if (!(opts & OPTION_n)) + bb_error_msg_and_die("%s volume id not specified", "UBI"); + + memset(&req, 0, sizeof(req)); + req.bytes = size_bytes; + req.vol_id = vol_id; + + xioctl(fd, UBI_IOCRSVOL, &req); + } else + if (do_update) { + long long bytes; + + if (opts & OPTION_t) { + // truncate the volume by starting an update for size 0 + bytes = 0; + xioctl(fd, UBI_IOCVOLUP, &bytes); + } + else { + struct stat st; + char buf[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size") + 2 * sizeof(int)*3]; + int input_fd; + unsigned ubinum, volnum; + unsigned leb_size; + ssize_t len; + char *input_data; + + // Make assumption that device not is in normal format. + // Removes need for scanning sysfs tree as full libubi does + if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) + bb_error_msg_and_die("%s volume node not in correct format", "UBI"); + + sprintf(buf, "/sys/class/ubi/ubi%u_%u/usable_eb_size", ubinum, volnum); + if (open_read_close(buf, buf, sizeof(buf)) <= 0) + bb_error_msg_and_die("%s could not get LEB size", "UBI"); + if (sscanf(buf, "%u", &leb_size) != 1) + bb_error_msg_and_die("%s could not get LEB size", "UBI"); + + if (opts & OPTION_s) { + input_fd = 0; + } else { + if (!argv[optind+1]) + bb_show_usage(); + xstat(argv[optind+1], &st); + size_bytes = st.st_size; + input_fd = xopen(argv[optind+1], O_RDONLY); + } + + bytes = size_bytes; + xioctl(fd, UBI_IOCVOLUP, &bytes); + + input_data = xmalloc(leb_size); + while ((len = full_read(input_fd, input_data, leb_size)) > 0) { + xwrite(fd, input_data, len); + } + if (len < 0) + bb_error_msg_and_die("%s volume update failed", "UBI"); + if (ENABLE_FEATURE_CLEAN_UP) + close(input_fd); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/volname.c b/release/src/router/busybox/miscutils/volname.c index 6e86156174..b50e79573b 100644 --- a/release/src/router/busybox/miscutils/volname.c +++ b/release/src/router/busybox/miscutils/volname.c @@ -27,6 +27,12 @@ * mods from distributed source (eject-2.0.13) are by * Matthew Stoltenberg */ + +//usage:#define volname_trivial_usage +//usage: "[DEVICE]" +//usage:#define volname_full_usage "\n\n" +//usage: "Show CD volume name of the DEVICE (default /dev/cdrom)" + #include "libbb.h" int volname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/miscutils/wall.c b/release/src/router/busybox/miscutils/wall.c index eecfc166bc..762f53b728 100644 --- a/release/src/router/busybox/miscutils/wall.c +++ b/release/src/router/busybox/miscutils/wall.c @@ -6,8 +6,16 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define wall_trivial_usage +//usage: "[FILE]" +//usage:#define wall_full_usage "\n\n" +//usage: "Write content of FILE or stdin to all logged-in users" +//usage: +//usage:#define wall_sample_usage +//usage: "echo foo | wall\n" +//usage: "wall ./mymessage" + #include "libbb.h" -#include int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wall_main(int argc UNUSED_PARAM, char **argv) diff --git a/release/src/router/busybox/miscutils/watchdog.c b/release/src/router/busybox/miscutils/watchdog.c index 6307826600..ee28dc30d3 100644 --- a/release/src/router/busybox/miscutils/watchdog.c +++ b/release/src/router/busybox/miscutils/watchdog.c @@ -9,6 +9,16 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define watchdog_trivial_usage +//usage: "[-t N[ms]] [-T N[ms]] [-F] DEV" +//usage:#define watchdog_full_usage "\n\n" +//usage: "Periodically write to watchdog device DEV\n" +//usage: "\n -T N Reboot after N seconds if not reset (default 60)" +//usage: "\n -t N Reset every N seconds (default 30)" +//usage: "\n -F Run in foreground" +//usage: "\n" +//usage: "\nUse 500ms to specify period in milliseconds" + #include "libbb.h" #include "linux/types.h" /* for __u32 */ #include "linux/watchdog.h" diff --git a/release/src/router/busybox/modutils/Config.src b/release/src/router/busybox/modutils/Config.src index 4191d29f2e..449ac65afb 100644 --- a/release/src/router/busybox/modutils/Config.src +++ b/release/src/router/busybox/modutils/Config.src @@ -4,13 +4,13 @@ # menu "Linux Module Utilities" -depends on PLATFORM_LINUX INSERT config MODPROBE_SMALL bool "Simplified modutils" default y + select PLATFORM_LINUX help Simplified modutils. @@ -45,6 +45,7 @@ config FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE bool "Accept module options on modprobe command line" default y depends on MODPROBE_SMALL + select PLATFORM_LINUX help Allow insmod and modprobe take module options from command line. @@ -59,6 +60,7 @@ config INSMOD bool "insmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help insmod is used to load specified modules in the running kernel. @@ -66,6 +68,7 @@ config RMMOD bool "rmmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help rmmod is used to unload specified modules from the kernel. @@ -73,6 +76,7 @@ config LSMOD bool "lsmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help lsmod is used to display a list of loaded modules. @@ -80,6 +84,7 @@ config FEATURE_LSMOD_PRETTY_2_6_OUTPUT bool "Pretty output" default n depends on LSMOD + select PLATFORM_LINUX help This option makes output format of lsmod adjusted to the format of module-init-tools for Linux kernel 2.6. @@ -89,6 +94,7 @@ config MODPROBE bool "modprobe" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help Handle the loading of modules, and their dependencies on a high level. @@ -97,6 +103,7 @@ config FEATURE_MODPROBE_BLACKLIST bool "Blacklist support" default n depends on MODPROBE + select PLATFORM_LINUX help Say 'y' here to enable support for the 'blacklist' command in modprobe.conf. This prevents the alias resolver to resolve @@ -108,6 +115,7 @@ config DEPMOD bool "depmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help depmod generates modules.dep (and potentially modules.alias and modules.symbols) that contain dependency information @@ -119,6 +127,7 @@ config FEATURE_2_4_MODULES bool "Support version 2.2/2.4 Linux kernels" default n depends on INSMOD || RMMOD || LSMOD + select PLATFORM_LINUX help Support module loading for 2.2.x and 2.4.x Linux kernels. This increases size considerably. Say N unless you plan @@ -128,6 +137,7 @@ config FEATURE_INSMOD_TRY_MMAP bool "Try to load module from a mmap'ed area" default n depends on INSMOD || MODPROBE_SMALL + select PLATFORM_LINUX help This option causes module loading code to try to mmap module first. If it does not work (for example, @@ -144,6 +154,7 @@ config FEATURE_INSMOD_VERSION_CHECKING bool "Enable module version checking" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help Support checking of versions for modules. This is used to ensure that the kernel and module are made for each other. @@ -152,6 +163,7 @@ config FEATURE_INSMOD_KSYMOOPS_SYMBOLS bool "Add module symbols to kernel symbol table" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help By adding module symbols to the kernel symbol table, Oops messages occuring within kernel modules can be properly debugged. By enabling @@ -163,6 +175,7 @@ config FEATURE_INSMOD_LOADINKMEM bool "In kernel memory optimization (uClinux only)" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help This is a special uClinux only memory optimization that lets insmod load the specified kernel module directly into kernel space, reducing @@ -173,6 +186,7 @@ config FEATURE_INSMOD_LOAD_MAP bool "Enable insmod load map (-m) option" default n depends on FEATURE_2_4_MODULES && INSMOD + select PLATFORM_LINUX help Enabling this, one would be able to get a load map output on stdout. This makes kernel module debugging @@ -184,6 +198,7 @@ config FEATURE_INSMOD_LOAD_MAP_FULL bool "Symbols in load map" default y depends on FEATURE_INSMOD_LOAD_MAP && !MODPROBE_SMALL + select PLATFORM_LINUX help Without this option, -m will only output section load map. With this option, -m will also output @@ -193,6 +208,7 @@ config FEATURE_CHECK_TAINTED_MODULE bool "Support tainted module checking with new kernels" default y depends on (LSMOD || FEATURE_2_4_MODULES) && !MODPROBE_SMALL + select PLATFORM_LINUX help Support checking for tainted modules. These are usually binary only modules that will make the linux-kernel list ignore your @@ -203,6 +219,7 @@ config FEATURE_MODUTILS_ALIAS bool "Support for module.aliases file" default y depends on DEPMOD || MODPROBE + select PLATFORM_LINUX help Generate and parse modules.alias containing aliases for bus identifiers: @@ -219,6 +236,7 @@ config FEATURE_MODUTILS_SYMBOLS bool "Support for module.symbols file" default y depends on DEPMOD || MODPROBE + select PLATFORM_LINUX help Generate and parse modules.symbols containing aliases for symbol_request() kernel calls, such as: diff --git a/release/src/router/busybox/modutils/depmod.c b/release/src/router/busybox/modutils/depmod.c index 85b64a2295..7752361261 100644 --- a/release/src/router/busybox/modutils/depmod.c +++ b/release/src/router/busybox/modutils/depmod.c @@ -8,12 +8,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_DROP)) - -//usage:#if !ENABLE_MODPROBE_SMALL -//usage:#define depmod_trivial_usage NOUSAGE_STR -//usage:#define depmod_full_usage "" -//usage:#endif +//applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP)) #include "libbb.h" #include "modutils.h" @@ -131,7 +126,16 @@ static void xfreopen_write(const char *file, FILE *f) bb_perror_msg_and_die("can't open '%s'", file); } -/* Usage: +//usage:#if !ENABLE_MODPROBE_SMALL +//usage:#define depmod_trivial_usage "[-n] [-b BASE] [VERSION] [MODFILES]..." +//usage:#define depmod_full_usage "\n\n" +//usage: "Generate modules.dep, alias, and symbols files" +//usage: "\n" +//usage: "\n -b BASE Use BASE/lib/modules/VERSION" +//usage: "\n -n Dry run: print files to stdout" +//usage:#endif + +/* Upstream usage: * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]... * -a --all * Probe all modules. Default if no MODFILES. @@ -142,7 +146,7 @@ static void xfreopen_write(const char *file, FILE *f) * -C --config FILE or DIR * Path to /etc/depmod.conf or /etc/depmod.d/ * -e --errsyms - * When combined with the -F option, this reports any symbols which + * When combined with the -F option, this reports any symbols * which are not supplied by other modules or kernel. * -F --filesyms System.map * -n --dry-run @@ -154,8 +158,13 @@ static void xfreopen_write(const char *file, FILE *f) * -u No-op * -q No-op * - * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]... - * -aAeF are accepted but ignored. -vC are not accepted. + * So far we only support: [-n] [-b BASE] [VERSION] [MODFILES]... + * Accepted but ignored: + * -aAe + * -F System.map + * -C FILE/DIR + * + * Not accepted: -v */ enum { //OPT_a = (1 << 0), /* All modules, ignore mods in argv */ diff --git a/release/src/router/busybox/modutils/insmod.c b/release/src/router/busybox/modutils/insmod.c index 0b6cce7076..f6d4b982ff 100644 --- a/release/src/router/busybox/modutils/insmod.c +++ b/release/src/router/busybox/modutils/insmod.c @@ -7,7 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_INSMOD(APPLET(insmod, BB_DIR_SBIN, BB_SUID_DROP)) #include "libbb.h" #include "modutils.h" @@ -24,7 +24,6 @@ //usage:#define insmod_full_usage "\n\n" //usage: "Load the specified kernel modules into the kernel" //usage: IF_FEATURE_2_4_MODULES( "\n" -//usage: "\nOptions:" //usage: "\n -f Force module to load into the wrong kernel version" //usage: "\n -k Make module autoclean-able" //usage: "\n -v Verbose" @@ -119,7 +118,7 @@ int insmod_main(int argc UNUSED_PARAM, char **argv) if (fp != NULL) fclose(fp); - rc = bb_init_module(filename, parse_cmdline_module_options(argv)); + rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0)); if (rc) bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); diff --git a/release/src/router/busybox/modutils/lsmod.c b/release/src/router/busybox/modutils/lsmod.c index d7e16689b1..3b3c166b94 100644 --- a/release/src/router/busybox/modutils/lsmod.c +++ b/release/src/router/busybox/modutils/lsmod.c @@ -8,7 +8,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_LSMOD(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP)) //usage:#if !ENABLE_MODPROBE_SMALL //usage:#define lsmod_trivial_usage diff --git a/release/src/router/busybox/modutils/modinfo.c b/release/src/router/busybox/modutils/modinfo.c index 37ba77edf2..c0910ffedf 100644 --- a/release/src/router/busybox/modutils/modinfo.c +++ b/release/src/router/busybox/modutils/modinfo.c @@ -6,13 +6,14 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_MODINFO(APPLET(modinfo, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_MODINFO(APPLET(modinfo, BB_DIR_SBIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o //config:config MODINFO //config: bool "modinfo" //config: default y +//config: select PLATFORM_LINUX //config: help //config: Show information about a Linux Kernel module @@ -23,9 +24,9 @@ enum { - OPT_TAGS = (1 << 6) - 1, - OPT_F = (1 << 6), /* field name */ - OPT_0 = (1 << 7), /* \0 as separator */ + OPT_TAGS = (1 << 8) - 1, + OPT_F = (1 << 8), /* field name */ + OPT_0 = (1 << 9), /* \0 as separator */ }; struct modinfo_env { @@ -44,7 +45,7 @@ static int display(const char *data, const char *pattern, int flag) } static void modinfo(const char *path, const char *version, - struct modinfo_env *env) + const struct modinfo_env *env) { static const char *const shortcuts[] = { "filename", @@ -53,6 +54,8 @@ static void modinfo(const char *path, const char *version, "license", "vermagic", "parm", + "firmware", + "depends", }; size_t len; int j, length; @@ -80,11 +83,13 @@ static void modinfo(const char *path, const char *version, if (field) tags |= OPT_F; for (j = 1; (1< simulate modprobe -r */ diff --git a/release/src/router/busybox/modutils/modprobe.c b/release/src/router/busybox/modutils/modprobe.c index 9c1d41db5a..3232013df5 100644 --- a/release/src/router/busybox/modutils/modprobe.c +++ b/release/src/router/busybox/modutils/modprobe.c @@ -8,7 +8,21 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_MODPROBE(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP)) + +#include "libbb.h" +#include "modutils.h" +#include +#include + +//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) +#define DBG(...) ((void)0) + +/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), + * we expect the full dependency list to be specified in modules.dep. + * Older versions would only export the direct dependency list. + */ + //usage:#if !ENABLE_MODPROBE_SMALL //usage:#define modprobe_notes_usage @@ -72,54 +86,60 @@ //usage: " from the command line\n" //usage: //usage:#define modprobe_trivial_usage -//usage: "[-alrqvs" -//usage: IF_FEATURE_MODPROBE_BLACKLIST("b") -//usage: "] MODULE [symbol=value]..." +//usage: "[-alrqvsD" IF_FEATURE_MODPROBE_BLACKLIST("b") "]" +//usage: " MODULE [symbol=value]..." //usage:#define modprobe_full_usage "\n\n" -//usage: "Options:" -//usage: "\n -a Load multiple MODULEs" +//usage: " -a Load multiple MODULEs" //usage: "\n -l List (MODULE is a pattern)" //usage: "\n -r Remove MODULE (stacks) or do autoclean" //usage: "\n -q Quiet" //usage: "\n -v Verbose" //usage: "\n -s Log to syslog" +//usage: "\n -D Show dependencies" //usage: IF_FEATURE_MODPROBE_BLACKLIST( //usage: "\n -b Apply blacklist to module names too" //usage: ) //usage:#endif /* !ENABLE_MODPROBE_SMALL */ -#include "libbb.h" -#include "modutils.h" -#include -#include - -//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) -#define DBG(...) ((void)0) - -/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), - * we expect the full dependency list to be specified in modules.dep. - * Older versions would only export the direct dependency list. +/* Note: usage text doesn't document various 2.4 options + * we pull in through INSMOD_OPTS define + * Note2: -b is always accepted, but if !FEATURE_MODPROBE_BLACKLIST, + * it is a no-op. */ - -/* Note that usage text doesn't document various 2.4 options - * we pull in through INSMOD_OPTS define */ - -#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--ar:a--lr:r--al" -#define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b") +#define MODPROBE_OPTS "alrDb" +/* -a and -D _are_ in fact compatible */ +#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") +//#define MODPROBE_OPTS "acd:lnrt:C:b" //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" -//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") enum { - MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ - //MODPROBE_OPT_DUMP_ONLY= (INSMOD_OPT_UNUSED << x), /* c */ - //MODPROBE_OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ - MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ - //MODPROBE_OPT_SHOW_ONLY= (INSMOD_OPT_UNUSED << x), /* n */ - MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ - //MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ - //MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ - //MODPROBE_OPT_CONFIGFILE=(INSMOD_OPT_UNUSED << x), /* C */ - MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, + OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ + //OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << x), /* c */ + //OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ + OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ + //OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << x), /* n */ + OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ + //OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ + //OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ + //OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << x), /* C */ + OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << 3), /* D */ + OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 4) * ENABLE_FEATURE_MODPROBE_BLACKLIST, }; +#if ENABLE_LONG_OPTS +static const char modprobe_longopts[] ALIGN1 = + /* nobody asked for long opts (yet) */ + // "all\0" No_argument "a" + // "list\0" No_argument "l" + // "remove\0" No_argument "r" + // "quiet\0" No_argument "q" + // "verbose\0" No_argument "v" + // "syslog\0" No_argument "s" + /* module-init-tools 3.11.1 has only long opt --show-depends + * but no short -D, we provide long opt for scripts which + * were written for 3.11.1: */ + "show-depends\0" No_argument "D" + // "use-blacklist\0" No_argument "b" + ; +#endif #define MODULE_FLAG_LOADED 0x0001 #define MODULE_FLAG_NEED_DEPS 0x0002 @@ -138,16 +158,21 @@ struct module_entry { /* I'll call it ME. */ llist_t *deps; /* strings. modules we depend on */ }; +#define DB_HASH_SIZE 256 + struct globals { - llist_t *db; /* MEs of all modules ever seen (caching for speed) */ llist_t *probes; /* MEs of module(s) requested on cmdline */ char *cmdline_mopts; /* module options from cmdline */ int num_unresolved_deps; /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ smallint need_symbols; + struct utsname uts; + llist_t *db[DB_HASH_SIZE]; /* MEs of all modules ever seen (caching for speed) */ } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) static int read_config(const char *path); @@ -167,14 +192,26 @@ static char *gather_options_str(char *opts, const char *append) return opts; } +/* These three functions called many times, optimizing for speed. + * Users reported minute-long delays when they runn iptables repeatedly + * (iptables use modprobe to install needed kernel modules). + */ static struct module_entry *helper_get_module(const char *module, int create) { char modname[MODULE_NAME_LEN]; struct module_entry *e; llist_t *l; + unsigned i; + unsigned hash; filename2modname(module, modname); - for (l = G.db; l != NULL; l = l->link) { + + hash = 0; + for (i = 0; modname[i]; i++) + hash = ((hash << 5) + hash) + modname[i]; + hash %= DB_HASH_SIZE; + + for (l = G.db[hash]; l; l = l->link) { e = (struct module_entry *) l->data; if (strcmp(e->modname, modname) == 0) return e; @@ -184,15 +221,15 @@ static struct module_entry *helper_get_module(const char *module, int create) e = xzalloc(sizeof(*e)); e->modname = xstrdup(modname); - llist_add_to(&G.db, e); + llist_add_to(&G.db[hash], e); return e; } -static struct module_entry *get_or_add_modentry(const char *module) +static ALWAYS_INLINE struct module_entry *get_or_add_modentry(const char *module) { return helper_get_module(module, 1); } -static struct module_entry *get_modentry(const char *module) +static ALWAYS_INLINE struct module_entry *get_modentry(const char *module) { return helper_get_module(module, 0); } @@ -202,7 +239,7 @@ static void add_probe(const char *name) struct module_entry *m; m = get_or_add_modentry(name); - if (!(option_mask32 & MODPROBE_OPT_REMOVE) + if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) && (m->flags & MODULE_FLAG_LOADED) ) { DBG("skipping %s, it is already loaded", name); @@ -252,7 +289,7 @@ static int FAST_FUNC config_file_action(const char *filename, continue; filename2modname(tokens[1], wildcard); - for (l = G.probes; l != NULL; l = l->link) { + for (l = G.probes; l; l = l->link) { m = (struct module_entry *) l->data; if (fnmatch(wildcard, m->modname, 0) != 0) continue; @@ -353,10 +390,7 @@ static char *parse_and_add_kcmdline_module_options(char *options, const char *mo */ static int do_modprobe(struct module_entry *m) { - struct module_entry *m2 = m2; /* for compiler */ - char *fn, *options; int rc, first; - llist_t *l; if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { if (!(option_mask32 & INSMOD_OPT_SILENT)) @@ -366,20 +400,26 @@ static int do_modprobe(struct module_entry *m) } DBG("do_modprob'ing %s", m->modname); - if (!(option_mask32 & MODPROBE_OPT_REMOVE)) + if (!(option_mask32 & OPT_REMOVE)) m->deps = llist_rev(m->deps); - for (l = m->deps; l != NULL; l = l->link) - DBG("dep: %s", l->data); + if (0) { + llist_t *l; + for (l = m->deps; l; l = l->link) + DBG("dep: %s", l->data); + } first = 1; rc = 0; while (m->deps) { + struct module_entry *m2; + char *fn, *options; + rc = 0; fn = llist_pop(&m->deps); /* we leak it */ m2 = get_or_add_modentry(fn); - if (option_mask32 & MODPROBE_OPT_REMOVE) { + if (option_mask32 & OPT_REMOVE) { /* modprobe -r */ if (m2->flags & MODULE_FLAG_LOADED) { rc = bb_delete_module(m2->modname, O_NONBLOCK | O_EXCL); @@ -399,16 +439,27 @@ static int do_modprobe(struct module_entry *m) continue; } - if (m2->flags & MODULE_FLAG_LOADED) { - DBG("%s is already loaded, skipping", fn); - continue; - } - options = m2->options; m2->options = NULL; options = parse_and_add_kcmdline_module_options(options, m2->modname); if (m == m2) options = gather_options_str(options, G.cmdline_mopts); + + if (option_mask32 & OPT_SHOW_DEPS) { + printf(options ? "insmod %s/%s/%s %s\n" + : "insmod %s/%s/%s\n", + CONFIG_DEFAULT_MODULES_DIR, G.uts.release, fn, + options); + free(options); + continue; + } + + if (m2->flags & MODULE_FLAG_LOADED) { + DBG("%s is already loaded, skipping", fn); + free(options); + continue; + } + rc = bb_init_module(fn, options); DBG("loaded %s '%s', rc:%d", fn, options, rc); if (rc == EEXIST) @@ -456,7 +507,7 @@ static void load_modules_dep(void) /* Optimization... */ if ((m->flags & MODULE_FLAG_LOADED) - && !(option_mask32 & MODPROBE_OPT_REMOVE) + && !(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) ) { DBG("skip deps of %s, it's already loaded", tokens[0]); continue; @@ -477,25 +528,31 @@ static void load_modules_dep(void) int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int modprobe_main(int argc UNUSED_PARAM, char **argv) { - struct utsname uts; int rc; unsigned opt; struct module_entry *me; + INIT_G(); + + IF_LONG_OPTS(applet_long_options = modprobe_longopts;) opt_complementary = MODPROBE_COMPLEMENTARY; opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); argv += optind; /* Goto modules location */ xchdir(CONFIG_DEFAULT_MODULES_DIR); - uname(&uts); - xchdir(uts.release); + uname(&G.uts); + xchdir(G.uts.release); - if (opt & MODPROBE_OPT_LIST_ONLY) { + if (opt & OPT_LIST_ONLY) { + int i; char name[MODULE_NAME_LEN]; char *colon, *tokens[2]; parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); + for (i = 0; argv[i]; i++) + replace(argv[i], '-', '_'); + while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { colon = last_char_is(tokens[0], ':'); if (!colon) @@ -505,7 +562,6 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) puts(tokens[0]); else { - int i; for (i = 0; argv[i]; i++) { if (fnmatch(argv[i], name, 0) == 0) { puts(tokens[0]); @@ -521,7 +577,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) logmode = LOGMODE_SYSLOG; if (!argv[0]) { - if (opt & MODPROBE_OPT_REMOVE) { + if (opt & OPT_REMOVE) { /* "modprobe -r" (w/o params). * "If name is NULL, all unused modules marked * autoclean will be removed". @@ -541,7 +597,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) config_close(parser); } - if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { + if (opt & (OPT_INSERT_ALL | OPT_REMOVE)) { /* Each argument is a module name */ do { DBG("adding module %s", *argv); @@ -551,7 +607,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* First argument is module name, rest are parameters */ DBG("probing just module %s", *argv); add_probe(argv[0]); - G.cmdline_mopts = parse_cmdline_module_options(argv); + G.cmdline_mopts = parse_cmdline_module_options(argv, /*quote_spaces:*/ 1); } /* Happens if all requested modules are already loaded */ @@ -575,7 +631,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* This is not an alias. Literal names are blacklisted * only if '-b' is given. */ - if (!(opt & MODPROBE_OPT_BLACKLIST) + if (!(opt & OPT_BLACKLIST) || !(me->flags & MODULE_FLAG_BLACKLISTED) ) { rc |= do_modprobe(me); @@ -592,7 +648,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) m2 = get_or_add_modentry(realname); if (!(m2->flags & MODULE_FLAG_BLACKLISTED) && (!(m2->flags & MODULE_FLAG_LOADED) - || (opt & MODPROBE_OPT_REMOVE)) + || (opt & (OPT_REMOVE | OPT_SHOW_DEPS))) ) { //TODO: we can pass "me" as 2nd param to do_modprobe, //and make do_modprobe emit more meaningful error messages diff --git a/release/src/router/busybox/modutils/modutils-24.c b/release/src/router/busybox/modutils/modutils-24.c index 596676b8ed..c375e8d0bc 100644 --- a/release/src/router/busybox/modutils/modutils-24.c +++ b/release/src/router/busybox/modutils/modutils-24.c @@ -60,7 +60,6 @@ #include "libbb.h" #include "modutils.h" -#include #include #if ENABLE_FEATURE_INSMOD_LOADINKMEM @@ -2444,14 +2443,12 @@ new_process_module_arguments(struct obj_file *f, const char *options) bb_error_msg_and_die("symbol for parameter %s not found", param); /* Number of parameters */ + min = max = 1; if (isdigit(*pinfo)) { - min = strtoul(pinfo, &pinfo, 10); + min = max = strtoul(pinfo, &pinfo, 10); if (*pinfo == '-') max = strtoul(pinfo + 1, &pinfo, 10); - else - max = min; - } else - min = max = 1; + } contents = f->sections[sym->secidx]->contents; loc = contents + sym->value; @@ -2473,7 +2470,7 @@ new_process_module_arguments(struct obj_file *f, const char *options) /* Parse parameter values */ n = 0; p = val; - while (*p != 0) { + while (*p) { char sv_ch; char *endp; @@ -2484,7 +2481,7 @@ new_process_module_arguments(struct obj_file *f, const char *options) case 's': len = strcspn(p, ","); sv_ch = p[len]; - p[len] = 0; + p[len] = '\0'; obj_string_patch(f, sym->secidx, loc - contents, p); loc += tgt_sizeof_char_p; @@ -2494,7 +2491,7 @@ new_process_module_arguments(struct obj_file *f, const char *options) case 'c': len = strcspn(p, ","); sv_ch = p[len]; - p[len] = 0; + p[len] = '\0'; if (len >= charssize) bb_error_msg_and_die("string too long for %s (max %ld)", param, charssize - 1); diff --git a/release/src/router/busybox/modutils/modutils.c b/release/src/router/busybox/modutils/modutils.c index 415dbbe448..6187ca72fd 100644 --- a/release/src/router/busybox/modutils/modutils.c +++ b/release/src/router/busybox/modutils/modutils.c @@ -62,7 +62,7 @@ char* FAST_FUNC filename2modname(const char *filename, char *modname) return modname; } -char* FAST_FUNC parse_cmdline_module_options(char **argv) +char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces) { char *options; int optlen; @@ -70,13 +70,31 @@ char* FAST_FUNC parse_cmdline_module_options(char **argv) 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 */ -//TODO: module-init-tools version 3.11.1 quotes only value: -//it generates var="val with spaces", not "var=val with spaces" -//(and it won't quote var *name* even if it has spaces) - optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv); + const char *fmt; + const char *var; + const char *val; + + var = *argv; + options = xrealloc(options, optlen + 2 + strlen(var) + 2); + fmt = "%.*s%s "; + val = strchrnul(var, '='); + if (quote_spaces) { + /* + * modprobe (module-init-tools version 3.11.1) compat: + * quote only value: + * var="val with spaces", not "var=val with spaces" + * (note: var *name* is not checked for spaces!) + */ + if (*val) { /* has var=val format. skip '=' */ + val++; + if (strchr(val, ' ')) + fmt = "%.*s\"%s\" "; + } + } + optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val); } + /* Remove trailing space. Disabled */ + /* if (optlen != 0) options[optlen-1] = '\0'; */ return options; } diff --git a/release/src/router/busybox/modutils/modutils.h b/release/src/router/busybox/modutils/modutils.h index 863bc26d3d..5f059c716d 100644 --- a/release/src/router/busybox/modutils/modutils.h +++ b/release/src/router/busybox/modutils/modutils.h @@ -21,7 +21,7 @@ void replace(char *s, char what, char with) FAST_FUNC; char *replace_underscores(char *s) FAST_FUNC; int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; char *filename2modname(const char *filename, char *modname) FAST_FUNC; -char *parse_cmdline_module_options(char **argv) FAST_FUNC; +char *parse_cmdline_module_options(char **argv, int quote_spaces) FAST_FUNC; /* insmod for 2.4 and modprobe's options (insmod 2.6 has no options at all): */ #define INSMOD_OPTS \ diff --git a/release/src/router/busybox/modutils/rmmod.c b/release/src/router/busybox/modutils/rmmod.c index 2486511d73..4a4a91982c 100644 --- a/release/src/router/busybox/modutils/rmmod.c +++ b/release/src/router/busybox/modutils/rmmod.c @@ -8,14 +8,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_RMMOD(APPLET(rmmod, BB_DIR_SBIN, BB_SUID_DROP)) //usage:#if !ENABLE_MODPROBE_SMALL //usage:#define rmmod_trivial_usage //usage: "[-wfa] [MODULE]..." //usage:#define rmmod_full_usage "\n\n" //usage: "Unload kernel modules\n" -//usage: "\nOptions:" //usage: "\n -w Wait until the module is no longer used" //usage: "\n -f Force unload" //usage: "\n -a Remove all unused modules (recursively)" diff --git a/release/src/router/busybox/networking/Config.src b/release/src/router/busybox/networking/Config.src index 6dd7df7549..fb7dca7d49 100644 --- a/release/src/router/busybox/networking/Config.src +++ b/release/src/router/busybox/networking/Config.src @@ -51,21 +51,21 @@ config VERBOSE_RESOLUTION_ERRORS config ARP bool "arp" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Manipulate the system ARP cache. config ARPING bool "arping" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Ping hosts by ARP packets. config BRCTL bool "brctl" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Manage ethernet bridges. Supports addbr/delbr and addif/delif. @@ -98,7 +98,7 @@ config DNSD config ETHER_WAKE bool "ether-wake" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Send a magic packet to wake up sleeping machines. @@ -199,14 +199,22 @@ config FEATURE_HTTPD_BASIC_AUTH help Utilizes password settings from /etc/httpd.conf for basic authentication on a per url basis. + Example for httpd.conf file: + /adm:toor:PaSsWd config FEATURE_HTTPD_AUTH_MD5 bool "Support MD5 crypted passwords for http Authentication" default y depends on FEATURE_HTTPD_BASIC_AUTH help - Enables basic per URL authentication from /etc/httpd.conf - using md5 passwords. + Enables encrypted passwords, and wildcard user/passwords + in httpd.conf file. + User '*' means 'any system user name is ok', + password of '*' means 'use system password for this user' + Examples: + /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0 + /adm:root:* + /wiki:*:* config FEATURE_HTTPD_CGI bool "Support Common Gateway Interface (CGI)" @@ -223,8 +231,8 @@ config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 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: + properly. You need to supply an additional line in your + httpd.conf file: *.php:/path/to/your/php config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV @@ -281,7 +289,7 @@ config FEATURE_HTTPD_GZIP config IFCONFIG bool "ifconfig" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Ifconfig is used to configure the kernel-resident network interfaces. @@ -329,7 +337,7 @@ config FEATURE_IFCONFIG_BROADCAST_PLUS config IFENSLAVE bool "ifenslave" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Userspace application to bind several interfaces to a logical interface (use with kernel bonding driver). @@ -337,7 +345,7 @@ config IFENSLAVE config IFPLUGD bool "ifplugd" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Network interface plug detection daemon. @@ -379,7 +387,8 @@ config FEATURE_IFUPDOWN_IP config FEATURE_IFUPDOWN_IP_BUILTIN bool "Use busybox ip applet" default y - depends on FEATURE_IFUPDOWN_IP && PLATFORM_LINUX + depends on FEATURE_IFUPDOWN_IP + select PLATFORM_LINUX select IP select FEATURE_IP_ADDRESS select FEATURE_IP_LINK @@ -498,7 +507,7 @@ config FEATURE_INETD_RPC config IP bool "ip" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help The "ip" applet is a TCP/IP interface configuration and routing utility. You generally don't need "ip" to use busybox with @@ -611,39 +620,10 @@ config FEATURE_IPCALC_LONG_OPTIONS help Support long options for the ipcalc applet. -config NAMEIF - bool "nameif" - default y - depends on PLATFORM_LINUX - 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 y - 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 NETSTAT bool "netstat" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help netstat prints information about the Linux networking subsystem. @@ -672,7 +652,7 @@ config NSLOOKUP config NTPD bool "ntpd" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help The NTP client/server daemon. @@ -684,29 +664,6 @@ config FEATURE_NTPD_SERVER Make ntpd usable as a NTP server. If you disable this option ntpd will be usable only as a NTP client. -config PING - bool "ping" - default y - depends on PLATFORM_LINUX - 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 y - 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 y @@ -716,14 +673,14 @@ config PSCAN config ROUTE bool "route" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Route displays or manipulates the kernel's IP routing tables. config SLATTACH bool "slattach" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help slattach is a small utility to attach network interfaces to serial lines. @@ -910,7 +867,7 @@ config TFTP_DEBUG config TRACEROUTE bool "traceroute" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Utility to trace the route of IP packets. @@ -947,7 +904,7 @@ config FEATURE_TRACEROUTE_USE_ICMP config TUNCTL bool "tunctl" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help tunctl creates or deletes tun devices. @@ -980,7 +937,7 @@ config UDPSVD config VCONFIG bool "vconfig" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help Creates, removes, and configures VLAN interfaces @@ -1027,7 +984,7 @@ config FEATURE_WGET_TIMEOUT config ZCIP bool "zcip" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX select FEATURE_SYSLOG help ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. diff --git a/release/src/router/busybox/networking/Kbuild.src b/release/src/router/busybox/networking/Kbuild.src index f41a2df705..944f27be10 100644 --- a/release/src/router/busybox/networking/Kbuild.src +++ b/release/src/router/busybox/networking/Kbuild.src @@ -30,8 +30,6 @@ lib-$(CONFIG_NC) += nc.o lib-$(CONFIG_NETSTAT) += netstat.o lib-$(CONFIG_NSLOOKUP) += nslookup.o lib-$(CONFIG_NTPD) += ntpd.o -lib-$(CONFIG_PING) += ping.o -lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o lib-$(CONFIG_SLATTACH) += slattach.o diff --git a/release/src/router/busybox/networking/arp.c b/release/src/router/busybox/networking/arp.c index 0ef267a35c..696c402e01 100644 --- a/release/src/router/busybox/networking/arp.c +++ b/release/src/router/busybox/networking/arp.c @@ -13,6 +13,24 @@ * modified for getopt32 by Arne Bernin */ +//usage:#define arp_trivial_usage +//usage: "\n[-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]" +//usage: "\n[-v] [-i IF] -d HOSTNAME [pub]" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub" +//usage:#define arp_full_usage "\n\n" +//usage: "Manipulate ARP cache\n" +//usage: "\n -a Display (all) hosts" +//usage: "\n -s Set new ARP entry" +//usage: "\n -d Delete a specified entry" +//usage: "\n -v Verbose" +//usage: "\n -n Don't resolve names" +//usage: "\n -i IF Network interface" +//usage: "\n -D Read from given device" +//usage: "\n -A,-p AF Protocol family" +//usage: "\n -H HWTYPE Hardware address type" + #include "libbb.h" #include "inet_common.h" diff --git a/release/src/router/busybox/networking/arping.c b/release/src/router/busybox/networking/arping.c index 6f6b59cfba..a4421edcba 100644 --- a/release/src/router/busybox/networking/arping.c +++ b/release/src/router/busybox/networking/arping.c @@ -6,6 +6,22 @@ * Busybox port: Nick Fedchik */ +//usage:#define arping_trivial_usage +//usage: "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP" +//usage:#define arping_full_usage "\n\n" +//usage: "Send ARP requests/replies\n" +//usage: "\n -f Quit on first ARP reply" +//usage: "\n -q Quiet" +//usage: "\n -b Keep broadcasting, don't go unicast" +//usage: "\n -D Duplicated address detection mode" +//usage: "\n -U Unsolicited ARP mode, update your neighbors" +//usage: "\n -A ARP answer mode, update your neighbors" +//usage: "\n -c N Stop after sending N ARP requests" +//usage: "\n -w TIMEOUT Time to wait for ARP reply, seconds" +//usage: "\n -I IFACE Interface to use (default eth0)" +//usage: "\n -s SRC_IP Sender IP address" +//usage: "\n DST_IP Target IP address" + #include #include #include diff --git a/release/src/router/busybox/networking/brctl.c b/release/src/router/busybox/networking/brctl.c index c0b094eba2..19f474fce3 100644 --- a/release/src/router/busybox/networking/brctl.c +++ b/release/src/router/busybox/networking/brctl.c @@ -12,6 +12,30 @@ /* This applet currently uses only the ioctl interface and no sysfs at all. * At the time of this writing this was considered a feature. */ + +//usage:#define brctl_trivial_usage +//usage: "COMMAND [BRIDGE [INTERFACE]]" +//usage:#define brctl_full_usage "\n\n" +//usage: "Manage ethernet bridges\n" +//usage: "\nCommands:" +//usage: IF_FEATURE_BRCTL_SHOW( +//usage: "\n show Show a list of bridges" +//usage: ) +//usage: "\n addbr BRIDGE Create BRIDGE" +//usage: "\n delbr BRIDGE Delete BRIDGE" +//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" +//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" +//usage: IF_FEATURE_BRCTL_FANCY( +//usage: "\n setageing BRIDGE TIME Set ageing time" +//usage: "\n setfd BRIDGE TIME Set bridge forward delay" +//usage: "\n sethello BRIDGE TIME Set hello time" +//usage: "\n setmaxage BRIDGE TIME Set max message age" +//usage: "\n setpathcost BRIDGE COST Set path cost" +//usage: "\n setportprio BRIDGE PRIO Set port priority" +//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" +//usage: "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" +//usage: ) + #include "libbb.h" #include #include diff --git a/release/src/router/busybox/networking/dnsd.c b/release/src/router/busybox/networking/dnsd.c index 8ed31cea24..fe98400f7d 100644 --- a/release/src/router/busybox/networking/dnsd.c +++ b/release/src/router/busybox/networking/dnsd.c @@ -17,6 +17,21 @@ * the first porting of oao' scdns to busybox also. */ +//usage:#define dnsd_trivial_usage +//usage: "[-dvs] [-c CONFFILE] [-t TTL_SEC] [-p PORT] [-i ADDR]" +//usage:#define dnsd_full_usage "\n\n" +//usage: "Small static DNS server daemon\n" +//usage: "\n -c FILE Config file" +//usage: "\n -t SEC TTL" +//usage: "\n -p PORT Listen on PORT" +//usage: "\n -i ADDR Listen on ADDR" +//usage: "\n -d Daemonize" +//usage: "\n -v Verbose" +//usage: "\n -s Send successful replies only. Use this if you want" +//usage: "\n to use /etc/resolv.conf with two nameserver lines:" +//usage: "\n nameserver DNSD_SERVER" +//usage: "\n nameserver NORMAL_DNS_SERVER" + #include "libbb.h" #include diff --git a/release/src/router/busybox/networking/ether-wake.c b/release/src/router/busybox/networking/ether-wake.c index 8f1479c02a..6a88279f4e 100644 --- a/release/src/router/busybox/networking/ether-wake.c +++ b/release/src/router/busybox/networking/ether-wake.c @@ -64,14 +64,21 @@ * filter. That configuration consumes more power. */ +//usage:#define ether_wake_trivial_usage +//usage: "[-b] [-i iface] [-p aa:bb:cc:dd[:ee:ff]] MAC" +//usage:#define ether_wake_full_usage "\n\n" +//usage: "Send a magic packet to wake up sleeping machines.\n" +//usage: "MAC must be a station address (00:11:22:33:44:55) or\n" +//usage: "a hostname with a known 'ethers' entry.\n" +//usage: "\n -b Send wake-up packet to the broadcast address" +//usage: "\n -i iface Interface to use (default eth0)" +//usage: "\n -p pass Append four or six byte password PW to the packet" +#include "libbb.h" #include -#include #include #include -#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. diff --git a/release/src/router/busybox/networking/ftpd.c b/release/src/router/busybox/networking/ftpd.c index 64068e4676..1c97df564f 100644 --- a/release/src/router/busybox/networking/ftpd.c +++ b/release/src/router/busybox/networking/ftpd.c @@ -12,6 +12,22 @@ * You have to run this daemon via inetd. */ +//usage:#define ftpd_trivial_usage +//usage: "[-wvS] [-t N] [-T N] [DIR]" +//usage:#define ftpd_full_usage "\n\n" +//usage: "Anonymous FTP server\n" +//usage: "\n" +//usage: "ftpd should be used as an inetd service.\n" +//usage: "ftpd's line for inetd.conf:\n" +//usage: " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" +//usage: "It also can be ran from tcpsvd:\n" +//usage: " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve\n" +//usage: "\n -w Allow upload" +//usage: "\n -v Log errors to stderr. -vv: verbose log" +//usage: "\n -S Log errors to syslog. -SS: verbose log" +//usage: "\n -t,-T Idle and absolute timeouts" +//usage: "\n DIR Change root to this directory" + #include "libbb.h" #include #include @@ -206,7 +222,7 @@ cmdio_write_error(unsigned status) { *(uint32_t *) G.msg_err = status; xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1); - if (G.verbose > 1) + if (G.verbose > 0) verbose_log(G.msg_err); } #define WRITE_ERR(a) cmdio_write_error(STRNUM32sp(a)) @@ -416,7 +432,7 @@ bind_for_passive_mode(void) G.pasv_listen_fd = fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); setsockopt_reuseaddr(fd); - set_nport(G.local_addr, 0); + set_nport(&G.local_addr->u.sa, 0); xbind(fd, &G.local_addr->u.sa, G.local_addr->len); xlisten(fd, 1); getsockname(fd, &G.local_addr->u.sa, &G.local_addr->len); @@ -525,7 +541,7 @@ handle_port(void) G.port_addr = xdotted2sockaddr(raw, port); #else G.port_addr = get_peer_lsa(STDIN_FILENO); - set_nport(G.port_addr, htons(port)); + set_nport(&G.port_addr->u.sa, htons(port)); #endif WRITE_OK(FTP_PORTOK); } @@ -1163,8 +1179,7 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) #endif if (argv[optind]) { - xchdir(argv[optind]); - chroot("."); + xchroot(argv[optind]); } //umask(077); - admin can set umask before starting us diff --git a/release/src/router/busybox/networking/ftpgetput.c b/release/src/router/busybox/networking/ftpgetput.c index c68d0ace2e..8283366ccc 100644 --- a/release/src/router/busybox/networking/ftpgetput.c +++ b/release/src/router/busybox/networking/ftpgetput.c @@ -13,6 +13,42 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ftpget_trivial_usage +//usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" +//usage:#define ftpget_full_usage "\n\n" +//usage: "Download a file via FTP\n" +//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -c,--continue Continue previous transfer" +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" +//usage: ) +//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -c Continue previous transfer" +//usage: "\n -v Verbose" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port" +//usage: ) +//usage: +//usage:#define ftpput_trivial_usage +//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" +//usage:#define ftpput_full_usage "\n\n" +//usage: "Upload a file to a FTP server\n" +//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" +//usage: ) +//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -v Verbose" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port number" +//usage: ) + #include "libbb.h" struct globals { @@ -22,7 +58,7 @@ struct globals { FILE *control_stream; int verbose_flag; int do_continue; - char buf[1]; /* actually [BUFSZ] */ + char buf[4]; /* actually [BUFSZ] */ } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) }; @@ -67,7 +103,7 @@ static int ftpcmd(const char *s1, const char *s2) } do { - strcpy(buf, "EOF"); + strcpy(buf, "EOF"); /* for ftp_die */ if (fgets(buf, BUFSZ - 2, control_stream) == NULL) { ftp_die(NULL); } @@ -151,7 +187,7 @@ TODO2: need to stop ignoring IP address in PASV response. *buf_ptr = '\0'; port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; - set_nport(lsa, htons(port_num)); + set_nport(&lsa->u.sa, htons(port_num)); return xconnect_stream(lsa); } @@ -278,7 +314,6 @@ static const char ftpgetput_longopts[] ALIGN1 = int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ftpgetput_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; const char *port = "ftp"; /* socket to ftp server */ @@ -307,7 +342,7 @@ int ftpgetput_main(int argc UNUSED_PARAM, char **argv) applet_long_options = ftpgetput_longopts; #endif opt_complementary = "-2:vv:cc"; /* must have 2 to 3 params; -v and -c count */ - opt = getopt32(argv, "cvu:p:P:", &user, &password, &port, + getopt32(argv, "cvu:p:P:", &user, &password, &port, &verbose_flag, &do_continue); argv += optind; diff --git a/release/src/router/busybox/networking/hostname.c b/release/src/router/busybox/networking/hostname.c index 66b52dd909..d2516b5fb9 100644 --- a/release/src/router/busybox/networking/hostname.c +++ b/release/src/router/busybox/networking/hostname.c @@ -9,6 +9,24 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define hostname_trivial_usage +//usage: "[OPTIONS] [HOSTNAME | -F FILE]" +//usage:#define hostname_full_usage "\n\n" +//usage: "Get or set hostname or DNS domain name\n" +//usage: "\n -s Short" +//usage: "\n -i Addresses for the hostname" +//usage: "\n -d DNS domain name" +//usage: "\n -f Fully qualified domain name" +//usage: "\n -F FILE Use FILE's content as hostname" +//usage: +//usage:#define hostname_example_usage +//usage: "$ hostname\n" +//usage: "sage\n" +//usage: +//usage:#define dnsdomainname_trivial_usage NOUSAGE_STR +//usage:#define dnsdomainname_full_usage "" + #include "libbb.h" static void do_sethostname(char *s, int isfile) @@ -135,7 +153,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) if (hp->h_length == sizeof(struct in_addr)) { struct in_addr **h_addr_list = (struct in_addr **)hp->h_addr_list; while (*h_addr_list) { - printf("%s ", inet_ntoa(**h_addr_list)); + printf(h_addr_list[1] ? "%s " : "%s", inet_ntoa(**h_addr_list)); h_addr_list++; } bb_putchar('\n'); diff --git a/release/src/router/busybox/networking/httpd.c b/release/src/router/busybox/networking/httpd.c index b8113a8431..12218a0a32 100644 --- a/release/src/router/busybox/networking/httpd.c +++ b/release/src/router/busybox/networking/httpd.c @@ -21,6 +21,10 @@ * The server changes directory to the location of the script and executes it * after setting QUERY_STRING and other environment variables. * + * If directory URL is given, no index.html is found and CGI support is enabled, + * cgi-bin/index.cgi will be run. Directory to list is ../$QUERY_STRING. + * See httpd_indexcgi.c for an example GCI code. + * * Doc: * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html * @@ -50,6 +54,8 @@ * /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/ + * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/ + * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/ * .au:audio/basic # additional mime type for audio.au files * *.php:/path/php # run xxx.php through an interpreter * @@ -71,7 +77,7 @@ * 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 + * If a sub directory contains 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 @@ -93,7 +99,40 @@ */ /* TODO: use TCP_CORK, parse_config() */ +//usage:#define httpd_trivial_usage +//usage: "[-ifv[v]]" +//usage: " [-c CONFFILE]" +//usage: " [-p [IP:]PORT]" +//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") +//usage: IF_FEATURE_HTTPD_BASIC_AUTH(" [-r REALM]") +//usage: " [-h HOME]\n" +//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" +//usage:#define httpd_full_usage "\n\n" +//usage: "Listen for incoming HTTP requests\n" +//usage: "\n -i Inetd mode" +//usage: "\n -f Don't daemonize" +//usage: "\n -v[v] Verbose" +//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" +//usage: IF_FEATURE_HTTPD_SETUID( +//usage: "\n -u USER[:GRP] Set uid/gid after binding to port") +//usage: IF_FEATURE_HTTPD_BASIC_AUTH( +//usage: "\n -r REALM Authentication Realm for Basic Authentication") +//usage: "\n -h HOME Home directory (default .)" +//usage: "\n -c FILE Configuration file (default {/etc,HOME}/httpd.conf)" +//usage: IF_FEATURE_HTTPD_AUTH_MD5( +//usage: "\n -m STRING MD5 crypt STRING") +//usage: "\n -e STRING HTML encode STRING" +//usage: "\n -d STRING URL decode STRING" + #include "libbb.h" +#if ENABLE_PAM +/* PAM may include . 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 +# include +#endif #if ENABLE_FEATURE_HTTPD_USE_SENDFILE # include #endif @@ -309,7 +348,7 @@ struct globals { #define range_len (G.range_len ) #else enum { - range_start = 0, + range_start = -1, range_end = MAXINT(off_t) - 1, range_len = MAXINT(off_t), }; @@ -331,6 +370,7 @@ enum { #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ + IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ bind_addr_or_port = "80"; \ index_page = index_html; \ file_size = -1; \ @@ -791,78 +831,6 @@ static char *encodeString(const char *string) } #endif -/* - * 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. @@ -1065,6 +1033,7 @@ static void send_headers(int responseNum) static void send_headers_and_exit(int responseNum) NORETURN; static void send_headers_and_exit(int responseNum) { + IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) send_headers(responseNum); log_and_exit(); } @@ -1297,18 +1266,21 @@ static void setenv1(const char *name, const char *value) * * Parameters: * const char *url The requested URL (with leading /). + * const char *orig_uri The original URI before rewriting (if any) * 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 *orig_uri, const char *request, int post_len, const char *cookie, const char *content_type) NORETURN; static void send_cgi_and_exit( const char *url, + const char *orig_uri, const char *request, int post_len, const char *cookie, @@ -1316,7 +1288,7 @@ static void send_cgi_and_exit( { struct fd_pair fromCgi; /* CGI -> httpd pipe */ struct fd_pair toCgi; /* httpd -> CGI pipe */ - char *script; + char *script, *last_slash; int pid; /* Make a copy. NB: caller guarantees: @@ -1330,22 +1302,25 @@ static void send_cgi_and_exit( */ /* Check for [dirs/]script.cgi/PATH_INFO */ - script = (char*)url; + last_slash = script = (char*)url; while ((script = strchr(script + 1, '/')) != NULL) { + int dir; *script = '\0'; - if (!is_directory(url + 1, 1, NULL)) { + dir = is_directory(url + 1, /*followlinks:*/ 1); + *script = '/'; + if (!dir) { /* not directory, found script.cgi/PATH_INFO */ - *script = '/'; break; } - *script = '/'; /* is directory, find next '/' */ + /* is directory, find next '/' */ + last_slash = script; } 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)); + putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query)); } else { - setenv1("REQUEST_URI", url); + setenv1("REQUEST_URI", orig_uri); } if (script != NULL) *script = '\0'; /* cut off /PATH_INFO */ @@ -1419,7 +1394,7 @@ static void send_cgi_and_exit( log_and_exit(); } - if (!pid) { + if (pid == 0) { /* Child process */ char *argv[3]; @@ -1435,7 +1410,7 @@ static void send_cgi_and_exit( /* dup2(1, 2); */ /* Chdiring to script's dir */ - script = strrchr(url, '/'); + script = last_slash; if (script != url) { /* paranoia */ *script = '\0'; if (chdir(url + 1) != 0) { @@ -1615,18 +1590,18 @@ static NOINLINE void send_file_and_exit(const char *url, int what) if (what == SEND_BODY /* err pages and ranges don't mix */ || content_gzip /* we are sending compressed page: can't do ranges */ ///why? ) { - range_start = 0; + range_start = -1; } range_len = MAXINT(off_t); - if (range_start) { - if (!range_end) { + if (range_start >= 0) { + if (!range_end || range_end > file_size - 1) { range_end = file_size - 1; } if (range_end < range_start || lseek(fd, range_start, SEEK_SET) != range_start ) { lseek(fd, 0, SEEK_SET); - range_start = 0; + range_start = -1; } else { range_len = range_end - range_start + 1; send_headers(HTTP_PARTIAL_CONTENT); @@ -1649,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) break; /* fall back to read/write loop */ goto fin; } - IF_FEATURE_HTTPD_RANGES(range_len -= sz;) + IF_FEATURE_HTTPD_RANGES(range_len -= count;) if (count == 0 || range_len == 0) log_and_exit(); } @@ -1700,6 +1675,56 @@ static int checkPermIP(void) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH + +# if ENABLE_PAM +struct pam_userinfo { + const char *name; + const char *pw; +}; + +static int pam_talker(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int i; + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; + struct pam_response *response; + + if (!resp || !msg || !userinfo) + return PAM_CONV_ERR; + + /* allocate memory to store response */ + response = xzalloc(num_msg * sizeof(*response)); + + /* copy values */ + for (i = 0; i < num_msg; i++) { + const char *s; + + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_ON: + s = userinfo->name; + break; + case PAM_PROMPT_ECHO_OFF: + s = userinfo->pw; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + s = ""; + break; + default: + free(response); + return PAM_CONV_ERR; + } + response[i].resp = xstrdup(s); + if (PAM_SUCCESS != 0) + response[i].resp_retcode = PAM_SUCCESS; + } + *resp = response; + return PAM_SUCCESS; +} +# endif + /* * Config file entries are of the form "/::". * If config file has no prefix match for path, access is allowed. @@ -1709,7 +1734,7 @@ static int checkPermIP(void) * * Returns 1 if user_and_passwd is OK. */ -static int check_user_passwd(const char *path, const char *user_and_passwd) +static int check_user_passwd(const char *path, char *user_and_passwd) { Htaccess *cur; const char *prev = NULL; @@ -1717,6 +1742,7 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) for (cur = g_auth; cur; cur = cur->next) { const char *dir_prefix; size_t len; + int r; dir_prefix = cur->before_colon; @@ -1732,7 +1758,8 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) 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')) + || (path[len] != '/' && path[len] != '\0') + ) ) { continue; } @@ -1741,38 +1768,105 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) prev = dir_prefix; if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { - char *md5_passwd; + char *colon_after_user; + const char *passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM + char sp_buf[256]; +# endif - 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; + colon_after_user = strchr(user_and_passwd, ':'); + if (!colon_after_user) + goto bad_input; - md5_passwd++; - user_len_p1 = md5_passwd - cur->after_colon; - /* comparing "user:" */ - if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { + /* compare "user:" */ + if (cur->after_colon[0] != '*' + && strncmp(cur->after_colon, user_and_passwd, + colon_after_user - user_and_passwd + 1) != 0 + ) { + continue; + } + /* this cfg entry is '*' or matches username from peer */ + + passwd = strchr(cur->after_colon, ':'); + if (!passwd) + goto bad_input; + passwd++; + if (passwd[0] == '*') { +# if ENABLE_PAM + struct pam_userinfo userinfo; + struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; + pam_handle_t *pamh; + + *colon_after_user = '\0'; + userinfo.name = user_and_passwd; + userinfo.pw = colon_after_user + 1; + r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS; + if (r == 0) { + r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + ; + pam_end(pamh, PAM_SUCCESS); + } + *colon_after_user = ':'; + goto end_check_passwd; +# else +# if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + struct spwd spw; +# endif + struct passwd *pw; + + *colon_after_user = '\0'; + pw = getpwnam(user_and_passwd); + *colon_after_user = ':'; + if (!pw || !pw->pw_passwd) continue; + passwd = pw->pw_passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS + if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[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, sp_buf, sizeof(sp_buf), &result); + if (r == 0 && result) + passwd = result->sp_pwdp; } +# endif + /* In this case, passwd is ALWAYS encrypted: + * it came from /etc/passwd or /etc/shadow! + */ + goto check_encrypted; +# endif /* ENABLE_PAM */ + } + /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ + if (passwd[0] == '$' && isdigit(passwd[1])) { + char *encrypted; +# if !ENABLE_PAM + check_encrypted: +# endif + /* encrypt pwd from peer and check match with local one */ encrypted = pw_encrypt( - user_and_passwd + user_len_p1 /* cleartext pwd from user */, - md5_passwd /*salt */, 1 /* cleanup */); - r = strcmp(encrypted, md5_passwd); + /* pwd (from peer): */ colon_after_user + 1, + /* salt: */ passwd, + /* cleanup: */ 0 + ); + r = strcmp(encrypted, passwd); free(encrypted); - if (r == 0) - goto set_remoteuser_var; /* Ok */ - continue; + } else { + /* local passwd is from httpd.conf and it's plaintext */ + r = strcmp(colon_after_user + 1, passwd); } + goto end_check_passwd; } - + bad_input: /* Comparing plaintext "user:pass" in one go */ - if (strcmp(cur->after_colon, user_and_passwd) == 0) { - set_remoteuser_var: + r = strcmp(cur->after_colon, user_and_passwd); + end_check_passwd: + if (r == 0) { remoteuser = xstrndup(user_and_passwd, - strchrnul(user_and_passwd, ':') - user_and_passwd); + strchrnul(user_and_passwd, ':') - user_and_passwd + ); return 1; /* Ok */ } } /* for */ @@ -1911,7 +2005,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* NB: urlcopy ptr is never changed after this */ /* Extract url args if present */ - g_query = NULL; + /* g_query = NULL; - already is */ tptr = strchr(urlcopy, '?'); if (tptr) { *tptr++ = '\0'; @@ -1919,7 +2013,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } /* Decode URL escape sequences */ - tptr = decodeString(urlcopy, 0); + tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); if (tptr == NULL) send_headers_and_exit(HTTP_BAD_REQUEST); if (tptr == urlcopy + 1) { @@ -1931,34 +2025,40 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Algorithm stolen from libbb bb_simplify_path(), * but don't strdup, retain trailing slash, protect root */ urlp = tptr = urlcopy; - do { + for (;;) { if (*urlp == '/') { /* skip duplicate (or initial) slash */ if (*tptr == '/') { - continue; + goto next_char; } 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 */ + if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) { + /* "..": be careful */ + /* protect root */ + if (urlp == urlcopy) send_headers_and_exit(HTTP_BAD_REQUEST); - while (*--urlp != '/') /* omit previous dir */; + /* omit previous dir */ + while (*--urlp != '/') continue; + /* skip to "./" or "." */ + tptr++; + } + if (tptr[1] == '/' || tptr[1] == '\0') { + /* skip extra "/./" */ + goto next_char; } } } *++urlp = *tptr; - } while (*++tptr); - *++urlp = '\0'; /* terminate after last character */ + if (*urlp == '\0') + break; + next_char: + tptr++; + } /* If URL is a directory, add '/' */ if (urlp[-1] != '/') { - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { found_moved_temporarily = urlcopy; } } @@ -1972,7 +2072,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) { /* have path1/path2 */ *tptr = '\0'; - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { /* may have subdir config */ parse_conf(urlcopy + 1, SUBDIR_PARSE); ip_allowed = checkPermIP(); @@ -2071,11 +2171,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) s += sizeof("bytes=")-1; range_start = BB_STRTOOFF(s, &s, 10); if (s[0] != '-' || range_start < 0) { - range_start = 0; + range_start = -1; } else if (s[1]) { range_end = BB_STRTOOFF(s+1, NULL, 10); if (errno || range_end < range_start) - range_start = 0; + range_start = -1; } } } @@ -2109,10 +2209,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH - /* Case: no "Authorization:" was seen, but page does require passwd. + /* Case: no "Authorization:" was seen, but page might require passwd. * Check that with dummy user:pass */ if (authorized < 0) - authorized = check_user_passwd(urlcopy, ":"); + authorized = check_user_passwd(urlcopy, (char *) ""); if (!authorized) send_headers_and_exit(HTTP_UNAUTHORIZED); #endif @@ -2158,12 +2258,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* protect listing "cgi-bin/" */ send_headers_and_exit(HTTP_FORBIDDEN); } - send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } #endif - if (urlp[-1] == '/') + if (urlp[-1] == '/') { + /* When index_page string is appended to / URL, it overwrites + * the query string. If we fall back to call /cgi-bin/index.cgi, + * query string would be lost and not available to the CGI. + * Work around it by making a deep copy. + */ + if (ENABLE_FEATURE_HTTPD_CGI) + g_query = xstrdup(g_query); /* ok for NULL too */ strcpy(urlp, index_page); + } if (stat(tptr, &sb) == 0) { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR char *suffix = strrchr(tptr, '.'); @@ -2171,7 +2279,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) 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); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } } } @@ -2184,9 +2292,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* 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); + urlp[0] = '\0'; /* remove index_page */ + send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type); } } /* else fall through to send_file, it errors out if open fails: */ @@ -2285,6 +2392,7 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) /* Run a copy of ourself in inetd mode */ re_exec(argv_copy); } + argv_copy[0][0] &= 0x7f; /* parent, or vfork failed */ close(n); } /* while (1) */ @@ -2378,7 +2486,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) , &verbose ); if (opt & OPT_DECODE_URL) { - fputs(decodeString(url_for_decode, 1), stdout); + fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout); return 0; } #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR @@ -2393,8 +2501,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) salt[0] = '$'; salt[1] = '1'; salt[2] = '$'; - crypt_make_salt(salt + 3, 4, 0); - puts(pw_encrypt(pass, salt, 1)); + crypt_make_salt(salt + 3, 4); + puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); return 0; } #endif diff --git a/release/src/router/busybox/networking/httpd_indexcgi.c b/release/src/router/busybox/networking/httpd_indexcgi.c index 7e0225e198..d732cd4f8a 100644 --- a/release/src/router/busybox/networking/httpd_indexcgi.c +++ b/release/src/router/busybox/networking/httpd_indexcgi.c @@ -221,20 +221,25 @@ int main(int argc, char *argv[]) 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, "//") - || strstr(QUERY_STRING, "/../") - || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 + char *location; + + location = getenv("REQUEST_URI"); + if (!location) + return 1; + + /* drop URL arguments if any */ + strchrnul(location, '?')[0] = '\0'; + + if (location[0] != '/' + || strstr(location, "//") + || strstr(location, "/../") + || strcmp(strrchr(location, '/'), "/..") == 0 ) { return 1; } if (chdir("..") - || (QUERY_STRING[1] && chdir(QUERY_STRING + 1)) + || (location[1] && chdir(location + 1)) ) { return 1; } @@ -271,14 +276,14 @@ int main(int argc, char *argv[]) "\r\n" /* Mandatory empty line after headers */ "Index of "); /* Guard against directories with &, > etc */ - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "\n" STYLE_STR "" "\n" "" "\n" "

Index of "); - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "

" "\n" "" "\n" diff --git a/release/src/router/busybox/networking/httpd_ssi.c b/release/src/router/busybox/networking/httpd_ssi.c index 87f43fcfa8..cfe64eb46e 100644 --- a/release/src/router/busybox/networking/httpd_ssi.c +++ b/release/src/router/busybox/networking/httpd_ssi.c @@ -52,9 +52,9 @@ httpd_ssi.c -o httpd_ssi static char* skip_whitespace(char *s) { - while (*s == ' ' || *s == '\t') ++s; + while (*s == ' ' || *s == '\t') ++s; - return s; + return s; } static char line[64 * 1024]; diff --git a/release/src/router/busybox/networking/ifconfig.c b/release/src/router/busybox/networking/ifconfig.c index da2635ce05..b6604f5d15 100644 --- a/release/src/router/busybox/networking/ifconfig.c +++ b/release/src/router/busybox/networking/ifconfig.c @@ -26,18 +26,34 @@ * IPV6 support added by Bart Visscher */ +//usage:#define ifconfig_trivial_usage +//usage: IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]" +//usage:#define ifconfig_full_usage "\n\n" +//usage: "Configure a network interface\n" +//usage: "\n" +//usage: IF_FEATURE_IPV6( +//usage: " [add ADDRESS[/PREFIXLEN]]\n") +//usage: IF_FEATURE_IPV6( +//usage: " [del ADDRESS[/PREFIXLEN]]\n") +//usage: " [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" +//usage: " [netmask ADDRESS] [dstaddr ADDRESS]\n" +//usage: IF_FEATURE_IFCONFIG_SLIP( +//usage: " [outfill NN] [keepalive NN]\n") +//usage: " " IF_FEATURE_IFCONFIG_HW("[hw ether" IF_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu NN]\n" +//usage: " [[-]trailers] [[-]arp] [[-]allmulti]\n" +//usage: " [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic]\n" +//usage: IF_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( +//usage: " [mem_start NN] [io_addr NN] [irq NN]\n") +//usage: " [up|down] ..." + +#include "libbb.h" +#include "inet_common.h" #include #include #include -#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 -#include -#include -#else -#include -#include +#ifdef HAVE_NET_ETHERNET_H +# include #endif -#include "libbb.h" -#include "inet_common.h" #if ENABLE_FEATURE_IFCONFIG_SLIP # include diff --git a/release/src/router/busybox/networking/ifenslave.c b/release/src/router/busybox/networking/ifenslave.c index 0b3ebf72ad..ae7719f52f 100644 --- a/release/src/router/busybox/networking/ifenslave.c +++ b/release/src/router/busybox/networking/ifenslave.c @@ -98,6 +98,32 @@ * set version to 1.1.0 */ +//usage:#define ifenslave_trivial_usage +//usage: "[-cdf] MASTER_IFACE SLAVE_IFACE..." +//usage:#define ifenslave_full_usage "\n\n" +//usage: "Configure network interfaces for parallel routing\n" +//usage: "\n -c,--change-active Change active slave" +//usage: "\n -d,--detach Remove slave interface from bonding device" +//usage: "\n -f,--force Force, even if interface is not Ethernet" +/* //usage: "\n -r,--receive-slave Create a receive-only slave" */ +//usage: +//usage:#define ifenslave_example_usage +//usage: "To create a bond device, simply follow these three steps:\n" +//usage: "- ensure that the required drivers are properly loaded:\n" +//usage: " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" +//usage: "- assign an IP address to the bond device:\n" +//usage: " # ifconfig bond0 netmask broadcast \n" +//usage: "- attach all the interfaces you need to the bond device:\n" +//usage: " # ifenslave bond0 eth0 eth1 eth2\n" +//usage: " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" +//usage: " interfaces attached AFTER this assignment will get the same MAC addr.\n\n" +//usage: " To detach a dead interface without setting the bond device down:\n" +//usage: " # ifenslave -d bond0 eth1\n\n" +//usage: " To set the bond device down and automatically release all the slaves:\n" +//usage: " # ifconfig bond0 down\n\n" +//usage: " To change active slave:\n" +//usage: " # ifenslave -c bond0 eth0\n" + #include "libbb.h" /* #include - no. linux/if_bonding.h pulls in linux/if.h */ diff --git a/release/src/router/busybox/networking/ifplugd.c b/release/src/router/busybox/networking/ifplugd.c index 58f56dbf15..d8358cdfd5 100644 --- a/release/src/router/busybox/networking/ifplugd.c +++ b/release/src/router/busybox/networking/ifplugd.c @@ -6,13 +6,40 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define ifplugd_trivial_usage +//usage: "[OPTIONS]" +//usage:#define ifplugd_full_usage "\n\n" +//usage: "Network interface plug detection daemon\n" +//usage: "\n -n Don't daemonize" +//usage: "\n -s Don't log to syslog" +//usage: "\n -i IFACE Interface" +//usage: "\n -f/-F Treat link detection error as link down/link up" +//usage: "\n (otherwise exit on error)" +//usage: "\n -a Don't up interface at each link probe" +//usage: "\n -M Monitor creation/destruction of interface" +//usage: "\n (otherwise it must exist)" +//usage: "\n -r PROG Script to run" +//usage: "\n -x ARG Extra argument for script" +//usage: "\n -I Don't exit on nonzero exit code from script" +//usage: "\n -p Don't run script on daemon startup" +//usage: "\n -q Don't run script on daemon quit" +//usage: "\n -l Run script on startup even if no cable is detected" +//usage: "\n -t SECS Poll time in seconds" +//usage: "\n -u SECS Delay before running script after link up" +//usage: "\n -d SECS Delay after link down" +//usage: "\n -m MODE API mode (mii, priv, ethtool, wlan, iff, auto)" +//usage: "\n -k Kill running daemon" + #include "libbb.h" #include "fix_u32.h" #include #include #include -#include +#ifdef HAVE_NET_ETHERNET_H +# include +#endif #include #include #include @@ -131,18 +158,21 @@ static int network_ioctl(int request, void* data, const char *errmsg) static smallint detect_link_mii(void) { - struct ifreq ifreq; - struct mii_ioctl_data *mii = (void *)&ifreq.ifr_data; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char buf[sizeof(struct ifreq)]; + struct ifreq *const ifreq = (void *)buf; - set_ifreq_to_ifname(&ifreq); + struct mii_ioctl_data *mii = (void *)&ifreq->ifr_data; - if (network_ioctl(SIOCGMIIPHY, &ifreq, "SIOCGMIIPHY") < 0) { + set_ifreq_to_ifname(ifreq); + + if (network_ioctl(SIOCGMIIPHY, ifreq, "SIOCGMIIPHY") < 0) { return IFSTATUS_ERR; } mii->reg_num = 1; - if (network_ioctl(SIOCGMIIREG, &ifreq, "SIOCGMIIREG") < 0) { + if (network_ioctl(SIOCGMIIREG, ifreq, "SIOCGMIIREG") < 0) { return IFSTATUS_ERR; } @@ -151,18 +181,21 @@ static smallint detect_link_mii(void) static smallint detect_link_priv(void) { - struct ifreq ifreq; - struct mii_ioctl_data *mii = (void *)&ifreq.ifr_data; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char buf[sizeof(struct ifreq)]; + struct ifreq *const ifreq = (void *)buf; - set_ifreq_to_ifname(&ifreq); + struct mii_ioctl_data *mii = (void *)&ifreq->ifr_data; + + set_ifreq_to_ifname(ifreq); - if (network_ioctl(SIOCDEVPRIVATE, &ifreq, "SIOCDEVPRIVATE") < 0) { + if (network_ioctl(SIOCDEVPRIVATE, ifreq, "SIOCDEVPRIVATE") < 0) { return IFSTATUS_ERR; } mii->reg_num = 1; - if (network_ioctl(SIOCDEVPRIVATE+1, &ifreq, "SIOCDEVPRIVATE+1") < 0) { + if (network_ioctl(SIOCDEVPRIVATE+1, ifreq, "SIOCDEVPRIVATE+1") < 0) { return IFSTATUS_ERR; } diff --git a/release/src/router/busybox/networking/ifupdown.c b/release/src/router/busybox/networking/ifupdown.c index 59df4e80fa..9b34986964 100644 --- a/release/src/router/busybox/networking/ifupdown.c +++ b/release/src/router/busybox/networking/ifupdown.c @@ -17,6 +17,32 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ifup_trivial_usage +//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." +//usage:#define ifup_full_usage "\n\n" +//usage: " -a De/configure all interfaces automatically" +//usage: "\n -i FILE Use FILE for interface definitions" +//usage: "\n -n Print out what would happen, but don't do it" +//usage: IF_FEATURE_IFUPDOWN_MAPPING( +//usage: "\n (note: doesn't disable mappings)" +//usage: "\n -m Don't run any mappings" +//usage: ) +//usage: "\n -v Print out what would happen before doing it" +//usage: "\n -f Force de/configuration" +//usage: +//usage:#define ifdown_trivial_usage +//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." +//usage:#define ifdown_full_usage "\n\n" +//usage: " -a De/configure all interfaces automatically" +//usage: "\n -i FILE Use FILE for interface definitions" +//usage: "\n -n Print out what would happen, but don't do it" +//usage: IF_FEATURE_IFUPDOWN_MAPPING( +//usage: "\n (note: doesn't disable mappings)" +//usage: "\n -m Don't run any mappings" +//usage: ) +//usage: "\n -v Print out what would happen before doing it" +//usage: "\n -f Force de/configuration" + #include "libbb.h" /* After libbb.h, since it needs sys/types.h on some systems */ #include @@ -61,7 +87,6 @@ struct mapping_defn_t { char *script; - int max_mappings; int n_mappings; char **mapping; }; @@ -76,7 +101,6 @@ struct interface_defn_t { const struct method_t *method; char *iface; - int max_options; int n_options; struct variable_t *option; }; @@ -106,11 +130,20 @@ enum { struct globals { char **my_environ; const char *startup_PATH; + char *shell; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) +static const char keywords_up_down[] ALIGN1 = + "up\0" + "down\0" + "pre-up\0" + "post-down\0" +; + + #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 static void addstr(char **bufp, const char *str, size_t str_length) @@ -368,11 +401,11 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ - result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); + result += execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd, exec); # else result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); - result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); + result += execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd, exec); # endif return ((result == 3) ? 3 : 0); } @@ -455,7 +488,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); - result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); + result += execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd, exec); return ((result == 3) ? 3 : 0); # else /* ifconfig said to set iface up before it processes hw %hwaddress%, @@ -465,7 +498,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) result += execute("ifconfig %iface% %address% netmask %netmask%" "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ", ifd, exec); - result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); + result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec); return ((result == 3) ? 3 : 0); # endif } @@ -776,7 +809,6 @@ static struct interfaces_file_t *read_interfaces(const char *filename) currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches); currmap->match[currmap->n_matches++] = xstrdup(first_word); } - /*currmap->max_mappings = 0; - done by xzalloc */ /*currmap->n_mappings = 0;*/ /*currmap->mapping = NULL;*/ /*currmap->script = NULL;*/ @@ -861,23 +893,21 @@ static struct interfaces_file_t *read_interfaces(const char *filename) if (rest_of_line[0] == '\0') bb_error_msg_and_die("option with empty value \"%s\"", buf); - if (strcmp(first_word, "up") != 0 - && strcmp(first_word, "down") != 0 - && strcmp(first_word, "pre-up") != 0 - && strcmp(first_word, "post-down") != 0 - ) { + if (strcmp(first_word, "post-up") == 0) + first_word += 5; /* "up" */ + else if (strcmp(first_word, "pre-down") == 0) + first_word += 4; /* "down" */ + + /* If not one of "up", "down",... words... */ + if (index_in_strings(keywords_up_down, first_word) < 0) { int i; for (i = 0; i < currif->n_options; i++) { if (strcmp(currif->option[i].name, first_word) == 0) bb_error_msg_and_die("duplicate option \"%s\"", buf); } } - if (currif->n_options >= currif->max_options) { - currif->max_options += 10; - currif->option = xrealloc(currif->option, - sizeof(*currif->option) * currif->max_options); - } debug_noise("\t%s=%s\n", first_word, rest_of_line); + currif->option = xrealloc_vector(currif->option, 4, currif->n_options); currif->option[currif->n_options].name = xstrdup(first_word); currif->option[currif->n_options].value = xstrdup(rest_of_line); currif->n_options++; @@ -889,11 +919,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf); currmap->script = xstrdup(next_word(&rest_of_line)); } else if (strcmp(first_word, "map") == 0) { - if (currmap->n_mappings >= currmap->max_mappings) { - currmap->max_mappings = currmap->max_mappings * 2 + 1; - currmap->mapping = xrealloc(currmap->mapping, - sizeof(char *) * currmap->max_mappings); - } + currmap->mapping = xrealloc_vector(currmap->mapping, 2, currmap->n_mappings); currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line)); currmap->n_mappings++; } else { @@ -940,7 +966,7 @@ static char *setlocalenv(const char *format, const char *name, const char *value return result; } -static void set_environ(struct interface_defn_t *iface, const char *mode) +static void set_environ(struct interface_defn_t *iface, const char *mode, const char *opt) { int i; char **pp; @@ -953,15 +979,11 @@ static void set_environ(struct interface_defn_t *iface, const char *mode) } /* note: last element will stay NULL: */ - G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 6)); + G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 7)); pp = G.my_environ; for (i = 0; i < iface->n_options; i++) { - if (strcmp(iface->option[i].name, "up") == 0 - || strcmp(iface->option[i].name, "down") == 0 - || strcmp(iface->option[i].name, "pre-up") == 0 - || strcmp(iface->option[i].name, "post-down") == 0 - ) { + if (index_in_strings(keywords_up_down, iface->option[i].name) >= 0) { continue; } *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value); @@ -971,6 +993,7 @@ static void set_environ(struct interface_defn_t *iface, const char *mode) *pp++ = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name); *pp++ = setlocalenv("%s=%s", "METHOD", iface->method->name); *pp++ = setlocalenv("%s=%s", "MODE", mode); + *pp++ = setlocalenv("%s=%s", "PHASE", opt); if (G.startup_PATH) *pp++ = setlocalenv("%s=%s", "PATH", G.startup_PATH); } @@ -986,11 +1009,10 @@ static int doit(char *str) fflush_all(); child = vfork(); - switch (child) { - case -1: /* failure */ + if (child < 0) /* failure */ return 0; - case 0: /* child */ - execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, (char *) NULL, G.my_environ); + if (child == 0) { /* child */ + execle(G.shell, G.shell, "-c", str, (char *) NULL, G.my_environ); _exit(127); } safe_waitpid(child, &status, 0); @@ -1026,9 +1048,10 @@ static int check(char *str) static int iface_up(struct interface_defn_t *iface) { if (!iface->method->up(iface, check)) return -1; - set_environ(iface, "start"); + set_environ(iface, "start", "pre-up"); if (!execute_all(iface, "pre-up")) return 0; if (!iface->method->up(iface, doit)) return 0; + set_environ(iface, "start", "post-up"); if (!execute_all(iface, "up")) return 0; return 1; } @@ -1036,9 +1059,10 @@ static int iface_up(struct interface_defn_t *iface) static int iface_down(struct interface_defn_t *iface) { if (!iface->method->down(iface,check)) return -1; - set_environ(iface, "stop"); + set_environ(iface, "stop", "pre-down"); if (!execute_all(iface, "down")) return 0; if (!iface->method->down(iface, doit)) return 0; + set_environ(iface, "stop", "post-down"); if (!execute_all(iface, "post-down")) return 0; return 1; } @@ -1165,6 +1189,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) INIT_G(); G.startup_PATH = getenv("PATH"); + G.shell = xstrdup(get_shell_name()); cmds = iface_down; if (applet_name[2] == 'u') { @@ -1220,13 +1245,13 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) /* ifup */ if (iface_state) { bb_error_msg("interface %s already configured", iface); - continue; + goto next; } } else { /* ifdown */ if (!iface_state) { bb_error_msg("interface %s not configured", iface); - continue; + goto next; } } llist_free(state_list, free); @@ -1290,9 +1315,9 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) llist_t *state_list = read_iface_state(); llist_t *iface_state = find_iface_state(state_list, iface); - if (cmds == iface_up) { - char * const newiface = xasprintf("%s=%s", iface, liface); - if (iface_state == NULL) { + if (cmds == iface_up && !any_failures) { + char *newiface = xasprintf("%s=%s", iface, liface); + if (!iface_state) { llist_add_to_end(&state_list, newiface); } else { free(iface_state->data); @@ -1316,6 +1341,9 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) fclose(state_fp); llist_free(state_list, free); } + next: + free(iface); + free(liface); } return any_failures; diff --git a/release/src/router/busybox/networking/inetd.c b/release/src/router/busybox/networking/inetd.c index fb00c6cd71..26b66992d4 100644 --- a/release/src/router/busybox/networking/inetd.c +++ b/release/src/router/busybox/networking/inetd.c @@ -154,14 +154,27 @@ * setuid() */ +//usage:#define inetd_trivial_usage +//usage: "[-fe] [-q N] [-R N] [CONFFILE]" +//usage:#define inetd_full_usage "\n\n" +//usage: "Listen for network connections and launch programs\n" +//usage: "\n -f Run in foreground" +//usage: "\n -e Log to stderr" +//usage: "\n -q N Socket listen queue (default: 128)" +//usage: "\n -R N Pause services after N connects/min" +//usage: "\n (default: 0 - disabled)" + #include #include #include "libbb.h" #if ENABLE_FEATURE_INETD_RPC -#include -#include +# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) +# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support" +# endif +# include +# include #endif #if !BB_MMU @@ -344,10 +357,26 @@ struct BUG_G_too_big { config_filename = "/etc/inetd.conf"; \ } while (0) +#if 1 +# define dbg(...) ((void)0) +#else +# define dbg(...) \ +do { \ + int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \ + if (dbg_fd >= 0) { \ + fdprintf(dbg_fd, "%d: ", getpid()); \ + fdprintf(dbg_fd, __VA_ARGS__); \ + close(dbg_fd); \ + } \ +} while (0) +#endif + static void maybe_close(int fd) { - if (fd >= 0) + if (fd >= 0) { close(fd); + dbg("closed fd:%d\n", fd); + } } // TODO: move to libbb? @@ -451,7 +480,9 @@ static void remove_fd_from_set(int fd) { if (fd >= 0) { FD_CLR(fd, &allsock); + dbg("stopped listening on fd:%d\n", fd); maxsock = -1; + dbg("maxsock:%d\n", maxsock); } } @@ -459,8 +490,10 @@ static void add_fd_to_set(int fd) { if (fd >= 0) { FD_SET(fd, &allsock); + dbg("started listening on fd:%d\n", fd); if (maxsock >= 0 && fd > maxsock) { prev_maxsock = maxsock = fd; + dbg("maxsock:%d\n", maxsock); if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) bump_nofile(); } @@ -479,6 +512,7 @@ static void recalculate_maxsock(void) maxsock = fd; fd++; } + dbg("recalculated maxsock:%d\n", maxsock); prev_maxsock = maxsock; if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) bump_nofile(); @@ -501,7 +535,7 @@ static void prepare_socket_fd(servtab_t *sep) /* zero out the port for all RPC services; let bind() * find one. */ - set_nport(sep->se_lsa, 0); + set_nport(&sep->se_lsa->u.sa, 0); /* for RPC services, attempt to use a reserved port * if they are going to be running as root. */ @@ -536,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep) rearm_alarm(); return; } - if (sep->se_socktype == SOCK_STREAM) + + if (sep->se_socktype == SOCK_STREAM) { listen(fd, global_queuelen); + dbg("new sep->se_fd:%d (stream)\n", fd); + } else { + dbg("new sep->se_fd:%d (!stream)\n", fd); + } add_fd_to_set(fd); sep->se_fd = fd; @@ -959,7 +998,7 @@ static void reread_config_file(int sig UNUSED_PARAM) } if (LONE_CHAR(sep->se_local_hostname, '*')) { lsa = xzalloc_lsa(sep->se_family); - set_nport(lsa, port); + set_nport(&lsa->u.sa, port); } else { lsa = host_and_af2sockaddr(sep->se_local_hostname, ntohs(port), sep->se_family); @@ -999,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM) * new config file doesnt have them. */ block_CHLD_HUP_ALRM(&omask); sepp = &serv_list; - while ((sep = *sepp)) { + while ((sep = *sepp) != NULL) { if (sep->se_checked) { sepp = &sep->se_next; continue; @@ -1153,12 +1192,17 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sigaddset(&sa.sa_mask, SIGALRM); sigaddset(&sa.sa_mask, SIGCHLD); sigaddset(&sa.sa_mask, SIGHUP); +//FIXME: explain why no SA_RESTART +//FIXME: retry_network_setup is unsafe to run in signal handler (many reasons)! sa.sa_handler = retry_network_setup; sigaction_set(SIGALRM, &sa); +//FIXME: reread_config_file is unsafe to run in signal handler(many reasons)! sa.sa_handler = reread_config_file; sigaction_set(SIGHUP, &sa); +//FIXME: reap_child is unsafe to run in signal handler (uses stdio)! sa.sa_handler = reap_child; sigaction_set(SIGCHLD, &sa); +//FIXME: clean_up_and_exit is unsafe to run in signal handler (uses stdio)! sa.sa_handler = clean_up_and_exit; sigaction_set(SIGTERM, &sa); sa.sa_handler = clean_up_and_exit; @@ -1188,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) } continue; } + dbg("ready_fd_cnt:%d\n", ready_fd_cnt); for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) continue; + dbg("ready fd:%d\n", sep->se_fd); ready_fd_cnt--; ctrl = sep->se_fd; accepted_fd = -1; @@ -1200,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) if (!sep->se_wait) { if (sep->se_socktype == SOCK_STREAM) { ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); + dbg("accepted_fd:%d\n", accepted_fd); if (ctrl < 0) { if (errno != EINTR) bb_perror_msg("accept (for %s)", sep->se_service); @@ -1220,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * (can create many copies of same child, etc). * Parent must create and use new socket instead. */ new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); + dbg("new_udp_fd:%d\n", new_udp_fd); if (new_udp_fd < 0) { /* error: eat packet, forget about it */ udp_err: recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); continue; } setsockopt_reuseaddr(new_udp_fd); - /* TODO: better do bind after vfork in parent, + /* TODO: better do bind after fork in parent, * so that we don't have two wildcard bound sockets * even for a brief moment? */ if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { + dbg("bind(new_udp_fd) failed\n"); close(new_udp_fd); goto udp_err; } + dbg("bind(new_udp_fd) succeeded\n"); } } @@ -1260,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_count = 0; rearm_alarm(); /* will revive it in RETRYTIME sec */ restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } @@ -1280,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_perror_msg("vfork"+1); sleep(1); restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } if (pid == 0) pid--; /* -1: "we did fork and we are child" */ } - /* if pid == 0 here, we never forked */ + /* if pid == 0 here, we didn't fork */ if (pid > 0) { /* parent */ if (sep->se_wait) { - /* tcp wait: we passed listening socket to child, + /* wait: we passed socket to child, * will wait for child to terminate */ sep->se_wait = pid; remove_fd_from_set(sep->se_fd); @@ -1299,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) /* udp nowait: child connected the socket, * we created and will use new, unconnected one */ xmove_fd(new_udp_fd, sep->se_fd); + dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd); } restore_sigmask(&omask); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } - /* we are either child or didn't vfork at all */ + /* we are either child or didn't fork at all */ #ifdef INETD_BUILTINS_ENABLED if (sep->se_builtin) { - if (pid) { /* "pid" is -1: we did vfork */ + if (pid) { /* "pid" is -1: we did fork */ close(sep->se_fd); /* listening socket */ + dbg("closed sep->se_fd:%d\n", sep->se_fd); logmode = LOGMODE_NONE; /* make xwrite etc silent */ } restore_sigmask(&omask); @@ -1317,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_builtin->bi_stream_fn(ctrl, sep); else sep->se_builtin->bi_dgram_fn(ctrl, sep); - if (pid) /* we did vfork */ + if (pid) /* we did fork */ _exit(EXIT_FAILURE); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ @@ -1327,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) setsid(); /* "nowait" udp */ if (new_udp_fd >= 0) { - len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); + len_and_sockaddr *lsa; + int r; + + close(new_udp_fd); + dbg("closed new_udp_fd:%d\n", new_udp_fd); + lsa = xzalloc_lsa(sep->se_family); /* peek at the packet and remember peer addr */ - int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, + r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, &lsa->u.sa, &lsa->len); if (r < 0) goto do_exit1; @@ -1337,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * only packets from this peer will be recv'ed, * and bare write()/send() will work on it */ connect(ctrl, &lsa->u.sa, lsa->len); + dbg("connected ctrl:%d to remote peer\n", ctrl); free(lsa); } /* prepare env and exec program */ @@ -1354,7 +1414,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("non-root must run services as himself"); goto do_exit1; } - if (pwd->pw_uid) { + if (pwd->pw_uid != 0) { if (sep->se_group) pwd->pw_gid = grp->gr_gid; /* initgroups, setgid, setuid: */ @@ -1373,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) */ xmove_fd(ctrl, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); + dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl); /* manpages of inetd I managed to find either say * that stderr is also redirected to the network, * or do not talk about redirection at all (!) */ @@ -1385,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) maybe_close(sep2->se_fd); sigaction_set(SIGPIPE, &saved_pipe_handler); restore_sigmask(&omask); + dbg("execing:'%s'\n", sep->se_program); BB_EXECVP(sep->se_program, sep->se_argv); bb_perror_msg("can't execute '%s'", sep->se_program); do_exit1: diff --git a/release/src/router/busybox/networking/interface.c b/release/src/router/busybox/networking/interface.c index c5b939435f..4a319bfb3b 100644 --- a/release/src/router/busybox/networking/interface.c +++ b/release/src/router/busybox/networking/interface.c @@ -30,15 +30,14 @@ * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu * (default AF was wrong) */ + +#include "libbb.h" +#include "inet_common.h" #include #include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) +#ifdef HAVE_NET_ETHERNET_H # include -#else -# include #endif -#include "libbb.h" -#include "inet_common.h" #if ENABLE_FEATURE_HWIB /* #include */ diff --git a/release/src/router/busybox/networking/ip.c b/release/src/router/busybox/networking/ip.c index 350656cef7..98fe621b16 100644 --- a/release/src/router/busybox/networking/ip.c +++ b/release/src/router/busybox/networking/ip.c @@ -9,6 +9,78 @@ * Bernhard Reutner-Fischer rewrote to use index_in_substr_array */ +/* would need to make the " | " optional depending on more than one selected: */ +//usage:#define ip_trivial_usage +//usage: "[OPTIONS] {" +//usage: IF_FEATURE_IP_ADDRESS("address | ") +//usage: IF_FEATURE_IP_ROUTE("route | ") +//usage: IF_FEATURE_IP_LINK("link | ") +//usage: IF_FEATURE_IP_TUNNEL("tunnel | ") +//usage: IF_FEATURE_IP_RULE("rule") +//usage: "} {COMMAND}" +//usage:#define ip_full_usage "\n\n" +//usage: "ip [OPTIONS] OBJECT {COMMAND}\n" +//usage: "where OBJECT := {" +//usage: IF_FEATURE_IP_ADDRESS("address | ") +//usage: IF_FEATURE_IP_ROUTE("route | ") +//usage: IF_FEATURE_IP_LINK("link | ") +//usage: IF_FEATURE_IP_TUNNEL("tunnel | ") +//usage: IF_FEATURE_IP_RULE("rule") +//usage: "}\n" +//usage: "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" +//usage: +//usage:#define ipaddr_trivial_usage +//usage: "{ {add|del} IFADDR dev STRING | {show|flush}\n" +//usage: " [dev STRING] [to PREFIX] }" +//usage:#define ipaddr_full_usage "\n\n" +//usage: "ipaddr {add|delete} IFADDR dev STRING\n" +//usage: "ipaddr {show|flush} [dev STRING] [scope SCOPE-ID]\n" +//usage: " [to PREFIX] [label PATTERN]\n" +//usage: " IFADDR := PREFIX | ADDR peer PREFIX\n" +//usage: " [broadcast ADDR] [anycast ADDR]\n" +//usage: " [label STRING] [scope SCOPE-ID]\n" +//usage: " SCOPE-ID := [host | link | global | NUMBER]" +//usage: +//usage:#define iplink_trivial_usage +//usage: "{ set DEVICE { up | down | arp { on | off } | show [DEVICE] }" +//usage:#define iplink_full_usage "\n\n" +//usage: "iplink set DEVICE { up | down | arp | multicast { on | off } |\n" +//usage: " dynamic { on | off } |\n" +//usage: " mtu MTU }\n" +//usage: "iplink show [DEVICE]" +//usage: +//usage:#define iproute_trivial_usage +//usage: "{ list | flush | add | del | change | append |\n" +//usage: " replace | test } ROUTE" +//usage:#define iproute_full_usage "\n\n" +//usage: "iproute { list | flush } SELECTOR\n" +//usage: "iproute get ADDRESS [from ADDRESS iif STRING]\n" +//usage: " [oif STRING] [tos TOS]\n" +//usage: "iproute { add | del | change | append | replace | test } ROUTE\n" +//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" +//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO] [metric METRIC]" +//usage: +//usage:#define iprule_trivial_usage +//usage: "{[list | add | del] RULE}" +//usage:#define iprule_full_usage "\n\n" +//usage: "iprule [list | add | del] SELECTOR ACTION\n" +//usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n" +//usage: " [dev STRING] [pref NUMBER]\n" +//usage: " ACTION := [table TABLE_ID] [nat ADDRESS]\n" +//usage: " [prohibit | reject | unreachable]\n" +//usage: " [realms [SRCREALM/]DSTREALM]\n" +//usage: " TABLE_ID := [local | main | default | NUMBER]" +//usage: +//usage:#define iptunnel_trivial_usage +//usage: "{ add | change | del | show } [NAME]\n" +//usage: " [mode { ipip | gre | sit }]\n" +//usage: " [remote ADDR] [local ADDR] [ttl TTL]" +//usage:#define iptunnel_full_usage "\n\n" +//usage: "iptunnel { add | change | del | show } [NAME]\n" +//usage: " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" +//usage: " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" +//usage: " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" + #include "libbb.h" #include "libiproute/utils.h" diff --git a/release/src/router/busybox/networking/ipcalc.c b/release/src/router/busybox/networking/ipcalc.c index acbaa4ac50..3c8b8bfc91 100644 --- a/release/src/router/busybox/networking/ipcalc.c +++ b/release/src/router/busybox/networking/ipcalc.c @@ -11,6 +11,32 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define ipcalc_trivial_usage +//usage: "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" +//usage:#define ipcalc_full_usage "\n\n" +//usage: "Calculate IP network settings from a IP address\n" +//usage: IF_FEATURE_IPCALC_LONG_OPTIONS( +//usage: "\n -b,--broadcast Display calculated broadcast address" +//usage: "\n -n,--network Display calculated network address" +//usage: "\n -m,--netmask Display default netmask for IP" +//usage: IF_FEATURE_IPCALC_FANCY( +//usage: "\n -p,--prefix Display the prefix for IP/NETMASK" +//usage: "\n -h,--hostname Display first resolved host name" +//usage: "\n -s,--silent Don't ever display error messages" +//usage: ) +//usage: ) +//usage: IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( +//usage: "\n -b Display calculated broadcast address" +//usage: "\n -n Display calculated network address" +//usage: "\n -m Display default netmask for IP" +//usage: IF_FEATURE_IPCALC_FANCY( +//usage: "\n -p Display the prefix for IP/NETMASK" +//usage: "\n -h Display first resolved host name" +//usage: "\n -s Don't ever display error messages" +//usage: ) +//usage: ) + #include "libbb.h" /* After libbb.h, because on some systems it needs other includes */ #include diff --git a/release/src/router/busybox/networking/isrv_identd.c b/release/src/router/busybox/networking/isrv_identd.c index 18ce59aaf7..a41405c333 100644 --- a/release/src/router/busybox/networking/isrv_identd.c +++ b/release/src/router/busybox/networking/isrv_identd.c @@ -7,6 +7,16 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define fakeidentd_trivial_usage +//usage: "[-fiw] [-b ADDR] [STRING]" +//usage:#define fakeidentd_full_usage "\n\n" +//usage: "Provide fake ident (auth) service\n" +//usage: "\n -f Run in foreground" +//usage: "\n -i Inetd mode" +//usage: "\n -w Inetd 'wait' mode" +//usage: "\n -b ADDR Bind to specified address" +//usage: "\n STRING Ident answer string (default: nobody)" + #include "libbb.h" #include #include "isrv.h" diff --git a/release/src/router/busybox/networking/libiproute/ipaddress.c b/release/src/router/busybox/networking/libiproute/ipaddress.c index 397a8ee342..b3748e8c59 100644 --- a/release/src/router/busybox/networking/libiproute/ipaddress.c +++ b/release/src/router/busybox/networking/libiproute/ipaddress.c @@ -162,6 +162,8 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } #endif +/* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */ +#ifdef IFF_DORMANT if (tb[IFLA_OPERSTATE]) { static const char operstate_labels[] ALIGN1 = "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0" @@ -169,6 +171,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("state %s ", nth_string(operstate_labels, *(uint8_t *)RTA_DATA(tb[IFLA_OPERSTATE]))); } +#endif if (G_filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); diff --git a/release/src/router/busybox/networking/libiproute/iplink.c b/release/src/router/busybox/networking/libiproute/iplink.c index 82ab979a5b..bad2017feb 100644 --- a/release/src/router/busybox/networking/libiproute/iplink.c +++ b/release/src/router/busybox/networking/libiproute/iplink.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" diff --git a/release/src/router/busybox/networking/libiproute/iproute.c b/release/src/router/busybox/networking/libiproute/iproute.c index f6071b4634..f8a67d9eed 100644 --- a/release/src/router/busybox/networking/libiproute/iproute.c +++ b/release/src/router/busybox/networking/libiproute/iproute.c @@ -31,8 +31,8 @@ struct filter_t { //int type; - read-only //int typemask; - unused //int tos, tosmask; - unused - int iif, iifmask; - int oif, oifmask; + int iif; + int oif; //int realm, realmmask; - unused //inet_prefix rprefsrc; - read-only inet_prefix rvia; @@ -82,7 +82,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, { struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; @@ -159,8 +159,21 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, } memset(tb, 0, sizeof(tb)); + memset(&src, 0, sizeof(src)); + memset(&dst, 0, sizeof(dst)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + if (tb[RTA_SRC]) { + src.bitlen = r->rtm_src_len; + src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen); + } + if (tb[RTA_DST]) { + dst.bitlen = r->rtm_dst_len; + dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen); + } + if (G_filter.rdst.family && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen) ) { @@ -182,23 +195,32 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, ) { return 0; } - if (G_filter.flushb - && r->rtm_family == AF_INET6 - && r->rtm_dst_len == 0 - && r->rtm_type == RTN_UNREACHABLE - && tb[RTA_PRIORITY] - && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 - ) { - return 0; + if (G_filter.oif != 0) { + if (!tb[RTA_OIF]) + return 0; + if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF])) + return 0; } if (G_filter.flushb) { struct nlmsghdr *fn; + + /* We are creating route flush commands */ + + if (r->rtm_family == AF_INET6 + && r->rtm_dst_len == 0 + && r->rtm_type == RTN_UNREACHABLE + && tb[RTA_PRIORITY] + && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 + ) { + return 0; + } + if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { if (flush_update()) bb_error_msg_and_die("flush"); } - fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); + fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; @@ -208,6 +230,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, return 0; } + /* We are printing routes */ + if (n->nlmsg_type == RTM_DELROUTE) { printf("Deleted "); } @@ -257,10 +281,12 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } - if (tb[RTA_OIF] && G_filter.oifmask != -1) { + if (tb[RTA_OIF]) { printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); } + /* Todo: parse & show "proto kernel", "scope link" here */ + if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. @@ -292,7 +318,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, printf(" error %d", ci->rta_error); } } - if (tb[RTA_IIF] && G_filter.iifmask != -1) { + if (tb[RTA_IIF] && G_filter.iif == 0) { printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); } bb_putchar('\n'); @@ -413,7 +439,8 @@ IF_FEATURE_IP_RULE(ARG_table,) NEXT_ARG(); } if ((**argv < '0' || **argv > '9') - && rtnl_rtntype_a2n(&type, *argv) == 0) { + && rtnl_rtntype_a2n(&type, *argv) == 0 + ) { NEXT_ARG(); req.r.rtm_type = type; ok |= type_ok; @@ -662,12 +689,10 @@ static int iproute_list_or_flush(char **argv, int flush) if (id) { idx = xll_name_to_index(id); G_filter.iif = idx; - G_filter.iifmask = -1; } if (od) { idx = xll_name_to_index(od); G_filter.oif = idx; - G_filter.oifmask = -1; } } diff --git a/release/src/router/busybox/networking/libiproute/libnetlink.c b/release/src/router/busybox/networking/libiproute/libnetlink.c index 7291ee2f10..c7533a4a70 100644 --- a/release/src/router/busybox/networking/libiproute/libnetlink.c +++ b/release/src/router/busybox/networking/libiproute/libnetlink.c @@ -55,6 +55,7 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty return rtnl_send(rth, (void*)&req, sizeof(req)); } +//TODO: pass rth->fd instead of full rth? int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; @@ -392,7 +393,7 @@ void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, in if (rta->rta_type <= max) { tb[rta->rta_type] = rta; } - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) { bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); diff --git a/release/src/router/busybox/networking/libiproute/ll_proto.c b/release/src/router/busybox/networking/libiproute/ll_proto.c index 04925ecf68..7aac8364d3 100644 --- a/release/src/router/busybox/networking/libiproute/ll_proto.c +++ b/release/src/router/busybox/networking/libiproute/ll_proto.c @@ -12,11 +12,7 @@ #include "rt_names.h" #include "utils.h" -#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 -#include -#else -#include -#endif +#include #if !ENABLE_WERROR #warning de-bloat diff --git a/release/src/router/busybox/networking/libiproute/ll_types.c b/release/src/router/busybox/networking/libiproute/ll_types.c index 38b6c05166..bb42e269e5 100644 --- a/release/src/router/busybox/networking/libiproute/ll_types.c +++ b/release/src/router/busybox/networking/libiproute/ll_types.c @@ -7,6 +7,7 @@ * * Authors: Alexey Kuznetsov, */ +#include /* linux/if_arp.h needs it on some systems */ #include #include diff --git a/release/src/router/busybox/networking/libiproute/utils.c b/release/src/router/busybox/networking/libiproute/utils.c index d32db8de5d..d0fe30605c 100644 --- a/release/src/router/busybox/networking/libiproute/utils.c +++ b/release/src/router/busybox/networking/libiproute/utils.c @@ -83,20 +83,43 @@ int get_addr_1(inet_prefix *addr, char *name, int family) return 0; } - addr->family = AF_INET; if (family != AF_UNSPEC && family != AF_INET) return -1; + + /* Try to parse it as IPv4 */ + addr->family = AF_INET; +#if 0 /* Doesn't handle e.g. "10.10", for example, "ip r l root 10.10/16" */ if (inet_pton(AF_INET, name, addr->data) <= 0) return -1; +#else + { + unsigned i = 0; + unsigned n = 0; + const char *cp = name - 1; + while (*++cp) { + if ((unsigned char)(*cp - '0') <= 9) { + n = 10 * n + (unsigned char)(*cp - '0'); + if (n >= 256) + return -1; + ((uint8_t*)addr->data)[i] = n; + continue; + } + if (*cp == '.' && ++i <= 3) { + n = 0; + continue; + } + return -1; + } + } +#endif addr->bytelen = 4; addr->bitlen = -1; + return 0; } -static int get_prefix_1(inet_prefix *dst, char *arg, int family) +static void get_prefix_1(inet_prefix *dst, char *arg, int family) { - int err; - unsigned plen; char *slash; memset(dst, 0, sizeof(*dst)); @@ -108,48 +131,50 @@ static int get_prefix_1(inet_prefix *dst, char *arg, int family) dst->family = family; /*dst->bytelen = 0; - done by memset */ /*dst->bitlen = 0;*/ - return 0; + return; } slash = strchr(arg, '/'); if (slash) *slash = '\0'; - err = get_addr_1(dst, arg, family); - if (err == 0) { + + if (get_addr_1(dst, arg, family) == 0) { dst->bitlen = (dst->family == AF_INET6) ? 128 : 32; if (slash) { + unsigned plen; inet_prefix netmask_pfx; netmask_pfx.family = AF_UNSPEC; plen = bb_strtou(slash + 1, NULL, 0); if ((errno || plen > dst->bitlen) - && (get_addr_1(&netmask_pfx, slash + 1, family))) - err = -1; - else if (netmask_pfx.family == AF_INET) { + && get_addr_1(&netmask_pfx, slash + 1, family) != 0 + ) { + goto bad; + } + if (netmask_pfx.family == AF_INET) { /* fill in prefix length of dotted quad */ uint32_t mask = ntohl(netmask_pfx.data[0]); uint32_t host = ~mask; /* a valid netmask must be 2^n - 1 */ - if (!(host & (host + 1))) { - for (plen = 0; mask; mask <<= 1) - ++plen; - if (plen <= dst->bitlen) { - dst->bitlen = plen; - /* dst->flags |= PREFIXLEN_SPECIFIED; */ - } else - err = -1; - } else - err = -1; - } else { - /* plain prefix */ - dst->bitlen = plen; + if (host & (host + 1)) + goto bad; + + for (plen = 0; mask; mask <<= 1) + ++plen; + if (plen > dst->bitlen) + goto bad; + /* dst->flags |= PREFIXLEN_SPECIFIED; */ } + dst->bitlen = plen; } } + if (slash) *slash = '/'; - return err; + return; + bad: + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); } int get_addr(inet_prefix *dst, char *arg, int family) @@ -163,15 +188,12 @@ int get_addr(inet_prefix *dst, char *arg, int family) return 0; } -int get_prefix(inet_prefix *dst, char *arg, int family) +void get_prefix(inet_prefix *dst, char *arg, int family) { if (family == AF_PACKET) { bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix"); } - if (get_prefix_1(dst, arg, family)) { - bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); - } - return 0; + get_prefix_1(dst, arg, family); } uint32_t get_addr32(char *name) @@ -204,10 +226,10 @@ void duparg2(const char *key, const char *arg) bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); } -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) { - uint32_t *a1 = a->data; - uint32_t *a2 = b->data; + const uint32_t *a1 = a->data; + const uint32_t *a2 = b->data; int words = bits >> 5; bits &= 0x1f; diff --git a/release/src/router/busybox/networking/libiproute/utils.h b/release/src/router/busybox/networking/libiproute/utils.h index 93c9d25d64..5fb4a862cc 100644 --- a/release/src/router/busybox/networking/libiproute/utils.h +++ b/release/src/router/busybox/networking/libiproute/utils.h @@ -58,9 +58,9 @@ struct ipx_addr { extern uint32_t get_addr32(char *name); extern int get_addr_1(inet_prefix *dst, char *arg, int family); -/*extern int get_prefix_1(inet_prefix *dst, char *arg, int family);*/ +/*extern void get_prefix_1(inet_prefix *dst, char *arg, int family);*/ extern int get_addr(inet_prefix *dst, char *arg, int family); -extern int get_prefix(inet_prefix *dst, char *arg, int family); +extern void get_prefix(inet_prefix *dst, char *arg, int family); extern unsigned get_unsigned(char *arg, const char *errmsg); extern uint32_t get_u32(char *arg, const char *errmsg); @@ -77,7 +77,7 @@ extern const char *format_host(int af, int len, void *addr, char *buf, int bufle void invarg(const char *, const char *) NORETURN; void duparg(const char *, const char *) NORETURN; void duparg2(const char *, const char *) NORETURN; -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits); const char *dnet_ntop(int af, const void *addr, char *str, size_t len); int dnet_pton(int af, const char *src, void *addr); diff --git a/release/src/router/busybox/networking/nameif.c b/release/src/router/busybox/networking/nameif.c index d02c2c11bf..5d7e8f9a44 100644 --- a/release/src/router/busybox/networking/nameif.c +++ b/release/src/router/busybox/networking/nameif.c @@ -10,6 +10,65 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config NAMEIF +//config: bool "nameif" +//config: default y +//config: select PLATFORM_LINUX +//config: select FEATURE_SYSLOG +//config: help +//config: nameif is used to rename network interface by its MAC address. +//config: Renamed interfaces MUST be in the down state. +//config: It is possible to use a file (default: /etc/mactab) +//config: with list of new interface names and MACs. +//config: Maximum interface name length: IFNAMSIZ = 16 +//config: File fields are separated by space or tab. +//config: File format: +//config: # Comment +//config: new_interface_name XX:XX:XX:XX:XX:XX +//config: +//config:config FEATURE_NAMEIF_EXTENDED +//config: bool "Extended nameif" +//config: default y +//config: depends on NAMEIF +//config: help +//config: This extends the nameif syntax to support the bus_info, driver, +//config: phyaddr selectors. The syntax is compatible to the normal nameif. +//config: File format: +//config: new_interface_name driver=asix bus=usb-0000:00:08.2-3 +//config: new_interface_name bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5 +//config: new_interface_name phy_address=2 00:80:C8:38:91:B5 +//config: new_interface_name mac=00:80:C8:38:91:B5 +//config: new_interface_name 00:80:C8:38:91:B5 + +//usage:#define nameif_trivial_usage +//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( +//usage: "[-s] [-c FILE] [IFNAME HWADDR]..." +//usage: ) +//usage: IF_FEATURE_NAMEIF_EXTENDED( +//usage: "[-s] [-c FILE] [IFNAME SELECTOR]..." +//usage: ) +//usage:#define nameif_full_usage "\n\n" +//usage: "Rename network interface while it in the down state." +//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( +//usage: "\nThe device with address HWADDR is renamed to IFACE." +//usage: ) +//usage: IF_FEATURE_NAMEIF_EXTENDED( +//usage: "\nThe device matched by SELECTOR is renamed to IFACE." +//usage: "\nSELECTOR can be a combination of:" +//usage: "\n driver=STRING" +//usage: "\n bus=STRING" +//usage: "\n phy_address=NUM" +//usage: "\n [mac=]XX:XX:XX:XX:XX:XX" +//usage: ) +//usage: "\n" +//usage: "\n -c FILE Configuration file (default: /etc/mactab)" +//usage: "\n -s Log to syslog" +//usage: +//usage:#define nameif_example_usage +//usage: "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n" +//usage: " or\n" +//usage: "$ nameif -c /etc/my_mactab_file\n" + #include "libbb.h" #include #include @@ -38,6 +97,7 @@ typedef struct ethtable_s { #if ENABLE_FEATURE_NAMEIF_EXTENDED char *bus_info; char *driver; + int32_t phy_address; #endif } ethtable_t; @@ -59,6 +119,25 @@ struct ethtool_drvinfo { uint32_t eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ uint32_t regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ }; + +struct ethtool_cmd { + uint32_t cmd; + uint32_t supported; /* Features this interface supports */ + uint32_t advertising; /* Features this interface advertises */ + uint16_t speed; /* The forced speed, 10Mb, 100Mb, gigabit */ + uint8_t duplex; /* Duplex, half or full */ + uint8_t port; /* Which connector port */ + uint8_t phy_address; + uint8_t transceiver; /* Which transceiver to use */ + uint8_t autoneg; /* Enable or disable autonegotiation */ + uint32_t maxtxpkt; /* Tx pkts before generating tx int */ + uint32_t maxrxpkt; /* Rx pkts before generating rx int */ + uint16_t speed_hi; + uint16_t reserved2; + uint32_t reserved[3]; +}; + +#define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ #endif @@ -74,6 +153,7 @@ static void nameif_parse_selector(ethtable_t *ch, char *selector) #endif selector = skip_whitespace(selector); #if ENABLE_FEATURE_NAMEIF_EXTENDED + ch->phy_address = -1; if (*selector == '\0') break; /* Search for the end .... */ @@ -87,6 +167,9 @@ static void nameif_parse_selector(ethtable_t *ch, char *selector) } else if (strncmp(selector, "driver=", 7) == 0) { ch->driver = xstrdup(selector + 7); found_selector++; + } else if (strncmp(selector, "phyaddr=", 8) == 0) { + ch->phy_address = xatoi_positive(selector + 8); + found_selector++; } else { #endif lmac = xmalloc(ETH_ALEN); @@ -133,7 +216,7 @@ void delete_eth_table(ethtable_t *ch); #endif int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int nameif_main(int argc, char **argv) +int nameif_main(int argc UNUSED_PARAM, char **argv) { ethtable_t *clist = NULL; const char *fname = "/etc/mactab"; @@ -148,17 +231,15 @@ int nameif_main(int argc, char **argv) * can't hurt. 2>/dev/null if you don't like it: */ logmode |= LOGMODE_SYSLOG; } - argc -= optind; argv += optind; - if (argc & 1) - bb_show_usage(); - - if (argc) { - while (*argv) { - char *ifname = xstrdup(*argv++); - prepend_new_eth_table(&clist, ifname, *argv++); - } + if (argv[0]) { + do { + if (!argv[1]) + bb_show_usage(); + prepend_new_eth_table(&clist, argv[0], argv[1]); + argv += 2; + } while (*argv); } else { parser = config_open(fname); while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) @@ -173,8 +254,9 @@ int nameif_main(int argc, char **argv) struct ifreq ifr; #if ENABLE_FEATURE_NAMEIF_EXTENDED struct ethtool_drvinfo drvinfo; + struct ethtool_cmd eth_settings; #endif - if (parser->lineno < 2) + if (parser->lineno <= 2) continue; /* Skip the first two lines */ /* Find the current interface name and copy it to ifr.ifr_name */ @@ -182,8 +264,14 @@ int nameif_main(int argc, char **argv) strncpy_IFNAMSIZ(ifr.ifr_name, token[0]); #if ENABLE_FEATURE_NAMEIF_EXTENDED + /* Check for phy address */ + memset(ð_settings, 0, sizeof(eth_settings)); + eth_settings.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t) ð_settings; + ioctl(ctl_sk, SIOCETHTOOL, &ifr); + /* Check for driver etc. */ - memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + memset(&drvinfo, 0, sizeof(drvinfo)); drvinfo.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t) &drvinfo; /* Get driver and businfo first, so we have it in drvinfo */ @@ -198,6 +286,8 @@ int nameif_main(int argc, char **argv) continue; if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0) continue; + if (ch->phy_address != -1 && ch->phy_address != eth_settings.phy_address) + continue; #endif if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) continue; diff --git a/release/src/router/busybox/networking/nbd-client.c b/release/src/router/busybox/networking/nbd-client.c index 8b856eda79..cadda5261d 100644 --- a/release/src/router/busybox/networking/nbd-client.c +++ b/release/src/router/busybox/networking/nbd-client.c @@ -7,7 +7,7 @@ #include #include -//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nbdclient)) +//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) //kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o diff --git a/release/src/router/busybox/networking/nc.c b/release/src/router/busybox/networking/nc.c index 31d450dda8..1b32e3aa33 100644 --- a/release/src/router/busybox/networking/nc.c +++ b/release/src/router/busybox/networking/nc.c @@ -49,7 +49,7 @@ //usage:#if !ENABLE_NC_110_COMPAT //usage: //usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA -//usage:#define NC_OPTIONS_STR "\n\nOptions:" +//usage:#define NC_OPTIONS_STR "\n" //usage:#else //usage:#define NC_OPTIONS_STR //usage:#endif diff --git a/release/src/router/busybox/networking/nc_bloaty.c b/release/src/router/busybox/networking/nc_bloaty.c index 3c622e51ec..62a0251165 100644 --- a/release/src/router/busybox/networking/nc_bloaty.c +++ b/release/src/router/busybox/networking/nc_bloaty.c @@ -60,8 +60,7 @@ //usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen" //usage: ) //usage:#define nc_full_usage "\n\n" -//usage: "Options:" -//usage: "\n -e PROG Run PROG after connect (must be last)" +//usage: " -e PROG Run PROG after connect (must be last)" //usage: IF_NC_SERVER( //usage: "\n -l Listen mode, for inbound connects" //usage: ) @@ -116,6 +115,7 @@ struct globals { unsigned wrote_out; /* total stdout bytes */ unsigned wrote_net; /* total net bytes */ #endif + char *proggie0saved; /* ouraddr is never NULL and goes through three states as we progress: 1 - local address before bind (IP/port possibly zero) 2 - local address after bind (port is nonzero) @@ -128,7 +128,6 @@ struct globals { jmp_buf jbuf; /* timer crud */ - /* will malloc up the following globals: */ fd_set ding1; /* for select loop */ fd_set ding2; char bigbuf_in[BIGSIZ]; /* data buffers */ @@ -160,17 +159,16 @@ struct globals { /* Must match getopt32 call! */ enum { - OPT_h = (1 << 0), - OPT_n = (1 << 1), - OPT_p = (1 << 2), - OPT_s = (1 << 3), - OPT_u = (1 << 4), - OPT_v = (1 << 5), - OPT_w = (1 << 6), - OPT_l = (1 << 7) * ENABLE_NC_SERVER, - OPT_i = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_o = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_z = (1 << (9+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_n = (1 << 0), + OPT_p = (1 << 1), + OPT_s = (1 << 2), + OPT_u = (1 << 3), + OPT_v = (1 << 4), + OPT_w = (1 << 5), + OPT_l = (1 << 6) * ENABLE_NC_SERVER, + OPT_i = (1 << (6+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_o = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_z = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, }; #define o_nflag (option_mask32 & OPT_n) @@ -264,12 +262,13 @@ Debug("findline returning whole thing: %d", siz); static int doexec(char **proggie) NORETURN; static int doexec(char **proggie) { + if (G.proggie0saved) + proggie[0] = G.proggie0saved; xmove_fd(netfd, 0); dup2(0, 1); /* dup2(0, 2); - do we *really* want this? NO! * exec'ed prog can do it yourself, if needed */ - execvp(proggie[0], proggie); - bb_perror_msg_and_die("can't execute '%s'", proggie[0]); + BB_EXECVP_or_die(proggie); } /* connect_w_timeout: @@ -387,10 +386,10 @@ create new one, and bind() it. TODO */ if (port == 0) { /* "nc -nl -p LPORT RHOST" (w/o RPORT!): * we should accept any remote port */ - set_nport(&remend, 0); /* blot out remote port# */ + set_nport(&remend.u.sa, 0); /* blot out remote port# */ } r = memcmp(&remend.u.sa, &themaddr->u.sa, remend.len); - set_nport(&remend, sv_port); /* restore */ + set_nport(&remend.u.sa, sv_port); /* restore */ if (r != 0) { /* nc 1.10 bails out instead, and its error message * is not suppressed by o_verbose */ @@ -430,8 +429,7 @@ create new one, and bind() it. TODO */ rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); if (rr >= 0 && x) { /* we've got options, lessee em... */ - bin2hex(bigbuf_net, optbuf, x); - bigbuf_net[2*x] = '\0'; + *bin2hex(bigbuf_net, optbuf, x) = '\0'; fprintf(stderr, "IP options: %s\n", bigbuf_net); } #endif @@ -487,7 +485,7 @@ static int udptest(void) us to hang forever, and hit it */ o_wait = 5; /* enough that we'll notice?? */ rr = xsocket(ouraddr->u.sa.sa_family, SOCK_STREAM, 0); - set_nport(themaddr, htons(SLEAZE_PORT)); + set_nport(&themaddr->u.sa, htons(SLEAZE_PORT)); connect_w_timeout(rr); /* don't need to restore themaddr's port, it's not used anymore */ close(rr); @@ -729,7 +727,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) { char *str_p, *str_s; IF_NC_EXTRA(char *str_i, *str_o;) - char *themdotted = themdotted; /* gcc */ + char *themdotted = themdotted; /* for compiler */ char **proggie; int x; unsigned o_lport = 0; @@ -757,13 +755,27 @@ int nc_main(int argc UNUSED_PARAM, char **argv) proggie++; goto e_found; } + /* -e PROG [ARGS] ? */ + /* (aboriginal linux uses this form) */ + if (proggie[0][0] == '-') { + char *optpos = *proggie + 1; + /* Skip all valid opts w/o params */ + optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("l")IF_NC_EXTRA("z")); + if (*optpos == 'e' && !optpos[1]) { + *optpos = '\0'; + proggie++; + G.proggie0saved = *proggie; + *proggie = NULL; /* terminate argv for getopt32 */ + goto e_found; + } + } } proggie = NULL; e_found: // -g -G -t -r deleted, unimplemented -a deleted too opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ - getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") + getopt32(argv, "np:s:uvw:" IF_NC_SERVER("l") IF_NC_EXTRA("i:o:z"), &str_p, &str_s, &o_wait IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); @@ -814,7 +826,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) (themaddr ? themaddr->u.sa.sa_family : AF_UNSPEC), x); if (o_lport) - set_nport(ouraddr, htons(o_lport)); + set_nport(&ouraddr->u.sa, htons(o_lport)); } xmove_fd(x, netfd); setsockopt_reuseaddr(netfd); diff --git a/release/src/router/busybox/networking/netstat.c b/release/src/router/busybox/networking/netstat.c index 356fb53cb2..9c239579fe 100644 --- a/release/src/router/busybox/networking/netstat.c +++ b/release/src/router/busybox/networking/netstat.c @@ -21,7 +21,6 @@ //usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" //usage:#define netstat_full_usage "\n\n" //usage: "Display networking information\n" -//usage: "\nOptions:" //usage: IF_ROUTE( //usage: "\n -r Routing table" //usage: ) diff --git a/release/src/router/busybox/networking/nslookup.c b/release/src/router/busybox/networking/nslookup.c index dcac7379e1..f4fd407dd7 100644 --- a/release/src/router/busybox/networking/nslookup.c +++ b/release/src/router/busybox/networking/nslookup.c @@ -11,6 +11,20 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define nslookup_trivial_usage +//usage: "[HOST] [SERVER]" +//usage:#define nslookup_full_usage "\n\n" +//usage: "Query the nameserver for the IP address of the given HOST\n" +//usage: "optionally using a specified DNS server" +//usage: +//usage:#define nslookup_example_usage +//usage: "$ nslookup localhost\n" +//usage: "Server: default\n" +//usage: "Address: default\n" +//usage: "\n" +//usage: "Name: debian\n" +//usage: "Address: 127.0.0.1\n" + #include #include "libbb.h" @@ -66,7 +80,7 @@ static int print_host(const char *hostname, const char *header) // hint.ai_flags = AI_CANONNAME; rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result); - if (!rc) { + if (rc == 0) { struct addrinfo *cur = result; unsigned cnt = 0; @@ -94,7 +108,7 @@ static int print_host(const char *hostname, const char *header) bb_error_msg("can't resolve '%s'", hostname); #endif } - if (ENABLE_FEATURE_CLEAN_UP) + if (ENABLE_FEATURE_CLEAN_UP && result) freeaddrinfo(result); return (rc != 0); } diff --git a/release/src/router/busybox/networking/ntpd.c b/release/src/router/busybox/networking/ntpd.c index 8fe529edbb..603801ec60 100644 --- a/release/src/router/busybox/networking/ntpd.c +++ b/release/src/router/busybox/networking/ntpd.c @@ -27,6 +27,22 @@ * * *********************************************************************** */ + +//usage:#define ntpd_trivial_usage +//usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l")"] [-S PROG] [-p PEER]..." +//usage:#define ntpd_full_usage "\n\n" +//usage: "NTP client/server\n" +//usage: "\n -d Verbose" +//usage: "\n -n Do not daemonize" +//usage: "\n -q Quit after clock is set" +//usage: "\n -N Run at high priority" +//usage: "\n -w Do not set time (only query peers), implies -n" +//usage: IF_FEATURE_NTPD_SERVER( +//usage: "\n -l Run as server on port 123" +//usage: ) +//usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" +//usage: "\n -p PEER Obtain time from PEER (may be repeated)" + #include "libbb.h" #include #include /* For IPTOS_LOWDELAY definition */ @@ -91,12 +107,15 @@ #define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ #define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ -#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ +/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, + * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). + */ +#define BIGPOLL 10 /* 2^10 sec ~= 17 min */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ /* Actively lower poll when we see such big offsets. * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively - * if offset increases over 0.03 sec */ -#define POLLDOWN_OFFSET (STEP_THRESHOLD / 4) + * if offset increases over ~0.04 sec */ +#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) #define MINDISP 0.01 /* minimum dispersion (sec) */ #define MAXDISP 16 /* maximum dispersion (sec) */ #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ @@ -108,17 +127,18 @@ /* Poll-adjust threshold. * When we see that offset is small enough compared to discipline jitter, - * we grow a counter: += MINPOLL. When it goes over POLLADJ_LIMIT, + * we grow a counter: += MINPOLL. When counter goes over POLLADJ_LIMIT, * we poll_exp++. If offset isn't small, counter -= poll_exp*2, - * and when it goes below -POLLADJ_LIMIT, we poll_exp-- - * (bumped from 30 to 36 since otherwise I often see poll_exp going *2* steps down) + * and when it goes below -POLLADJ_LIMIT, we poll_exp--. + * (Bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down) */ -#define POLLADJ_LIMIT 36 -/* If offset < POLLADJ_GATE * discipline_jitter, then we can increase +#define POLLADJ_LIMIT 40 +/* If offset < discipline_jitter * POLLADJ_GATE, then we decide to increase * poll interval (we think we can't improve timekeeping * by staying at smaller poll). */ #define POLLADJ_GATE 4 +#define TIMECONST_HACK_GATE 2 /* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ #define ALLAN 512 /* PLL loop gain */ @@ -192,8 +212,8 @@ typedef struct { } msg_t; typedef struct { - double d_recv_time; double d_offset; + double d_recv_time; double d_dispersion; } datapoint_t; @@ -238,6 +258,8 @@ enum { OPT_p = (1 << 5), OPT_S = (1 << 6), OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, + /* We hijack some bits for other purposes */ + OPT_qq = (1 << 31), }; struct globals { @@ -254,15 +276,19 @@ struct globals { llist_t *ntp_peers; #if ENABLE_FEATURE_NTPD_SERVER int listen_fd; +# define G_listen_fd (G.listen_fd) +#else +# define G_listen_fd (-1) #endif unsigned verbose; unsigned peer_cnt; /* refid: 32-bit code identifying the particular server or reference clock - * in stratum 0 packets this is a four-character ASCII string, - * called the kiss code, used for debugging and monitoring - * in stratum 1 packets this is a four-character ASCII string - * assigned to the reference clock by IANA. Example: "GPS " - * in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6 + * in stratum 0 packets this is a four-character ASCII string, + * called the kiss code, used for debugging and monitoring + * in stratum 1 packets this is a four-character ASCII string + * assigned to the reference clock by IANA. Example: "GPS " + * in stratum 2+ packets, it's IPv4 address or 4 first bytes + * of MD5 hash of IPv6 */ uint32_t refid; uint8_t ntp_status; @@ -271,27 +297,35 @@ struct globals { * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the * system clock hardware representation is to the nanosecond. * - * Delays, jitters of various kinds are clamper down to precision. + * Delays, jitters of various kinds are clamped down to precision. * * If precision_sec is too large, discipline_jitter gets clamped to it - * and if offset is much smaller than discipline_jitter, poll interval - * grows even though we really can benefit from staying at smaller one, - * collecting non-lagged datapoits and correcting the offset. + * and if offset is smaller than discipline_jitter * POLLADJ_GATE, poll + * interval grows even though we really can benefit from staying at + * smaller one, collecting non-lagged datapoits and correcting offset. * (Lagged datapoits exist when poll_exp is large but we still have * systematic offset error - the time distance between datapoints - * is significat and older datapoints have smaller offsets. + * is significant and older datapoints have smaller offsets. * This makes our offset estimation a bit smaller than reality) * Due to this effect, setting G_precision_sec close to * STEP_THRESHOLD isn't such a good idea - offsets may grow * too big and we will step. I observed it with -6. * - * OTOH, setting precision too small would result in futile attempts - * to syncronize to the unachievable precision. + * OTOH, setting precision_sec far too small would result in futile + * attempts to syncronize to an unachievable precision. * * -6 is 1/64 sec, -7 is 1/128 sec and so on. + * -8 is 1/256 ~= 0.003906 (worked well for me --vda) + * -9 is 1/512 ~= 0.001953 (let's try this for some time) + */ +#define G_precision_exp -9 + /* + * G_precision_exp is used only for construction outgoing packets. + * It's ok to set G_precision_sec to a slightly different value + * (One which is "nicer looking" in logs). + * Exact value would be (1.0 / (1 << (- G_precision_exp))): */ -#define G_precision_exp -8 -#define G_precision_sec (1.0 / (1 << (- G_precision_exp))) +#define G_precision_sec 0.002 uint8_t stratum; /* Bool. After set to 1, never goes back to 0: */ smallint initial_poll_complete; @@ -309,6 +343,10 @@ struct globals { double last_update_offset; // c.last double last_update_recv_time; // s.t double discipline_jitter; // c.jitter + /* Since we only compare it with ints, can simplify code + * by not making this variable floating point: + */ + unsigned offset_to_jitter_ratio; //double cluster_offset; // s.offset //double cluster_jitter; // s.jitter #if !USING_KERNEL_PLL_LOOP @@ -482,23 +520,34 @@ static void filter_datapoints(peer_t *p) { int i, idx; + double sum, wavg; + datapoint_t *fdp; + +#if 0 +/* Simulations have shown that use of *averaged* offset for p->filter_offset + * is in fact worse than simply using last received one: with large poll intervals + * (>= 2048) averaging code uses offset values which are outdated by hours, + * and time/frequency correction goes totally wrong when fed essentially bogus offsets. + */ int got_newest; - double minoff, maxoff, wavg, sum, w; + double minoff, maxoff, w; double x = x; /* for compiler */ double oldest_off = oldest_off; double oldest_age = oldest_age; double newest_off = newest_off; double newest_age = newest_age; - minoff = maxoff = p->filter_datapoint[0].d_offset; + fdp = p->filter_datapoint; + + minoff = maxoff = fdp[0].d_offset; for (i = 1; i < NUM_DATAPOINTS; i++) { - if (minoff > p->filter_datapoint[i].d_offset) - minoff = p->filter_datapoint[i].d_offset; - if (maxoff < p->filter_datapoint[i].d_offset) - maxoff = p->filter_datapoint[i].d_offset; + if (minoff > fdp[i].d_offset) + minoff = fdp[i].d_offset; + if (maxoff < fdp[i].d_offset) + maxoff = fdp[i].d_offset; } - idx = p->datapoint_idx; /* most recent datapoint */ + idx = p->datapoint_idx; /* most recent datapoint's index */ /* Average offset: * Drop two outliers and take weighted average of the rest: * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32 @@ -520,24 +569,24 @@ filter_datapoints(peer_t *p) VERB4 { bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", i, - p->filter_datapoint[idx].d_offset, - p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]), - G.cur_time - p->filter_datapoint[idx].d_recv_time, - (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) + fdp[idx].d_offset, + fdp[idx].d_dispersion, dispersion(&fdp[idx]), + G.cur_time - fdp[idx].d_recv_time, + (minoff == fdp[idx].d_offset || maxoff == fdp[idx].d_offset) ? " (outlier by offset)" : "" ); } - sum += dispersion(&p->filter_datapoint[idx]) / (2 << i); + sum += dispersion(&fdp[idx]) / (2 << i); - if (minoff == p->filter_datapoint[idx].d_offset) { + if (minoff == fdp[idx].d_offset) { minoff -= 1; /* so that we don't match it ever again */ } else - if (maxoff == p->filter_datapoint[idx].d_offset) { + if (maxoff == fdp[idx].d_offset) { maxoff += 1; } else { - oldest_off = p->filter_datapoint[idx].d_offset; - oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time; + oldest_off = fdp[idx].d_offset; + oldest_age = G.cur_time - fdp[idx].d_recv_time; if (!got_newest) { got_newest = 1; newest_off = oldest_off; @@ -570,6 +619,32 @@ filter_datapoints(peer_t *p) } p->filter_offset = wavg; +#else + + fdp = p->filter_datapoint; + idx = p->datapoint_idx; /* most recent datapoint's index */ + + /* filter_offset: simply use the most recent value */ + p->filter_offset = fdp[idx].d_offset; + + /* n-1 + * --- dispersion(i) + * filter_dispersion = \ ------------- + * / (i+1) + * --- 2 + * i=0 + */ + wavg = 0; + sum = 0; + for (i = 0; i < NUM_DATAPOINTS; i++) { + sum += dispersion(&fdp[idx]) / (2 << i); + wavg += fdp[idx].d_offset; + idx = (idx - 1) & (NUM_DATAPOINTS - 1); + } + wavg /= NUM_DATAPOINTS; + p->filter_dispersion = sum; +#endif + /* +----- -----+ ^ 1/2 * | n-1 | * | --- | @@ -583,13 +658,13 @@ filter_datapoints(peer_t *p) */ sum = 0; for (i = 0; i < NUM_DATAPOINTS; i++) { - sum += SQUARE(wavg - p->filter_datapoint[i].d_offset); + sum += SQUARE(wavg - fdp[i].d_offset); } sum = SQRT(sum / NUM_DATAPOINTS); p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; - VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f", - p->filter_offset, x, + VERB3 bb_error_msg("filter offset:%+f disp:%f jitter:%f", + p->filter_offset, p->filter_dispersion, p->filter_jitter); } @@ -604,7 +679,11 @@ reset_peer_stats(peer_t *p, double offset) if (small_ofs) { p->filter_datapoint[i].d_recv_time += offset; if (p->filter_datapoint[i].d_offset != 0) { - p->filter_datapoint[i].d_offset += offset; + p->filter_datapoint[i].d_offset -= offset; + //bb_error_msg("p->filter_datapoint[%d].d_offset %f -> %f", + // i, + // p->filter_datapoint[i].d_offset + offset, + // p->filter_datapoint[i].d_offset); } } else { p->filter_datapoint[i].d_recv_time = G.cur_time; @@ -701,6 +780,12 @@ send_query_to_peer(peer_t *p) free(local_lsa); } + /* Emit message _before_ attempted send. Think of a very short + * roundtrip networks: we need to go back to recv loop ASAP, + * to reduce delay. Printing messages after send works against that. + */ + VERB1 bb_error_msg("sending query to %s", p->p_dotted); + /* * Send out a random 64-bit number as our transmit time. The NTP * server will copy said number into the originate field on the @@ -728,7 +813,6 @@ send_query_to_peer(peer_t *p) } p->reachable_bits <<= 1; - VERB1 bb_error_msg("sent query to %s", p->p_dotted); set_next(p, RESPONSE_INTERVAL); } @@ -790,22 +874,24 @@ step_time(double offset) { llist_t *item; double dtime; - struct timeval tv; - char buf[80]; + struct timeval tvc, tvn; + char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4]; time_t tval; - gettimeofday(&tv, NULL); /* never fails */ - dtime = offset + tv.tv_sec; - dtime += 1.0e-6 * tv.tv_usec; - d_to_tv(dtime, &tv); - - if (settimeofday(&tv, NULL) == -1) + gettimeofday(&tvc, NULL); /* never fails */ + dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset; + d_to_tv(dtime, &tvn); + if (settimeofday(&tvn, NULL) == -1) bb_perror_msg_and_die("settimeofday"); - tval = tv.tv_sec; - strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); - - bb_error_msg("setting clock to %s (offset %fs)", buf, offset); + VERB2 { + tval = tvc.tv_sec; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval)); + bb_error_msg("current time is %s.%06u", buf, (unsigned)tvc.tv_usec); + } + tval = tvn.tv_sec; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval)); + bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); /* Correct various fields which contain time-relative values: */ @@ -813,7 +899,7 @@ step_time(double offset) for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *pp = (peer_t *) item->data; reset_peer_stats(pp, offset); - //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", + //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f", // offset, pp->next_action_time, pp->next_action_time + offset); pp->next_action_time += offset; } @@ -882,7 +968,7 @@ fit(peer_t *p, double rd) // /* Do we have a loop? */ // if (p->refid == p->dstaddr || p->refid == s.refid) // return 0; - return 1; + return 1; } static peer_t* select_and_cluster(void) @@ -1149,7 +1235,7 @@ select_and_cluster(void) } G.last_update_peer = p; keep_old: - VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", + VERB3 bb_error_msg("selected peer %s filter_offset:%+f age:%f", p->p_dotted, p->filter_offset, G.cur_time - p->lastpkt_recv_time @@ -1240,7 +1326,7 @@ update_local_clock(peer_t *p) switch (G.discipline_state) { case STATE_SYNC: /* The first outlyer: ignore it, switch to SPIK state */ - VERB3 bb_error_msg("offset:%f - spike detected", offset); + VERB3 bb_error_msg("offset:%+f - spike detected", offset); G.discipline_state = STATE_SPIK; return -1; /* "decrease poll interval" */ @@ -1277,7 +1363,7 @@ update_local_clock(peer_t *p) * is always suppressed, even at the longer poll * intervals. */ - VERB3 bb_error_msg("stepping time by %f; poll_exp=MINPOLL", offset); + VERB3 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset); step_time(offset); if (option_mask32 & OPT_q) { /* We were only asked to set time once. Done. */ @@ -1296,12 +1382,13 @@ update_local_clock(peer_t *p) return 1; /* "ok to increase poll interval" */ } #endif - set_new_values(STATE_SYNC, /*offset:*/ 0, recv_time); + abs_offset = offset = 0; + set_new_values(STATE_SYNC, offset, recv_time); } else { /* abs_offset <= STEP_THRESHOLD */ if (G.poll_exp < MINPOLL && G.initial_poll_complete) { - VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset); + VERB3 bb_error_msg("small offset:%+f, disabling burst mode", offset); G.polladj_count = 0; G.poll_exp = MINPOLL; } @@ -1310,9 +1397,8 @@ update_local_clock(peer_t *p) * weighted offset differences. Used by the poll adjust code. */ etemp = SQUARE(G.discipline_jitter); - dtemp = SQUARE(MAXD(fabs(offset - G.last_update_offset), G_precision_sec)); + dtemp = SQUARE(offset - G.last_update_offset); G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); - VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter); switch (G.discipline_state) { case STATE_NSET: @@ -1389,6 +1475,10 @@ update_local_clock(peer_t *p) } } + if (G.discipline_jitter < G_precision_sec) + G.discipline_jitter = G_precision_sec; + G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter; + G.reftime = G.cur_time; G.ntp_status = p->lastpkt_status; G.refid = p->lastpkt_refid; @@ -1400,7 +1490,7 @@ update_local_clock(peer_t *p) /* We are in STATE_SYNC now, but did not do adjtimex yet. * (Any other state does not reach this, they all return earlier) - * By this time, freq_drift and G.last_update_offset are set + * By this time, freq_drift and offset are set * to values suitable for adjtimex. */ #if !USING_KERNEL_PLL_LOOP @@ -1426,8 +1516,8 @@ update_local_clock(peer_t *p) memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("p adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); + bb_error_msg("p adjtimex freq:%ld offset:%+ld status:0x%x tc:%ld", + tmx.freq, tmx.offset, tmx.status, tmx.constant); } memset(&tmx, 0, sizeof(tmx)); @@ -1439,40 +1529,42 @@ update_local_clock(peer_t *p) tmx.modes = ADJ_FREQUENCY | ADJ_OFFSET; /* 65536 is one ppm */ tmx.freq = G.discipline_freq_drift * 65536e6; - tmx.offset = G.last_update_offset * 1000000; /* usec */ #endif tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; - tmx.offset = (G.last_update_offset * 1000000); /* usec */ - /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */ + tmx.offset = (offset * 1000000); /* usec */ tmx.status = STA_PLL; if (G.ntp_status & LI_PLUSSEC) tmx.status |= STA_INS; if (G.ntp_status & LI_MINUSSEC) tmx.status |= STA_DEL; + tmx.constant = G.poll_exp - 4; - //tmx.esterror = (u_int32)(clock_jitter * 1e6); - //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); + /* EXPERIMENTAL. + * The below if statement should be unnecessary, but... + * It looks like Linux kernel's PLL is far too gentle in changing + * tmx.freq in response to clock offset. Offset keeps growing + * and eventually we fall back to smaller poll intervals. + * We can make correction more agressive (about x2) by supplying + * PLL time constant which is one less than the real one. + * To be on a safe side, let's do it only if offset is significantly + * larger than jitter. + */ + if (tmx.constant > 0 && G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE) + tmx.constant--; + + //tmx.esterror = (uint32_t)(clock_jitter * 1e6); + //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); rc = adjtimex(&tmx); if (rc < 0) bb_perror_msg_and_die("adjtimex"); /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. * Not sure why. Perhaps it is normal. */ - VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x", - rc, tmx.freq, tmx.offset, tmx.constant, tmx.status); -#if 0 - VERB3 { - /* always gives the same output as above msg */ - memset(&tmx, 0, sizeof(tmx)); - if (adjtimex(&tmx) < 0) - bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("c adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); - } -#endif + VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x", + rc, tmx.freq, tmx.offset, tmx.status); G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%f, clock drift:%ld ppm", - p->p_dotted, G.last_update_offset, G.kernel_freq_drift); + VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d", + p->p_dotted, offset, G.discipline_jitter, (double)tmx.freq / 65536, (int)tmx.constant); return 1; /* "ok to increase poll interval" */ } @@ -1608,22 +1700,22 @@ recv_and_process_peer_pkt(peer_t *p) if (!p->reachable_bits) { /* 1st datapoint ever - replicate offset in every element */ int i; - for (i = 1; i < NUM_DATAPOINTS; i++) { + for (i = 0; i < NUM_DATAPOINTS; i++) { p->filter_datapoint[i].d_offset = datapoint->d_offset; } } p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", + bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", p->p_dotted, - p->reachable_bits, datapoint->d_offset, p->lastpkt_delay, p->lastpkt_status, p->lastpkt_stratum, p->lastpkt_refid, - p->lastpkt_rootdelay + p->lastpkt_rootdelay, + p->reachable_bits /* not shown: m_ppoll, m_precision_exp, m_rootdisp, * m_reftime, m_orgtime, m_rectime, m_xmttime */ @@ -1642,7 +1734,7 @@ recv_and_process_peer_pkt(peer_t *p) * drop poll interval one step down. */ if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { - VERB3 bb_error_msg("offset:%f > POLLDOWN_OFFSET", q->filter_offset); + VERB3 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset); goto poll_down; } } @@ -1656,14 +1748,7 @@ recv_and_process_peer_pkt(peer_t *p) * is increased, otherwise it is decreased. A bit of hysteresis * helps calm the dance. Works best using burst mode. */ - VERB4 if (rc > 0) { - bb_error_msg("offset:%f POLLADJ_GATE*discipline_jitter:%f poll:%s", - q->filter_offset, POLLADJ_GATE * G.discipline_jitter, - fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter - ? "grows" : "falls" - ); - } - if (rc > 0 && fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter) { + if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { /* was += G.poll_exp but it is a bit * too optimistic for my taste at high poll_exp's */ G.polladj_count += MINPOLL; @@ -1726,17 +1811,17 @@ static NOINLINE void recv_and_process_client_pkt(void /*int fd*/) { ssize_t size; - uint8_t version; + //uint8_t version; len_and_sockaddr *to; struct sockaddr *from; msg_t msg; uint8_t query_status; l_fixedpt_t query_xmttime; - to = get_sock_lsa(G.listen_fd); + to = get_sock_lsa(G_listen_fd); from = xzalloc(to->len); - size = recv_from_to(G.listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); + size = recv_from_to(G_listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { char *addr; if (size < 0) { @@ -1774,12 +1859,12 @@ recv_and_process_client_pkt(void /*int fd*/) msg.m_rootdelay = d_to_sfp(G.rootdelay); //simple code does not do this, fix simple code! msg.m_rootdisp = d_to_sfp(G.rootdisp); - version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ + //version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ msg.m_refid = G.refid; // (version > (3 << VERSION_SHIFT)) ? G.refid : G.refid3; /* We reply from the local address packet was sent to, * this makes to/from look swapped here: */ - do_sendto(G.listen_fd, + do_sendto(G_listen_fd, /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, &msg, size); @@ -1918,11 +2003,11 @@ static NOINLINE void ntp_init(char **argv) logmode = LOGMODE_NONE; } #if ENABLE_FEATURE_NTPD_SERVER - G.listen_fd = -1; + G_listen_fd = -1; if (opts & OPT_l) { - G.listen_fd = create_and_bind_dgram_or_die(NULL, 123); - socket_want_pktinfo(G.listen_fd); - setsockopt(G.listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); + G_listen_fd = create_and_bind_dgram_or_die(NULL, 123); + socket_want_pktinfo(G_listen_fd); + setsockopt(G_listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); } #endif /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ @@ -1930,15 +2015,18 @@ static NOINLINE void ntp_init(char **argv) setpriority(PRIO_PROCESS, 0, -15); /* If network is up, syncronization occurs in ~10 seconds. - * We give "ntpd -q" a full minute to finish, then we exit. + * We give "ntpd -q" 10 seconds to get first reply, + * then another 50 seconds to finish syncing. * * I tested ntpd 4.2.6p1 and apparently it never exits * (will try forever), but it does not feel right. * The goal of -q is to act like ntpdate: set time * after a reasonably small period of polling, or fail. */ - if (opts & OPT_q) - alarm(60); + if (opts & OPT_q) { + option_mask32 |= OPT_qq; + alarm(10); + } bb_signals(0 | (1 << SIGTERM) @@ -1993,8 +2081,8 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) i = 0; #if ENABLE_FEATURE_NTPD_SERVER - if (G.listen_fd != -1) { - pfd[0].fd = G.listen_fd; + if (G_listen_fd != -1) { + pfd[0].fd = G_listen_fd; pfd[0].events = POLLIN; i++; } @@ -2039,8 +2127,23 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ /* Here we may block */ - VERB2 bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); + VERB2 { + if (i > (ENABLE_FEATURE_NTPD_SERVER && G_listen_fd != -1)) { + /* We wait for at least one reply. + * Poll for it, without wasting time for message. + * Since replies often come under 1 second, this also + * reduces clutter in logs. + */ + nfds = poll(pfd, i, 1000); + if (nfds != 0) + goto did_poll; + if (--timeout <= 0) + goto did_poll; + } + bb_error_msg("poll:%us sockets:%u interval:%us", timeout, i, 1 << G.poll_exp); + } nfds = poll(pfd, i, timeout * 1000); + did_poll: gettime1900d(); /* sets G.cur_time */ if (nfds <= 0) { if (G.script_name && G.cur_time - G.last_script_run > 11*60) { @@ -2065,6 +2168,15 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) #endif for (; nfds != 0 && j < i; j++) { if (pfd[j].revents /* & (POLLIN|POLLERR)*/) { + /* + * At init, alarm was set to 10 sec. + * Now we did get a reply. + * Increase timeout to 50 seconds to finish syncing. + */ + if (option_mask32 & OPT_qq) { + option_mask32 &= ~OPT_qq; + alarm(50); + } nfds--; recv_and_process_peer_pkt(idx2peer[j]); gettime1900d(); /* sets G.cur_time */ diff --git a/release/src/router/busybox/networking/ping.c b/release/src/router/busybox/networking/ping.c index 5fc80fe4eb..b8a438ba82 100644 --- a/release/src/router/busybox/networking/ping.c +++ b/release/src/router/busybox/networking/ping.c @@ -29,6 +29,107 @@ #include #include "libbb.h" +#ifdef __BIONIC__ +/* should be in netinet/ip_icmp.h */ +# define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +# define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +# define ICMP_REDIRECT 5 /* Redirect (change route) */ +# define ICMP_ECHO 8 /* Echo Request */ +# define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +# define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +# define ICMP_TIMESTAMP 13 /* Timestamp Request */ +# define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +# define ICMP_INFO_REQUEST 15 /* Information Request */ +# define ICMP_INFO_REPLY 16 /* Information Reply */ +# define ICMP_ADDRESS 17 /* Address Mask Request */ +# define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ +#endif + +//config:config PING +//config: bool "ping" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to +//config: elicit an ICMP ECHO_RESPONSE from a host or gateway. +//config: +//config:config PING6 +//config: bool "ping6" +//config: default y +//config: depends on FEATURE_IPV6 && PING +//config: help +//config: This will give you a ping that can talk IPv6. +//config: +//config:config FEATURE_FANCY_PING +//config: bool "Enable fancy ping output" +//config: default y +//config: depends on PING +//config: help +//config: Make the output from the ping applet include statistics, and at the +//config: same time provide full support for ICMP packets. + +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore BB_SUID_MAYBE: */ +//applet:IF_PING(APPLET(ping, BB_DIR_BIN, BB_SUID_MAYBE)) +//applet:IF_PING6(APPLET(ping6, BB_DIR_BIN, BB_SUID_MAYBE)) + +//kbuild:lib-$(CONFIG_PING) += ping.o +//kbuild:lib-$(CONFIG_PING6) += ping.o + +//usage:#if !ENABLE_FEATURE_FANCY_PING +//usage:# define ping_trivial_usage +//usage: "HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:# define ping6_trivial_usage +//usage: "HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:#else +//usage:# define ping_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -t TTL Set TTL" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -W SEC Seconds to wait for the first response (default:10)" +//usage: "\n (after all -c CNT packets are sent)" +//usage: "\n -w SEC Seconds until ping exits (default:infinite)" +//usage: "\n (can exit earlier with -c CNT)" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:# define ping6_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:#endif +//usage: +//usage:#define ping_example_usage +//usage: "$ ping localhost\n" +//usage: "PING slag (127.0.0.1): 56 data bytes\n" +//usage: "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" +//usage: "\n" +//usage: "--- debian ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" +//usage:#define ping6_example_usage +//usage: "$ ping6 ip6-localhost\n" +//usage: "PING ip6-localhost (::1): 56 data bytes\n" +//usage: "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" +//usage: "\n" +//usage: "--- ip6-localhost ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" + #if ENABLE_PING6 # include /* I see RENUMBERED constants in bits/in.h - !!? @@ -48,31 +149,6 @@ enum { PINGINTERVAL = 1, /* 1 second */ }; -/* Common routines */ - -static int in_cksum(unsigned short *buf, int sz) -{ - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *) (&ans) = *(unsigned char *) w; - sum += ans; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return ans; -} - #if !ENABLE_FEATURE_FANCY_PING /* Simple version */ @@ -100,7 +176,7 @@ static void ping4(len_and_sockaddr *lsa) pkt = (struct icmp *) G.packet; memset(pkt, 0, sizeof(G.packet)); pkt->icmp_type = ICMP_ECHO; - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet)); + pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); @@ -223,17 +299,18 @@ static int common_ping_main(sa_family_t af, char **argv) /* Full(er) version */ -#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6")) +#define OPT_STRING ("qvc:s:t:w:W:I:4" IF_PING6("6")) enum { OPT_QUIET = 1 << 0, OPT_VERBOSE = 1 << 1, OPT_c = 1 << 2, OPT_s = 1 << 3, - OPT_w = 1 << 4, - OPT_W = 1 << 5, - OPT_I = 1 << 6, - OPT_IPV4 = 1 << 7, - OPT_IPV6 = (1 << 8) * ENABLE_PING6, + OPT_t = 1 << 4, + OPT_w = 1 << 5, + OPT_W = 1 << 6, + OPT_I = 1 << 7, + OPT_IPV4 = 1 << 8, + OPT_IPV6 = (1 << 9) * ENABLE_PING6, }; @@ -244,6 +321,7 @@ struct globals { len_and_sockaddr *source_lsa; unsigned datalen; unsigned pingcount; /* must be int-sized */ + unsigned opt_ttl; unsigned long ntransmitted, nreceived, nrepeats; uint16_t myid; unsigned tmin, tmax; /* in us */ @@ -275,6 +353,7 @@ struct globals { #define nreceived (G.nreceived ) #define nrepeats (G.nrepeats ) #define pingcount (G.pingcount ) +#define opt_ttl (G.opt_ttl ) #define myid (G.myid ) #define tmin (G.tmin ) #define tmax (G.tmax ) @@ -329,16 +408,18 @@ static void print_stats_and_exit(int junk UNUSED_PARAM) exit(nreceived == 0 || (deadline && nreceived < pingcount)); } -static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) +static void sendping_tail(void (*sp)(int), int size_pkt) { int sz; CLR((uint16_t)ntransmitted % MAX_DUP_CHK); ntransmitted++; + size_pkt += datalen; + /* sizeof(pingaddr) can be larger than real sa size, but I think * it doesn't matter */ - sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr)); + sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); if (sz != size_pkt) bb_error_msg_and_die(bb_msg_write_error); @@ -387,9 +468,9 @@ static void sendping4(int junk UNUSED_PARAM) /* No hton: we'll read it back on the same machine */ *(uint32_t*)&pkt->icmp_dun = monotonic_us(); - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); + pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); - sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN); + sendping_tail(sendping4, ICMP_MINLEN); } #if ENABLE_PING6 static void sendping6(int junk UNUSED_PARAM) @@ -406,9 +487,9 @@ static void sendping6(int junk UNUSED_PARAM) /*if (datalen >= 4)*/ *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); - //TODO? pkt->icmp_cksum = in_cksum(...); + //TODO? pkt->icmp_cksum = inet_cksum(...); - sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); + sendping_tail(sendping6, sizeof(struct icmp6_hdr)); } #endif @@ -532,7 +613,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) } } #if ENABLE_PING6 -static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit) +static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) { struct icmp6_hdr *icmppkt; char buf[INET6_ADDRSTRLEN]; @@ -552,7 +633,7 @@ static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hop if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) tp = (uint32_t *) &icmppkt->icmp6_data8[4]; unpack_tail(sz, tp, - inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, + inet_ntop(AF_INET6, &from->sin6_addr, buf, sizeof(buf)), recv_seq, hoplimit); } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { @@ -586,6 +667,12 @@ static void ping4(len_and_sockaddr *lsa) sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); + if (opt_ttl != 0) { + setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl)); + /* above doesnt affect packets sent to bcast IP, so... */ + setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); + } + signal(SIGINT, print_stats_and_exit); /* start the ping's going ... */ @@ -696,7 +783,7 @@ static void ping6(len_and_sockaddr *lsa) move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); } } - unpack6(G.rcv_packet, c, /*&from,*/ hoplimit); + unpack6(G.rcv_packet, c, &from, hoplimit); if (pingcount && nreceived >= pingcount) break; } @@ -735,9 +822,9 @@ static int common_ping_main(int opt, char **argv) INIT_G(); - /* exactly one argument needed; -v and -q don't mix; -c NUM, -w NUM, -W NUM */ - opt_complementary = "=1:q--v:v--q:c+:w+:W+"; - opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &deadline, &timeout, &str_I); + /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ + opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+"; + opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I); if (opt & OPT_s) datalen = xatou16(str_s); // -s if (opt & OPT_I) { // -I diff --git a/release/src/router/busybox/networking/pscan.c b/release/src/router/busybox/networking/pscan.c index a8194d1a8e..28005ad57e 100644 --- a/release/src/router/busybox/networking/pscan.c +++ b/release/src/router/busybox/networking/pscan.c @@ -6,6 +6,17 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define pscan_trivial_usage +//usage: "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST" +//usage:#define pscan_full_usage "\n\n" +//usage: "Scan a host, print all open ports\n" +//usage: "\n -c Show closed ports too" +//usage: "\n -b Show blocked ports too" +//usage: "\n -p Scan from this port (default 1)" +//usage: "\n -P Scan up to this port (default 1024)" +//usage: "\n -t Timeout (default 5000 ms)" +//usage: "\n -T Minimum rtt (default 5 ms, increase for congested hosts)" + #include "libbb.h" /* debugging */ @@ -76,7 +87,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv) DMSG("rtt %u", rtt_4); /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */ - set_nport(lsap, htons(port)); + set_nport(&lsap->u.sa, htons(port)); s = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0); /* We need unblocking socket so we don't need to wait for ETIMEOUT. */ /* Nonblocking connect typically "fails" with errno == EINPROGRESS */ diff --git a/release/src/router/busybox/networking/route.c b/release/src/router/busybox/networking/route.c index 94271fb73f..b7b5a02e69 100644 --- a/release/src/router/busybox/networking/route.c +++ b/release/src/router/busybox/networking/route.c @@ -25,6 +25,14 @@ * remove ridiculous amounts of bloat. */ +//usage:#define route_trivial_usage +//usage: "[{add|del|delete}]" +//usage:#define route_full_usage "\n\n" +//usage: "Edit kernel routing tables\n" +//usage: "\n -n Don't resolve names" +//usage: "\n -e Display other/more information" +//usage: "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family" + #include #include @@ -153,7 +161,10 @@ static int kw_lookup(const char *kwtbl, char ***pargs) static NOINLINE void INET_setroute(int action, char **args) { - struct rtentry rt; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char rt_buf[sizeof(struct rtentry)]; + struct rtentry *const rt = (void *)rt_buf; + const char *netmask = NULL; int skfd, isnet, xflag; @@ -166,7 +177,7 @@ static NOINLINE void INET_setroute(int action, char **args) } /* Clean out the RTREQ structure. */ - memset(&rt, 0, sizeof(rt)); + memset(rt, 0, sizeof(*rt)); { const char *target = *args++; @@ -178,17 +189,17 @@ static NOINLINE void INET_setroute(int action, char **args) int prefix_len; prefix_len = xatoul_range(prefix+1, 0, 32); - mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len)); + mask_in_addr(*rt) = htonl( ~(0xffffffffUL >> prefix_len)); *prefix = '\0'; #if HAVE_NEW_ADDRT - rt.rt_genmask.sa_family = AF_INET; + rt->rt_genmask.sa_family = AF_INET; #endif } else { /* Default netmask. */ netmask = "default"; } /* Prefer hostname lookup is -host flag (xflag==1) was given. */ - isnet = INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst, + isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst, (xflag & HOST_FLAG)); if (isnet < 0) { bb_error_msg_and_die("resolving %s", target); @@ -204,20 +215,20 @@ static NOINLINE void INET_setroute(int action, char **args) } /* Fill in the other fields. */ - rt.rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST)); + rt->rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST)); while (*args) { int k = kw_lookup(tbl_ipvx, &args); const char *args_m1 = args[-1]; if (k & KW_IPVx_FLAG_ONLY) { - rt.rt_flags |= flags_ipvx[k & 3]; + rt->rt_flags |= flags_ipvx[k & 3]; continue; } #if HAVE_NEW_ADDRT if (k == KW_IPVx_METRIC) { - rt.rt_metric = xatoul(args_m1) + 1; + rt->rt_metric = xatoul(args_m1) + 1; continue; } #endif @@ -225,7 +236,7 @@ static NOINLINE void INET_setroute(int action, char **args) if (k == KW_IPVx_NETMASK) { struct sockaddr mask; - if (mask_in_addr(rt)) { + if (mask_in_addr(*rt)) { bb_show_usage(); } @@ -234,18 +245,18 @@ static NOINLINE void INET_setroute(int action, char **args) if (isnet < 0) { bb_error_msg_and_die("resolving %s", netmask); } - rt.rt_genmask = full_mask(mask); + rt->rt_genmask = full_mask(mask); continue; } if (k == KW_IPVx_GATEWAY) { - if (rt.rt_flags & RTF_GATEWAY) { + if (rt->rt_flags & RTF_GATEWAY) { bb_show_usage(); } isnet = INET_resolve(args_m1, - (struct sockaddr_in *) &rt.rt_gateway, 1); - rt.rt_flags |= RTF_GATEWAY; + (struct sockaddr_in *) &rt->rt_gateway, 1); + rt->rt_flags |= RTF_GATEWAY; if (isnet) { if (isnet < 0) { @@ -257,24 +268,24 @@ static NOINLINE void INET_setroute(int action, char **args) } if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */ - rt.rt_flags |= RTF_MSS; - rt.rt_mss = xatoul_range(args_m1, 64, 32768); + rt->rt_flags |= RTF_MSS; + rt->rt_mss = xatoul_range(args_m1, 64, 32768); continue; } if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */ - rt.rt_flags |= RTF_WINDOW; - rt.rt_window = xatoul_range(args_m1, 128, INT_MAX); + rt->rt_flags |= RTF_WINDOW; + rt->rt_window = xatoul_range(args_m1, 128, INT_MAX); continue; } #ifdef RTF_IRTT if (k == KW_IPVx_IRTT) { - rt.rt_flags |= RTF_IRTT; - rt.rt_irtt = xatoul(args_m1); - rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ + rt->rt_flags |= RTF_IRTT; + rt->rt_irtt = xatoul(args_m1); + rt->rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ - if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { + if (rt->rt_irtt < 1 || rt->rt_irtt > (120 * HZ)) { bb_error_msg_and_die("bad irtt"); } #endif @@ -284,9 +295,9 @@ static NOINLINE void INET_setroute(int action, char **args) /* Device is special in that it can be the last arg specified * and doesn't requre the dev/device keyword in that case. */ - if (!rt.rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { + if (!rt->rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ - rt.rt_dev = args[-1]; + rt->rt_dev = args[-1]; continue; } @@ -295,41 +306,41 @@ static NOINLINE void INET_setroute(int action, char **args) } #ifdef RTF_REJECT - if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) { - rt.rt_dev = (char*)"lo"; + if ((rt->rt_flags & RTF_REJECT) && !rt->rt_dev) { + rt->rt_dev = (char*)"lo"; } #endif /* sanity checks.. */ - if (mask_in_addr(rt)) { - uint32_t mask = mask_in_addr(rt); + if (mask_in_addr(*rt)) { + uint32_t mask = mask_in_addr(*rt); mask = ~ntohl(mask); - if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { + if ((rt->rt_flags & RTF_HOST) && mask != 0xffffffff) { bb_error_msg_and_die("netmask %.8x and host route conflict", (unsigned int) mask); } if (mask & (mask + 1)) { bb_error_msg_and_die("bogus netmask %s", netmask); } - mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; - if (mask & ~(uint32_t)mask_in_addr(rt)) { + mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr; + if (mask & ~(uint32_t)mask_in_addr(*rt)) { bb_error_msg_and_die("netmask and route address conflict"); } } /* Fill out netmask if still unset */ - if ((action == RTACTION_ADD) && (rt.rt_flags & RTF_HOST)) { - mask_in_addr(rt) = 0xffffffff; + if ((action == RTACTION_ADD) && (rt->rt_flags & RTF_HOST)) { + mask_in_addr(*rt) = 0xffffffff; } /* Create a socket to the INET kernel. */ skfd = xsocket(AF_INET, SOCK_DGRAM, 0); if (action == RTACTION_ADD) - xioctl(skfd, SIOCADDRT, &rt); + xioctl(skfd, SIOCADDRT, rt); else - xioctl(skfd, SIOCDELRT, &rt); + xioctl(skfd, SIOCDELRT, rt); if (ENABLE_FEATURE_CLEAN_UP) close(skfd); } @@ -602,7 +613,7 @@ static void INET6_displayroutes(void) set_flags(flags, (iflags & IPV6_MASK)); r = 0; - do { + while (1) { inet_pton(AF_INET6, addr6x + r, (struct sockaddr *) &snaddr6.sin6_addr); snaddr6.sin6_family = AF_INET6; @@ -621,7 +632,7 @@ static void INET6_displayroutes(void) free(naddr6); break; } - } while (1); + } } fclose(fp); } diff --git a/release/src/router/busybox/networking/slattach.c b/release/src/router/busybox/networking/slattach.c index 71edd2f27c..a500da6d06 100644 --- a/release/src/router/busybox/networking/slattach.c +++ b/release/src/router/busybox/networking/slattach.c @@ -13,6 +13,19 @@ * - The -F options allows disabling of RTS/CTS flow control. */ +//usage:#define slattach_trivial_usage +//usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" +//usage:#define slattach_full_usage "\n\n" +//usage: "Attach network interface(s) to serial line(s)\n" +//usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" +//usage: "\n -s SPD Set line speed" +//usage: "\n -e Exit after initializing device" +//usage: "\n -h Exit when the carrier is lost" +//usage: "\n -c PROG Run PROG when the line is hung up" +//usage: "\n -m Do NOT initialize the line in raw 8 bits mode" +//usage: "\n -L Enable 3-wire operation" +//usage: "\n -F Disable RTS/CTS flow control" + #include "libbb.h" #include "libiproute/utils.h" /* invarg() */ diff --git a/release/src/router/busybox/networking/tc.c b/release/src/router/busybox/networking/tc.c index 2e2473a702..1574353a5c 100644 --- a/release/src/router/busybox/networking/tc.c +++ b/release/src/router/busybox/networking/tc.c @@ -7,6 +7,27 @@ * Bernhard Reutner-Fischer adjusted for busybox */ +//usage:#define tc_trivial_usage +/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */ +//usage: "OBJECT CMD [dev STRING]" +//usage:#define tc_full_usage "\n\n" +//usage: "OBJECT: {qdisc|class|filter}\n" +//usage: "CMD: {add|del|change|replace|show}\n" +//usage: "\n" +//usage: "qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" +/* //usage: "[ estimator INTERVAL TIME_CONSTANT ]\n" */ +//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" +//usage: " QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" +//usage: "qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n" +//usage: "class [ classid CLASSID ] [ root | parent CLASSID ]\n" +//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" +//usage: "class show [ dev STRING ] [ root | parent CLASSID ]\n" +//usage: "filter [ pref PRIO ] [ protocol PROTO ]\n" +/* //usage: "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ +//usage: " [ root | classid CLASSID ] [ handle FILTERID ]\n" +//usage: " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" +//usage: "filter show [ dev STRING ] [ root | parent CLASSID ]" + #include "libbb.h" #include "libiproute/utils.h" @@ -37,23 +58,21 @@ struct globals { int filter_ifindex; - __u32 filter_qdisc; - __u32 filter_parent; - __u32 filter_prio; - __u32 filter_proto; + uint32_t filter_qdisc; + uint32_t filter_parent; + uint32_t filter_prio; + uint32_t filter_proto; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +struct BUG_G_too_big { + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; +}; #define filter_ifindex (G.filter_ifindex) #define filter_qdisc (G.filter_qdisc) #define filter_parent (G.filter_parent) #define filter_prio (G.filter_prio) #define filter_proto (G.filter_proto) - -void BUG_tc_globals_too_big(void); -#define INIT_G() do { \ - if (sizeof(G) > COMMON_BUFSIZE) \ - BUG_tc_globals_too_big(); \ -} while (0) +#define INIT_G() do { } while (0) /* Allocates a buffer containing the name of a class id. * The caller must free the returned memory. */ @@ -75,8 +94,8 @@ static char* print_tc_classid(uint32_t cid) } /* Get a qdisc handle. Return 0 on success, !0 otherwise. */ -static int get_qdisc_handle(__u32 *h, const char *str) { - __u32 maj; +static int get_qdisc_handle(uint32_t *h, const char *str) { + uint32_t maj; char *p; maj = TC_H_UNSPEC; @@ -94,8 +113,8 @@ static int get_qdisc_handle(__u32 *h, const char *str) { } /* Get class ID. Return 0 on success, !0 otherwise. */ -static int get_tc_classid(__u32 *h, const char *str) { - __u32 maj, min; +static int get_tc_classid(uint32_t *h, const char *str) { + uint32_t maj, min; char *p; maj = TC_H_ROOT; @@ -494,7 +513,7 @@ int tc_main(int argc UNUSED_PARAM, char **argv) if (obj == OBJ_filter) filter_parent = TC_H_ROOT; } else if (arg == ARG_parent) { - __u32 handle; + uint32_t handle; if (msg.tcm_parent) duparg(*argv, "parent"); if (get_tc_classid(&handle, *argv)) @@ -511,7 +530,7 @@ int tc_main(int argc UNUSED_PARAM, char **argv) *slash = '\0'; */ msg.tcm_handle = get_u32(*argv, "handle"); - /* if (slash) {if (get_u32(__u32 &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ + /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){ } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */ if (filter_prio) diff --git a/release/src/router/busybox/networking/tcpudp.c b/release/src/router/busybox/networking/tcpudp.c index b532e43cd9..3df6a98d8c 100644 --- a/release/src/router/busybox/networking/tcpudp.c +++ b/release/src/router/busybox/networking/tcpudp.c @@ -29,6 +29,43 @@ * - don't know how to retrieve ORIGDST for udp. */ +//usage:#define tcpsvd_trivial_usage +//usage: "[-hEv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] IP PORT PROG" +/* with not-implemented options: */ +/* //usage: "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */ +//usage:#define tcpsvd_full_usage "\n\n" +//usage: "Create TCP socket, bind to IP:PORT and listen\n" +//usage: "for incoming connection. Run PROG for each connection.\n" +//usage: "\n IP IP to listen on, 0 = all" +//usage: "\n PORT Port to listen on" +//usage: "\n PROG ARGS Program to run" +//usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" +//usage: "\n -u USER[:GRP] Change to user/group after bind" +//usage: "\n -c N Handle up to N connections simultaneously" +//usage: "\n -b N Allow a backlog of approximately N TCP SYNs" +//usage: "\n -C N[:MSG] Allow only up to N connections from the same IP" +//usage: "\n New connections from this IP address are closed" +//usage: "\n immediately. MSG is written to the peer before close" +//usage: "\n -h Look up peer's hostname" +//usage: "\n -E Don't set up environment variables" +//usage: "\n -v Verbose" +//usage: +//usage:#define udpsvd_trivial_usage +//usage: "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG" +//usage:#define udpsvd_full_usage "\n\n" +//usage: "Create UDP socket, bind to IP:PORT and wait\n" +//usage: "for incoming packets. Run PROG for each packet,\n" +//usage: "redirecting all further packets with same peer ip:port to it.\n" +//usage: "\n IP IP to listen on, 0 = all" +//usage: "\n PORT Port to listen on" +//usage: "\n PROG ARGS Program to run" +//usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" +//usage: "\n -u USER[:GRP] Change to user/group after bind" +//usage: "\n -c N Handle up to N connections simultaneously" +//usage: "\n -h Look up peer's hostname" +//usage: "\n -E Don't set up environment variables" +//usage: "\n -v Verbose" + #include "libbb.h" /* Wants etc, thus included after libbb.h: */ @@ -387,7 +424,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) * already bound in parent! This seems to work in Linux. * (otherwise we can move socket to fd #0 only if bind succeeds) */ close(0); - set_nport(localp, htons(local_port)); + set_nport(&localp->u.sa, htons(local_port)); xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0); setsockopt_reuseaddr(0); /* crucial */ xbind(0, &localp->u.sa, localp->len); diff --git a/release/src/router/busybox/networking/telnet.c b/release/src/router/busybox/networking/telnet.c index f6fad684cf..e8e51dce4a 100644 --- a/release/src/router/busybox/networking/telnet.c +++ b/release/src/router/busybox/networking/telnet.c @@ -21,14 +21,44 @@ * */ +//usage:#if ENABLE_FEATURE_TELNET_AUTOLOGIN +//usage:#define telnet_trivial_usage +//usage: "[-a] [-l USER] HOST [PORT]" +//usage:#define telnet_full_usage "\n\n" +//usage: "Connect to telnet server\n" +//usage: "\n -a Automatic login with $USER variable" +//usage: "\n -l USER Automatic login as USER" +//usage: +//usage:#else +//usage:#define telnet_trivial_usage +//usage: "HOST [PORT]" +//usage:#define telnet_full_usage "\n\n" +//usage: "Connect to telnet server" +//usage:#endif + #include #include #include "libbb.h" +#ifdef __BIONIC__ +/* should be in arpa/telnet.h */ +# define IAC 255 /* interpret as command: */ +# define DONT 254 /* you are not to use option */ +# define DO 253 /* please, you use option */ +# define WONT 252 /* I won't use option */ +# define WILL 251 /* I will use option */ +# define SB 250 /* interpret as subnegotiation */ +# define SE 240 /* end sub negotiation */ +# define TELOPT_ECHO 1 /* echo */ +# define TELOPT_SGA 3 /* suppress go ahead */ +# define TELOPT_TTYPE 24 /* terminal type */ +# define TELOPT_NAWS 31 /* window size */ +#endif + #ifdef DOTRACE -#define TRACE(x, y) do { if (x) printf y; } while (0) +# define TRACE(x, y) do { if (x) printf y; } while (0) #else -#define TRACE(x, y) +# define TRACE(x, y) #endif enum { diff --git a/release/src/router/busybox/networking/telnetd.c b/release/src/router/busybox/networking/telnetd.c index fb7bd2bf16..0bc595ab9c 100644 --- a/release/src/router/busybox/networking/telnetd.c +++ b/release/src/router/busybox/networking/telnetd.c @@ -20,6 +20,27 @@ * Vladimir Oleynik 2001 * Set process group corrections, initial busybox port */ + +//usage:#define telnetd_trivial_usage +//usage: "[OPTIONS]" +//usage:#define telnetd_full_usage "\n\n" +//usage: "Handle incoming telnet connections" +//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" +//usage: "\n -l LOGIN Exec LOGIN on connect" +//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" +//usage: "\n -K Close connection as soon as login exits" +//usage: "\n (normally wait until all programs close slave pty)" +//usage: IF_FEATURE_TELNETD_STANDALONE( +//usage: "\n -p PORT Port to listen on" +//usage: "\n -b ADDR[:PORT] Address to bind to" +//usage: "\n -F Run in foreground" +//usage: "\n -i Inetd mode" +//usage: IF_FEATURE_TELNETD_INETD_WAIT( +//usage: "\n -w SEC Inetd 'wait' mode, linger time SEC" +//usage: "\n -S Log to syslog (implied by -i or without -F and -w)" +//usage: ) +//usage: ) + #define DEBUG 0 #include "libbb.h" @@ -31,10 +52,6 @@ #endif #include -#if ENABLE_FEATURE_UTMP -# include /* LOGIN_PROCESS */ -#endif - struct tsession { struct tsession *next; @@ -315,6 +332,8 @@ make_new_session( bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); signal(SIGINT, SIG_DFL); + pid = getpid(); + if (ENABLE_FEATURE_UTMP) { len_and_sockaddr *lsa = get_peer_lsa(sock); char *hostname = NULL; @@ -336,7 +355,6 @@ make_new_session( xopen(tty_name, O_RDWR); /* becomes our ctty */ xdup2(0, 1); xdup2(0, 2); - pid = getpid(); tcsetpgrp(0, pid); /* switch this tty's process group to us */ /* The pseudo-terminal allocated to the client is configured to operate diff --git a/release/src/router/busybox/networking/tftp.c b/release/src/router/busybox/networking/tftp.c index fcd933f6ad..ce48a1edd5 100644 --- a/release/src/router/busybox/networking/tftp.c +++ b/release/src/router/busybox/networking/tftp.c @@ -18,7 +18,40 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define tftp_trivial_usage +//usage: "[OPTIONS] HOST [PORT]" +//usage:#define tftp_full_usage "\n\n" +//usage: "Transfer a file from/to tftp server\n" +//usage: "\n -l FILE Local FILE" +//usage: "\n -r FILE Remote FILE" +//usage: IF_FEATURE_TFTP_GET( +//usage: "\n -g Get file" +//usage: ) +//usage: IF_FEATURE_TFTP_PUT( +//usage: "\n -p Put file" +//usage: ) +//usage: IF_FEATURE_TFTP_BLOCKSIZE( +//usage: "\n -b SIZE Transfer blocks of SIZE octets" +//usage: ) +//usage: +//usage:#define tftpd_trivial_usage +//usage: "[-cr] [-u USER] [DIR]" +//usage:#define tftpd_full_usage "\n\n" +//usage: "Transfer a file on tftp client's request\n" +//usage: "\n" +//usage: "tftpd should be used as an inetd service.\n" +//usage: "tftpd's line for inetd.conf:\n" +//usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n" +//usage: "It also can be ran from udpsvd:\n" +//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" +//usage: "\n -r Prohibit upload" +//usage: "\n -c Allow file creation via upload" +//usage: "\n -u Access files as USER" +//usage: "\n -l Log to syslog (inetd mode requires this)" + #include "libbb.h" +#include #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT @@ -59,6 +92,7 @@ enum { TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD, TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD, TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD, + TFTPD_OPT_l = (1 << 11) * ENABLE_TFTPD, }; #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT @@ -107,19 +141,19 @@ struct BUG_G_too_big { #if ENABLE_FEATURE_TFTP_PROGRESS_BAR static void tftp_progress_update(void) { - bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size); + bb_progress_update(&G.pmt, 0, G.pos, G.size); } static void tftp_progress_init(void) { - bb_progress_init(&G.pmt); + bb_progress_init(&G.pmt, G.file); tftp_progress_update(); } static void tftp_progress_done(void) { - if (G.pmt.inited) { + if (is_bb_progress_inited(&G.pmt)) { tftp_progress_update(); bb_putchar_stderr('\n'); - G.pmt.inited = 0; + bb_progress_free(&G.pmt); } } #else @@ -422,6 +456,7 @@ static int tftp_protocol( finished = 1; } cp += len; + IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += len;) } send_pkt: /* Send packet */ @@ -443,9 +478,7 @@ static int tftp_protocol( xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len); #if ENABLE_FEATURE_TFTP_PROGRESS_BAR - if (ENABLE_TFTP && remote_file) /* tftp */ - G.pos = (block_nr - 1) * (uoff_t)blksize; - if (G.pmt.inited) + if (is_bb_progress_inited(&G.pmt)) tftp_progress_update(); #endif /* Was it final ACK? then exit */ @@ -588,6 +621,7 @@ static int tftp_protocol( if (sz != blksize) { finished = 1; } + IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += sz;) continue; /* send ACK */ } /* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */ @@ -749,10 +783,15 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) peer_lsa->len = our_lsa->len; /* Shifting to not collide with TFTP_OPTs */ - opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8); + opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:l", &user_opt) << 8); argv += optind; - if (argv[0]) - xchdir(argv[0]); + if (opt & TFTPD_OPT_l) { + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + } + if (argv[0]) { + xchroot(argv[0]); + } result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), 0 /* flags */, @@ -775,7 +814,8 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) goto err; } mode = local_file + strlen(local_file) + 1; - if (mode >= block_buf + result || strcmp(mode, "octet") != 0) { + /* RFC 1350 says mode string is case independent */ + if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) { goto err; } # if ENABLE_FEATURE_TFTP_BLOCKSIZE diff --git a/release/src/router/busybox/networking/traceroute.c b/release/src/router/busybox/networking/traceroute.c index 7fcb784ba3..d197e54101 100644 --- a/release/src/router/busybox/networking/traceroute.c +++ b/release/src/router/busybox/networking/traceroute.c @@ -210,6 +210,49 @@ * Tue Dec 20 03:50:13 PST 1988 */ +//usage:#define traceroute_trivial_usage +//usage: "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" +//usage: " [-z PAUSE_MSEC] HOST [BYTES]" +//usage:#define traceroute_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: IF_TRACEROUTE6( +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: ) +//usage: "\n -F Set the don't fragment bit" +//usage: "\n -I Use ICMP ECHO instead of UDP datagrams" +//usage: "\n -l Display the TTL value of the returned packet" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" +//usage: "\n -g Loose source route gateway (8 max)" +//usage: +//usage:#define traceroute6_trivial_usage +//usage: "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" +//usage: " HOST [BYTES]" +//usage:#define traceroute6_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default is 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" + #define TRACEROUTE_SO_DEBUG 0 /* TODO: undefs were uncommented - ??! we have config system for that! */ @@ -353,56 +396,28 @@ static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) static int -wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) +wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) { struct pollfd pfd[1]; int read_len = 0; pfd[0].fd = rcvsock; pfd[0].events = POLLIN; - if (safe_poll(pfd, 1, waittime * 1000) > 0) { + if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) { + unsigned t; + read_len = recv_from_to(rcvsock, recv_pkt, sizeof(recv_pkt), - /*flags:*/ 0, + /*flags:*/ MSG_DONTWAIT, &from_lsa->u.sa, to, from_lsa->len); + t = monotonic_us(); + *left_ms -= (t - *timestamp_us) / 1000; + *timestamp_us = t; } return read_len; } -/* - * Checksum routine for Internet Protocol family headers (C Version) - */ -static uint16_t -in_cksum(uint16_t *addr, int len) -{ - int nleft = len; - uint16_t *w = addr; - uint16_t answer; - int sum = 0; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), - * we add sequential 16 bit words to it, and at the end, fold - * back all the carry bits from the top 16 bits into the lower - * 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) - sum += *(unsigned char *)w; - - /* add back carry outs from top 16 bits to low 16 bits */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return answer; -} - static void send_probe(int seq, int ttl) { @@ -429,7 +444,7 @@ send_probe(int seq, int ttl) /* Always calculate checksum for icmp packets */ outicmp->icmp_cksum = 0; - outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, + outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp, packlen - (sizeof(*outip) + optlen)); if (outicmp->icmp_cksum == 0) outicmp->icmp_cksum = 0xffff; @@ -482,7 +497,7 @@ send_probe(int seq, int ttl) if (!(option_mask32 & OPT_USE_ICMP)) { out = outdata; len -= sizeof(*outudp); - set_nport(dest_lsa, htons(port + seq)); + set_nport(&dest_lsa->u.sa, htons(port + seq)); } } @@ -685,7 +700,7 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, type, pr_type(type), icp->icmp6_code); read_len -= sizeof(struct icmp6_hdr); - for (i = 0; i < read_len ; i++) { + for (i = 0; i < read_len; i++) { if (i % 16 == 0) printf("%04x:", i); if (i % 4 == 0) @@ -751,7 +766,8 @@ print(int read_len, const struct sockaddr *from, const struct sockaddr *to) } else #endif { - read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; + struct ip *ip4packet = (struct ip*)recv_pkt; + read_len -= ip4packet->ip_hl << 2; } printf(" %d bytes to %s", read_len, ina); free(ina); @@ -773,7 +789,6 @@ print_delta_ms(unsigned t1p, unsigned t2p) static int common_traceroute_main(int op, char **argv) { - int i; int minpacket; int tos = 0; int max_ttl = 30; @@ -887,7 +902,15 @@ common_traceroute_main(int op, char **argv) #if ENABLE_TRACEROUTE6 if (af == AF_INET6) { xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); - socket_want_pktinfo(rcvsock); +# ifdef IPV6_RECVPKTINFO + setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO, + &const_int_1, sizeof(const_int_1)); + setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO, + &const_int_1, sizeof(const_int_1)); +# else + setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO, + &const_int_1, sizeof(const_int_1)); +# endif } else #endif { @@ -919,6 +942,7 @@ common_traceroute_main(int op, char **argv) #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS if (lsrr > 0) { unsigned char optlist[MAX_IPOPTLEN]; + unsigned size; /* final hop */ gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; @@ -928,14 +952,14 @@ common_traceroute_main(int op, char **argv) optlist[0] = IPOPT_NOP; /* loose source route option */ optlist[1] = IPOPT_LSRR; - i = lsrr * sizeof(gwlist[0]); - optlist[2] = i + 3; + size = lsrr * sizeof(gwlist[0]); + optlist[2] = size + 3; /* pointer to LSRR addresses */ optlist[3] = IPOPT_MINOFF; - memcpy(optlist + 4, gwlist, i); + memcpy(optlist + 4, gwlist, size); if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, - (char *)optlist, i + sizeof(gwlist[0])) < 0) { + (char *)optlist, size + sizeof(gwlist[0])) < 0) { bb_perror_msg_and_die("IP_OPTIONS"); } } @@ -1009,10 +1033,10 @@ common_traceroute_main(int op, char **argv) int probe_fd = xsocket(af, SOCK_DGRAM, 0); if (op & OPT_DEVICE) setsockopt_bindtodevice(probe_fd, device); - set_nport(dest_lsa, htons(1025)); + set_nport(&dest_lsa->u.sa, htons(1025)); /* dummy connect. makes kernel pick source IP (and port) */ xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); - set_nport(dest_lsa, htons(port)); + set_nport(&dest_lsa->u.sa, htons(port)); /* read IP and port */ source_lsa = get_sock_lsa(probe_fd); @@ -1022,7 +1046,7 @@ common_traceroute_main(int op, char **argv) close(probe_fd); /* bind our sockets to this IP (but not port) */ - set_nport(source_lsa, 0); + set_nport(&source_lsa->u.sa, 0); xbind(sndsock, &source_lsa->u.sa, source_lsa->len); xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); @@ -1049,28 +1073,34 @@ common_traceroute_main(int op, char **argv) int unreachable = 0; /* counter */ int gotlastaddr = 0; /* flags */ int got_there = 0; - int first = 1; printf("%2d", ttl); for (probe = 0; probe < nprobes; ++probe) { int read_len; unsigned t1; unsigned t2; + int left_ms; struct ip *ip; - if (!first && pausemsecs > 0) - usleep(pausemsecs * 1000); fflush_all(); + if (probe != 0 && pausemsecs > 0) + usleep(pausemsecs * 1000); - t1 = monotonic_us(); send_probe(++seq, ttl); + t2 = t1 = monotonic_us(); + + left_ms = waittime * 1000; + while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) { + int icmp_code; + + /* Recv'ed a packet, or read error */ + /* t2 = monotonic_us() - set by wait_for_reply */ - first = 0; - while ((read_len = wait_for_reply(from_lsa, to)) != 0) { - t2 = monotonic_us(); - i = packet_ok(read_len, from_lsa, to, seq); + if (read_len < 0) + continue; + icmp_code = packet_ok(read_len, from_lsa, to, seq); /* Skip short packet */ - if (i == 0) + if (icmp_code == 0) continue; if (!gotlastaddr @@ -1089,10 +1119,10 @@ common_traceroute_main(int op, char **argv) printf(" (%d)", ip->ip_ttl); /* time exceeded in transit */ - if (i == -1) + if (icmp_code == -1) break; - i--; - switch (i) { + icmp_code--; + switch (icmp_code) { #if ENABLE_TRACEROUTE6 case ICMP6_DST_UNREACH_NOPORT << 8: got_there = 1; @@ -1165,16 +1195,18 @@ common_traceroute_main(int op, char **argv) ++unreachable; break; default: - printf(" !<%d>", i); + printf(" !<%d>", icmp_code); ++unreachable; break; } break; - } + } /* while (wait and read a packet) */ + /* there was no packet at all? */ if (read_len == 0) printf(" *"); - } + } /* for (nprobes) */ + bb_putchar('\n'); if (got_there || (unreachable > 0 && unreachable >= nprobes - 1) diff --git a/release/src/router/busybox/networking/tunctl.c b/release/src/router/busybox/networking/tunctl.c index e17a9db64a..3a0870eb5d 100644 --- a/release/src/router/busybox/networking/tunctl.c +++ b/release/src/router/busybox/networking/tunctl.c @@ -9,6 +9,24 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define tunctl_trivial_usage +//usage: "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") +//usage:#define tunctl_full_usage "\n\n" +//usage: "Create or delete tun interfaces\n" +//usage: "\n -f name tun device (/dev/net/tun)" +//usage: "\n -t name Create iface 'name'" +//usage: "\n -d name Delete iface 'name'" +//usage: IF_FEATURE_TUNCTL_UG( +//usage: "\n -u owner Set iface owner" +//usage: "\n -g group Set iface group" +//usage: "\n -b Brief output" +//usage: ) +//usage: +//usage:#define tunctl_example_usage +//usage: "# tunctl\n" +//usage: "# tunctl -d tun0\n" + #include #include #include diff --git a/release/src/router/busybox/networking/udhcp/Config.src b/release/src/router/busybox/networking/udhcp/Config.src index 07d0291dba..7184ab6150 100644 --- a/release/src/router/busybox/networking/udhcp/Config.src +++ b/release/src/router/busybox/networking/udhcp/Config.src @@ -8,7 +8,7 @@ INSERT config UDHCPD bool "udhcp server (udhcpd)" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help udhcpd is a DHCP server geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. @@ -39,7 +39,21 @@ config FEATURE_UDHCPD_WRITE_LEASES_EARLY If selected, udhcpd will write a new file with leases every time a new lease has been accepted, thus eliminating the need to send SIGUSR1 for the initial writing or updating. Any timed - rewriting remains undisturbed + rewriting remains undisturbed. + +config FEATURE_UDHCPD_BASE_IP_ON_MAC + bool "Select IP address based on client MAC" + default n + depends on UDHCPD + help + If selected, udhcpd will base its selection of IP address to offer + on the client's hardware address. Otherwise udhcpd uses the next + consecutive free address. + + This reduces the frequency of IP address changes for clients + which let their lease expire, and makes consecutive DHCPOFFERS + for the same client to (almost always) contain the same + IP address. config DHCPD_LEASES_FILE string "Absolute path to lease file" @@ -52,7 +66,7 @@ config DHCPD_LEASES_FILE config UDHCPC bool "udhcp client (udhcpc)" default y - depends on PLATFORM_LINUX + select PLATFORM_LINUX help udhcpc is a DHCP client geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. @@ -72,7 +86,7 @@ config FEATURE_UDHCPC_ARPING config FEATURE_UDHCP_PORT bool "Enable '-P port' option for udhcpd and udhcpc" - default y + default n depends on UDHCPD || UDHCPC help At the cost of ~300 bytes, enables -P port option. @@ -106,6 +120,14 @@ config FEATURE_UDHCP_RFC5969 help None. +config FEATURE_UDHCP_8021Q + bool "Support for 802.1Q VLAN parameters" + default y + depends on UDHCPD || UDHCPC + help + If selected, both client and server will support passing of VLAN + ID and priority via options 132 and 133 as per 802.1Q. + config UDHCPC_DEFAULT_SCRIPT string "Absolute path to config script" default "/usr/share/udhcpc/default.script" diff --git a/release/src/router/busybox/networking/udhcp/arpping.c b/release/src/router/busybox/networking/udhcp/arpping.c index ff6347847f..b43e52e964 100644 --- a/release/src/router/busybox/networking/udhcp/arpping.c +++ b/release/src/router/busybox/networking/udhcp/arpping.c @@ -118,8 +118,13 @@ int FAST_FUNC arpping(uint32_t test_nip, break; } } - timeout_ms -= (unsigned)monotonic_ms() - prevTime; - } while (timeout_ms > 0); + timeout_ms -= (unsigned)monotonic_ms() - prevTime + 1; + + /* We used to check "timeout_ms > 0", but + * this is more under/overflow-resistant + * (people did see overflows here when system time jumps): + */ + } while ((unsigned)timeout_ms <= 2000); ret: close(s); diff --git a/release/src/router/busybox/networking/udhcp/common.c b/release/src/router/busybox/networking/udhcp/common.c index 1efe49b91c..a15220d352 100644 --- a/release/src/router/busybox/networking/udhcp/common.c +++ b/release/src/router/busybox/networking/udhcp/common.c @@ -536,3 +536,22 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) return retval; } + +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) +{ + char hexstrbuf[16 * 2]; + bin2hex(hexstrbuf, (void*)ip, 16); + return sprintf(dest, /* "%s" */ + "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", + /* pre, */ + hexstrbuf + 0 * 4, + hexstrbuf + 1 * 4, + hexstrbuf + 2 * 4, + hexstrbuf + 3 * 4, + hexstrbuf + 4 * 4, + hexstrbuf + 5 * 4, + hexstrbuf + 6 * 4, + hexstrbuf + 7 * 4 + ); +} diff --git a/release/src/router/busybox/networking/udhcp/common.c b/release/src/router/busybox/networking/udhcp/common.c.20 similarity index 86% copy from release/src/router/busybox/networking/udhcp/common.c copy to release/src/router/busybox/networking/udhcp/common.c.20 index 1efe49b91c..889f3ebf5a 100644 --- a/release/src/router/busybox/networking/udhcp/common.c +++ b/release/src/router/busybox/networking/udhcp/common.c.20 @@ -29,15 +29,15 @@ const struct dhcp_optflag dhcp_optflags[] = { // { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ // { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ - { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ - { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ { OPTION_U16 , 0x1a }, /* DHCP_MTU */ { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ - { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ + { OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */ { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ @@ -45,7 +45,7 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ //TODO: must be combined with 'sname' and 'file' handling: - { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ + { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ //TODO: not a string, but a set of LASCII strings: // { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ @@ -53,13 +53,13 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ #endif - { OPTION_STATIC_ROUTES | OPTION_REQ, 0x79 }, /* DHCP_STATIC_ROUTES */ - { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x21 }, /* DHCP_ROUTES */ - { OPTION_STATIC_ROUTES | OPTION_REQ, 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ -#if ENABLE_FEATURE_UDHCP_RFC5969 - { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ - { OPTION_6RD , 0x96 }, /* DHCP_COMCAST_6RD */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */ +#if ENABLE_FEATURE_UDHCP_8021Q + { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ + { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ #endif + { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ /* Options below have no match in dhcp_option_strings[], @@ -102,6 +102,7 @@ const char dhcp_option_strings[] ALIGN1 = "ipttl" "\0" /* DHCP_IP_TTL */ "mtu" "\0" /* DHCP_MTU */ "broadcast" "\0" /* DHCP_BROADCAST */ + "routes" "\0" /* DHCP_ROUTES */ "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ "nissrv" "\0" /* DHCP_NIS_SERVER */ "ntpsrv" "\0" /* DHCP_NTP_SERVER */ @@ -118,10 +119,12 @@ const char dhcp_option_strings[] ALIGN1 = // is not handled yet by "string->option" conversion code: "sipsrv" "\0" /* DHCP_SIP_SERVERS */ #endif -// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES -// is not handled yet by "string->option" conversion code: "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ - "routes" "\0" /* DHCP_ROUTES */ +#if ENABLE_FEATURE_UDHCP_8021Q + "vlanid" "\0" /* DHCP_VLAN_ID */ + "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ +#endif + "ip6rd" "\0" /* DHCP_6RD */ "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ #if ENABLE_FEATURE_UDHCP_RFC5969 "6rd" "\0" /* DHCP_6RD */ @@ -143,6 +146,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_IP_PAIR] = 8, // [OPTION_BOOLEAN] = 1, [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */ + [OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */ #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */ [OPTION_SIP_SERVERS] = 1, @@ -334,7 +338,8 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) lsa = host_and_af2sockaddr(str, 0, AF_INET); if (!lsa) return 0; - *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; + /* arg maybe unaligned */ + move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr); free(lsa); return 1; } @@ -414,7 +419,9 @@ static NOINLINE void attach_option( /* actually 255 is ok too, but adding a space can overlow it */ existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); - if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) { + if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING + || (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST + ) { /* add space separator between STRING options in a list */ existing->data[OPT_DATA + old_len] = ' '; old_len++; @@ -431,13 +438,14 @@ static NOINLINE void attach_option( int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) { struct option_set **opt_list = arg; - char *opt, *val, *endptr; + char *opt, *val; char *str; const struct dhcp_optflag *optflag; struct dhcp_optflag bin_optflag; unsigned optcode; int retval, length; - char buffer[8] ALIGNED(4); + /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ + char buffer[9] ALIGNED(4); uint16_t *result_u16 = (uint16_t *) buffer; uint32_t *result_u32 = (uint32_t *) buffer; @@ -478,6 +486,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) retval = udhcp_str2nip(val, buffer + 4); break; case OPTION_STRING: + case OPTION_STRING_HOST: #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: #endif @@ -494,34 +503,53 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) // break; // } case OPTION_U8: - buffer[0] = strtoul(val, &endptr, 0); - retval = (endptr[0] == '\0'); + buffer[0] = bb_strtou32(val, NULL, 0); + retval = (errno == 0); break; /* htonX are macros in older libc's, using temp var * in code below for safety */ /* TODO: use bb_strtoX? */ case OPTION_U16: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u16 = htons(tmp); - retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); + retval = (errno == 0 /*&& tmp < 0x10000*/); break; } // case OPTION_S16: { -// long tmp = strtol(val, &endptr, 0); +// long tmp = bb_strtoi32(val, NULL, 0); // *result_u16 = htons(tmp); -// retval = (endptr[0] == '\0'); +// retval = (errno == 0); // break; // } case OPTION_U32: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); break; } case OPTION_S32: { - long tmp = strtol(val, &endptr, 0); + int32_t tmp = bb_strtoi32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); + break; + } + case OPTION_STATIC_ROUTES: { + /* Input: "a.b.c.d/m" */ + /* Output: mask(1 byte),pfx(0-4 bytes),gw(4 bytes) */ + unsigned mask; + char *slash = strchr(val, '/'); + if (slash) { + *slash = '\0'; + retval = udhcp_str2nip(val, buffer + 1); + buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); + val = strtok(NULL, ", \t/-"); + if (!val || mask > 32 || errno) + retval = 0; + if (retval) { + length = ((mask + 7) >> 3) + 5; + retval = udhcp_str2nip(val, buffer + (length - 4)); + } + } break; } case OPTION_BIN: /* handled in attach_option() */ @@ -532,7 +560,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) } if (retval) attach_option(opt_list, optflag, opt, length); - } while (retval && optflag->flags & OPTION_LIST); + } while (retval && (optflag->flags & OPTION_LIST)); return retval; } + +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) +{ + char hexstrbuf[16 * 2]; + bin2hex(hexstrbuf, (void*)ip, 16); + return sprintf(dest, /* "%s" */ + "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", + /* pre, */ + hexstrbuf + 0 * 4, + hexstrbuf + 1 * 4, + hexstrbuf + 2 * 4, + hexstrbuf + 3 * 4, + hexstrbuf + 4 * 4, + hexstrbuf + 5 * 4, + hexstrbuf + 6 * 4, + hexstrbuf + 7 * 4 + ); +} diff --git a/release/src/router/busybox/networking/udhcp/common.h b/release/src/router/busybox/networking/udhcp/common.h index 1847b48783..331ef42421 100644 --- a/release/src/router/busybox/networking/udhcp/common.h +++ b/release/src/router/busybox/networking/udhcp/common.h @@ -82,6 +82,9 @@ enum { OPTION_IP = 1, OPTION_IP_PAIR, OPTION_STRING, + /* Opts of STRING_HOST type will be sanitized before they are passed + * to udhcpc script's environment: */ + OPTION_STRING_HOST, // OPTION_BOOLEAN, OPTION_U8, OPTION_U16, @@ -253,6 +256,7 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) /*** Logging ***/ #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ extern unsigned dhcp_verbose; # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) # if CONFIG_UDHCP_DEBUG >= 2 @@ -268,6 +272,7 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; # define log3(...) ((void)0) # endif #else +# define IF_UDHCP_VERBOSE(...) # define udhcp_dump_packet(...) ((void)0) # define log1(...) ((void)0) # define log2(...) ((void)0) @@ -282,8 +287,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg); /* 2nd param is "struct option_set**" */ int FAST_FUNC udhcp_str2optset(const char *str, void *arg); -uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; - void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; @@ -312,6 +315,9 @@ int arpping(uint32_t test_nip, uint8_t *from_mac, const char *interface) FAST_FUNC; +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int sprint_nip6(char *dest, /* const char *pre, */ const uint8_t *ip) FAST_FUNC; + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/udhcp/common.h b/release/src/router/busybox/networking/udhcp/common.h.20 similarity index 96% copy from release/src/router/busybox/networking/udhcp/common.h copy to release/src/router/busybox/networking/udhcp/common.h.20 index 1847b48783..327d4986a1 100644 --- a/release/src/router/busybox/networking/udhcp/common.h +++ b/release/src/router/busybox/networking/udhcp/common.h.20 @@ -82,6 +82,9 @@ enum { OPTION_IP = 1, OPTION_IP_PAIR, OPTION_STRING, + /* Opts of STRING_HOST type will be sanitized before they are passed + * to udhcpc script's environment: */ + OPTION_STRING_HOST, // OPTION_BOOLEAN, OPTION_U8, OPTION_U16, @@ -90,13 +93,11 @@ enum { OPTION_S32, OPTION_BIN, OPTION_STATIC_ROUTES, + OPTION_6RD, #if ENABLE_FEATURE_UDHCP_RFC3397 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ OPTION_SIP_SERVERS, #endif -#if ENABLE_FEATURE_UDHCP_RFC5969 - OPTION_6RD, -#endif OPTION_TYPE_MASK = 0x0f, /* Client requests this option by default */ @@ -108,7 +109,7 @@ enum { /* DHCP option codes (partial list). See RFC 2132 and * http://www.iana.org/assignments/bootp-dhcp-parameters/ * Commented out options are handled by common option machinery, - * uncommented ones have spacial cases (grep for them to see). + * uncommented ones have special cases (grep for them to see). */ #define DHCP_PADDING 0x00 #define DHCP_SUBNET 0x01 @@ -150,6 +151,8 @@ enum { //#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ //#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ //#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ +#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */ +#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */ //#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ //#define DHCP_6RD 0xd4 /* RFC 5969 6RD option */ //#define DHCP_COMCAST_6RD 0x96 /* Comcast ISP RFC 5969 compatible 6RD option */ @@ -253,6 +256,7 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) /*** Logging ***/ #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ extern unsigned dhcp_verbose; # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) # if CONFIG_UDHCP_DEBUG >= 2 @@ -268,6 +272,7 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; # define log3(...) ((void)0) # endif #else +# define IF_UDHCP_VERBOSE(...) # define udhcp_dump_packet(...) ((void)0) # define log1(...) ((void)0) # define log2(...) ((void)0) @@ -282,8 +287,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg); /* 2nd param is "struct option_set**" */ int FAST_FUNC udhcp_str2optset(const char *str, void *arg); -uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; - void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; @@ -312,6 +315,9 @@ int arpping(uint32_t test_nip, uint8_t *from_mac, const char *interface) FAST_FUNC; +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC; + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/udhcp/d6_common.h b/release/src/router/busybox/networking/udhcp/d6_common.h new file mode 100644 index 0000000000..eb211ea0f1 --- /dev/null +++ b/release/src/router/busybox/networking/udhcp/d6_common.h @@ -0,0 +1,127 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#ifndef UDHCP_D6_COMMON_H +#define UDHCP_D6_COMMON_H 1 + +#include + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + + +/*** DHCPv6 packet ***/ + +/* DHCPv6 protocol. See RFC 3315 */ +#define D6_MSG_SOLICIT 1 +#define D6_MSG_ADVERTISE 2 +#define D6_MSG_REQUEST 3 +#define D6_MSG_CONFIRM 4 +#define D6_MSG_RENEW 5 +#define D6_MSG_REBIND 6 +#define D6_MSG_REPLY 7 +#define D6_MSG_RELEASE 8 +#define D6_MSG_DECLINE 9 +#define D6_MSG_RECONFIGURE 10 +#define D6_MSG_INFORMATION_REQUEST 11 +#define D6_MSG_RELAY_FORW 12 +#define D6_MSG_RELAY_REPL 13 + +struct d6_packet { + union { + uint8_t d6_msg_type; + uint32_t d6_xid32; + } d6_u; + uint8_t d6_options[576 - sizeof(struct iphdr) - sizeof(struct udphdr) - 4 + + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; +} PACKED; +#define d6_msg_type d6_u.d6_msg_type +#define d6_xid32 d6_u.d6_xid32 + +struct ip6_udp_d6_packet { + struct ip6_hdr ip6; + struct udphdr udp; + struct d6_packet data; +} PACKED; + +struct udp_d6_packet { + struct udphdr udp; + struct d6_packet data; +} PACKED; + +/*** Options ***/ + +struct d6_option { + uint8_t code_hi; + uint8_t code; + uint8_t len_hi; + uint8_t len; + uint8_t data[1]; +} PACKED; + +#define D6_OPT_CLIENTID 1 +#define D6_OPT_SERVERID 2 +#define D6_OPT_IA_NA 3 +#define D6_OPT_IA_TA 4 +#define D6_OPT_IAADDR 5 +#define D6_OPT_ORO 6 +#define D6_OPT_PREFERENCE 7 +#define D6_OPT_ELAPSED_TIME 8 +#define D6_OPT_RELAY_MSG 9 +#define D6_OPT_AUTH 11 +#define D6_OPT_UNICAST 12 +#define D6_OPT_STATUS_CODE 13 +#define D6_OPT_RAPID_COMMIT 14 +#define D6_OPT_USER_CLASS 15 +#define D6_OPT_VENDOR_CLASS 16 +#define D6_OPT_VENDOR_OPTS 17 +#define D6_OPT_INTERFACE_ID 18 +#define D6_OPT_RECONF_MSG 19 +#define D6_OPT_RECONF_ACCEPT 20 + +#define D6_OPT_IA_PD 25 +#define D6_OPT_IAPREFIX 26 + +/*** Other shared functions ***/ + +struct client6_data_t { + struct d6_option *server_id; + struct d6_option *ia_na; + char **env_ptr; + unsigned env_idx; +}; + +#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) + +int FAST_FUNC d6_listen_socket(int port, const char *inf); + +int FAST_FUNC d6_recv_kernel_packet( + struct in6_addr *peer_ipv6, + struct d6_packet *packet, int fd +); + +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex +); + +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port +); + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +void FAST_FUNC d6_dump_packet(struct d6_packet *packet); +#else +# define d6_dump_packet(packet) ((void)0) +#endif + + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/release/src/router/busybox/networking/udhcp/d6_dhcpc.c b/release/src/router/busybox/networking/udhcp/d6_dhcpc.c new file mode 100644 index 0000000000..a792a9dcab --- /dev/null +++ b/release/src/router/busybox/networking/udhcp/d6_dhcpc.c @@ -0,0 +1,1483 @@ +/* vi: set sw=4 ts=4: */ +/* + * DHCPv6 client. + * + * 2011-11. + * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR + * TO BE READY FOR PRODUCTION USE. + * + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UDHCPC6 +//config: bool "udhcp client for DHCPv6 (udhcpc6)" +//config: default n # not yet ready +//config: help +//config: udhcpc6 is a DHCPv6 client + +//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o + + +#include +/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ +#define WANT_PIDFILE 1 +#include "common.h" +#include "dhcpd.h" +#include "dhcpc.h" +#include "d6_common.h" + +#include +#include +#include + +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ + + +#if ENABLE_LONG_OPTS +static const char udhcpc6_longopts[] ALIGN1 = + "interface\0" Required_argument "i" + "now\0" No_argument "n" + "pidfile\0" Required_argument "p" + "quit\0" No_argument "q" + "release\0" No_argument "R" + "request\0" Required_argument "r" + "script\0" Required_argument "s" + "timeout\0" Required_argument "T" + "retries\0" Required_argument "t" + "tryagain\0" Required_argument "A" + "syslog\0" No_argument "S" + "request-option\0" Required_argument "O" + "no-default-options\0" No_argument "o" + "foreground\0" No_argument "f" + "background\0" No_argument "b" +/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") + IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") + ; +#endif +/* Must match getopt32 option string order */ +enum { + OPT_i = 1 << 0, + OPT_n = 1 << 1, + OPT_p = 1 << 2, + OPT_q = 1 << 3, + OPT_R = 1 << 4, + OPT_r = 1 << 5, + OPT_s = 1 << 6, + OPT_T = 1 << 7, + OPT_t = 1 << 8, + OPT_S = 1 << 9, + OPT_A = 1 << 10, + OPT_O = 1 << 11, + OPT_o = 1 << 12, + OPT_x = 1 << 13, + OPT_f = 1 << 14, +/* The rest has variable bit positions, need to be clever */ + OPTBIT_f = 14, + USE_FOR_MMU( OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPTBIT_P,) + USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) +}; + + +/*** Utility functions ***/ + +static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + /* Next option's len is too big? */ + if (option[3] > len_m4) + return NULL; /* yes. bogus packet! */ + /* So far we treat any opts with code >255 + * or len >255 as bogus, and stop at once. + * This simplifies big-endian handling. + */ + if (option[0] != 0 || option[2] != 0) + return NULL; + /* Option seems to be valid */ + /* Does its code match? */ + if (option[1] == code) + return option; /* yes! */ + option += option[3] + 4; + len_m4 -= option[3] + 4; + } + return NULL; +} + +static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + uint8_t *opt = d6_find_option(option, option_end, code); + if (!opt) + return opt; + return memcpy(xmalloc(opt[3] + 4), opt, opt[3] + 4); +} + +static void *d6_store_blob(void *dst, const void *src, unsigned len) +{ + memcpy(dst, src, len); + return dst + len; +} + + +/*** Script execution code ***/ + +static char** new_env(void) +{ + client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx); + return &client6_data.env_ptr[client6_data.env_idx++]; +} + +/* put all the parameters into the environment */ +static void option_to_env(uint8_t *option, uint8_t *option_end) +{ + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + uint32_t v32; + char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; + + if (option[0] != 0 || option[2] != 0) + break; + + switch (option[1]) { + //case D6_OPT_CLIENTID: + //case D6_OPT_SERVERID: + case D6_OPT_IA_NA: + case D6_OPT_IA_PD: + option_to_env(option + 16, option + 4 + option[3]); + break; + //case D6_OPT_IA_TA: + case D6_OPT_IAADDR: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + sprint_nip6(ipv6str, option + 4); + *new_env() = xasprintf("ipv6=%s", ipv6str); + + move_from_unaligned32(v32, option + 4 + 16 + 4); + *new_env() = xasprintf("lease=%u", (unsigned)v32); + break; + + //case D6_OPT_ORO: + //case D6_OPT_PREFERENCE: + //case D6_OPT_ELAPSED_TIME: + //case D6_OPT_RELAY_MSG: + //case D6_OPT_AUTH: + //case D6_OPT_UNICAST: + //case D6_OPT_STATUS_CODE: + //case D6_OPT_RAPID_COMMIT: + //case D6_OPT_USER_CLASS: + //case D6_OPT_VENDOR_CLASS: + //case D6_OPT_VENDOR_OPTS: + //case D6_OPT_INTERFACE_ID: + //case D6_OPT_RECONF_MSG: + //case D6_OPT_RECONF_ACCEPT: + + case D6_OPT_IAPREFIX: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAPREFIX | option-length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | prefix-length | | + * +-+-+-+-+-+-+-+-+ IPv6 prefix | + * | (16 octets) | + * | | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * +-+-+-+-+-+-+-+-+ + */ + //move_from_unaligned32(v32, option + 4 + 4); + //*new_env() = xasprintf("lease=%u", (unsigned)v32); + + sprint_nip6(ipv6str, option + 4 + 4 + 1); + *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); + } + option += 4 + option[3]; + len_m4 -= 4 + option[3]; + } +} + +static char **fill_envp(struct d6_packet *packet) +{ + char **envp, **curr; + + client6_data.env_ptr = NULL; + client6_data.env_idx = 0; + + *new_env() = xasprintf("interface=%s", client_config.interface); + + if (packet) + option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options)); + + envp = curr = client6_data.env_ptr; + while (*curr) + putenv(*curr++); + + return envp; +} + +/* Call a script with a par file and env vars */ +static void d6_run_script(struct d6_packet *packet, const char *name) +{ + char **envp, **curr; + char *argv[3]; + + envp = fill_envp(packet); + + /* call script */ + log1("Executing %s %s", client_config.script, name); + argv[0] = (char*) client_config.script; + argv[1] = (char*) name; + argv[2] = NULL; + spawn_and_wait(argv); + + for (curr = envp; *curr; curr++) { + log2(" %s", *curr); + bb_unsetenv_and_free(*curr); + } + free(envp); +} + + +/*** Sending/receiving packets ***/ + +static ALWAYS_INLINE uint32_t random_xid(void) +{ + uint32_t t = rand() & htonl(0x00ffffff); + return t; +} + +/* Initialize the packet with the proper defaults */ +static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) +{ + struct d6_option *clientid; + + memset(packet, 0, sizeof(*packet)); + + packet->d6_xid32 = xid; + packet->d6_msg_type = type; + + clientid = (void*)client_config.clientid; + return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2); +} + +static uint8_t *add_d6_client_options(uint8_t *ptr) +{ + return ptr; + //uint8_t c; + //int i, end, len; + + /* Add a "param req" option with the list of options we'd like to have + * from stubborn DHCP servers. Pull the data from the struct in common.c. + * No bounds checking because it goes towards the head of the packet. */ + //... + + /* Add -x options if any */ + //... +} + +static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) +{ + static const uint8_t FF02__1_2[16] = { + 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, + }; + + return d6_send_raw_packet( + packet, (end - (uint8_t*) packet), + /*src*/ NULL, CLIENT_PORT, + /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT, MAC_BCAST_ADDR, + client_config.ifindex + ); +} + +/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. + * + * RFC 3315 17.1.1. Creation of Solicit Messages + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client includes IA options for any IAs to which + * it wants the server to assign addresses. The client MAY include + * addresses in the IAs as a hint to the server about addresses for + * which the client has a preference. ... + * + * The client uses IA_NA options to request the assignment of non- + * temporary addresses and uses IA_TA options to request the assignment + * of temporary addresses. Either IA_NA or IA_TA options, or a + * combination of both, can be included in DHCP messages. + * + * The client SHOULD include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY additionally include instances of those options that are + * identified in the Option Request option, with data values as hints to + * the server about parameter values the client would like to have + * returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * if the client is willing to accept Reconfigure messages from the + * server. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_CLIENTID | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . DUID . + . (variable length) . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IA_NA | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IAID (4 octets) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T1 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . IA_NA-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IAADDR | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | IPv6 address | + | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | preferred-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | valid-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . IAaddr-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_ORO | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | requested-option-code-1 | requested-option-code-2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_RECONF_ACCEPT | 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + unsigned len; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); + + /* Create new IA_NA, optionally with included IAADDR with requested IP */ + free(client6_data.ia_na); + len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; + client6_data.ia_na = xzalloc(len); + client6_data.ia_na->code = D6_OPT_IA_NA; + client6_data.ia_na->len = len - 4; + *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ + if (requested_ipv6) { + struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); + iaaddr->code = D6_OPT_IAADDR; + iaaddr->len = 16+4+4; + memcpy(iaaddr->data, requested_ipv6, 16); + } + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending discover..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Multicast a DHCPv6 request message + * + * RFC 3315 18.1.1. Creation and Transmission of Request Messages + * + * The client uses a Request message to populate IAs with addresses and + * obtain other configuration information. The client includes one or + * more IA options in the Request message. The server then returns + * addresses and other information about the IAs to the client in IA + * options in a Reply message. + * + * The client generates a transaction ID and inserts this value in the + * "transaction-id" field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any other appropriate options, + * including one or more IA options (if the client is requesting that + * the server assign it some network addresses). + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * indicating whether or not the client is willing to accept Reconfigure + * messages from the server. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_select(uint32_t xid) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending select..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast or broadcast a DHCP renew message + * + * RFC 3315 18.1.3. Creation and Transmission of Renew Messages + * + * To extend the valid and preferred lifetimes for the addresses + * associated with an IA, the client sends a Renew message to the server + * from which the client obtained the addresses in the IA containing an + * IA option for the IA. The client includes IA Address options in the + * IA option for the addresses associated with the IA. The server + * determines new lifetimes for the addresses in the IA according to the + * administrative configuration of the server. The server may also add + * new addresses to the IA. The server may remove addresses from the IA + * by setting the preferred and valid lifetimes of those addresses to + * zero. + * + * The server controls the time at which the client contacts the server + * to extend the lifetimes on assigned addresses through the T1 and T2 + * parameters assigned to an IA. + * + * At time T1 for an IA, the client initiates a Renew/Reply message + * exchange to extend the lifetimes on any addresses in the IA. The + * client includes an IA option with all addresses currently assigned to + * the IA in its Renew message. + * + * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no + * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind + * message, respectively, at the client's discretion. + * + * The client sets the "msg-type" field to RENEW. The client generates + * a transaction ID and inserts this value in the "transaction-id" + * field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any appropriate options, including + * one or more IA options. The client MUST include the list of + * addresses the client currently has associated with the IAs in the + * Renew message. + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending renew..."); + if (server_ipv6) + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT, + server_ipv6, SERVER_PORT + ); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast a DHCP release message */ +static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains our current IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + bb_info_msg("Sending release..."); + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT, + server_ipv6, SERVER_PORT + ); +} + +/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *d6_pkt, int fd) +{ + int bytes; + struct ip6_udp_d6_packet packet; + + bytes = safe_read(fd, &packet, sizeof(packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + /* NB: possible down interface, etc. Caller should pause. */ + return bytes; /* returns -1 */ + } + + if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) { + log1("Packet is too short, ignoring"); + return -2; + } + + if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) { + /* packet is bigger than sizeof(packet), we did partial read */ + log1("Oversized packet, ignoring"); + return -2; + } + + /* ignore any extra garbage bytes */ + bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen); + + /* make sure its the right packet for us, and that it passes sanity checks */ + if (packet.ip6.ip6_nxt != IPPROTO_UDP + || (packet.ip6.ip6_vfc >> 4) != 6 + || packet.udp.dest != htons(CLIENT_PORT) + /* || bytes > (int) sizeof(packet) - can't happen */ + || packet.udp.len != packet.ip6.ip6_plen + ) { + log1("Unrelated/bogus packet, ignoring"); + return -2; + } + +//How to do this for ipv6? +// /* verify UDP checksum. IP header has to be modified for this */ +// memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); +// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ +// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ +// check = packet.udp.check; +// packet.udp.check = 0; +// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { +// log1("Packet with bad UDP checksum received, ignoring"); +// return -2; +// } + + log1("Received a packet"); + d6_dump_packet(&packet.data); + + bytes -= sizeof(packet.ip6) + sizeof(packet.udp); + memcpy(d6_pkt, &packet.data, bytes); + return bytes; +} + + +/*** Main ***/ + +static int sockfd = -1; + +#define LISTEN_NONE 0 +#define LISTEN_KERNEL 1 +#define LISTEN_RAW 2 +static smallint listen_mode; + +/* initial state: (re)start DHCP negotiation */ +#define INIT_SELECTING 0 +/* discover was sent, DHCPOFFER reply received */ +#define REQUESTING 1 +/* select/renew was sent, DHCPACK reply received */ +#define BOUND 2 +/* half of lease passed, want to renew it by sending unicast renew requests */ +#define RENEWING 3 +/* renew requests were not answered, lease is almost over, send broadcast renew */ +#define REBINDING 4 +/* manually requested renew (SIGUSR1) */ +#define RENEW_REQUESTED 5 +/* release, possibly manually requested (SIGUSR2) */ +#define RELEASED 6 +static smallint state; + +static int d6_raw_socket(int ifindex) +{ + int fd; + struct sockaddr_ll sock; + + /* + * Comment: + * + * I've selected not to see LL header, so BPF doesn't see it, too. + * The filter may also pass non-IP and non-ARP packets, but we do + * a more complete check when receiving the message in userspace. + * + * and filter shamelessly stolen from: + * + * http://www.flamewarmaster.de/software/dhcpclient/ + * + * There are a few other interesting ideas on that page (look under + * "Motivation"). Use of netlink events is most interesting. Think + * of various network servers listening for events and reconfiguring. + * That would obsolete sending HUP signals and/or make use of restarts. + * + * Copyright: 2006, 2007 Stefan Rompf . + * License: GPL v2. + * + * TODO: make conditional? + */ +#if 0 + static const struct sock_filter filter_instr[] = { + /* load 9th byte (protocol) */ + BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), + }; + static const struct sock_fprog filter_prog = { + .len = sizeof(filter_instr) / sizeof(filter_instr[0]), + /* casting const away: */ + .filter = (struct sock_filter *) filter_instr, + }; +#endif + + log1("Opening raw socket on ifindex %d", ifindex); //log2? + + fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + log1("Got raw socket fd %d", fd); //log2? + + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IPV6); + sock.sll_ifindex = ifindex; + xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); + +#if 0 + if (CLIENT_PORT == 68) { + /* Use only if standard port is in use */ + /* Ignoring error (kernel may lack support for this) */ + if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, + sizeof(filter_prog)) >= 0) + log1("Attached filter to raw socket fd %d", fd); // log? + } +#endif + + log1("Created raw socket"); + + return fd; +} + +static void change_listen_mode(int new_mode) +{ + log1("Entering listen mode: %s", + new_mode != LISTEN_NONE + ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") + : "none" + ); + + listen_mode = new_mode; + if (sockfd >= 0) { + close(sockfd); + sockfd = -1; + } + if (new_mode == LISTEN_KERNEL) + sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); + else if (new_mode != LISTEN_NONE) + sockfd = d6_raw_socket(client_config.ifindex); + /* else LISTEN_NONE: sockfd stays closed */ +} + +/* Called only on SIGUSR1 */ +static void perform_renew(void) +{ + bb_info_msg("Performing a DHCP renew"); + switch (state) { + case BOUND: + change_listen_mode(LISTEN_KERNEL); + case RENEWING: + case REBINDING: + state = RENEW_REQUESTED; + break; + case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ + d6_run_script(NULL, "deconfig"); + case REQUESTING: + case RELEASED: + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + break; + case INIT_SELECTING: + break; + } +} + +static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + /* send release packet */ + if (state == BOUND || state == RENEWING || state == REBINDING) { + bb_info_msg("Unicasting a release"); + send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ + d6_run_script(NULL, "deconfig"); + } + bb_info_msg("Entering released state"); + + change_listen_mode(LISTEN_NONE); + state = RELEASED; +} + +///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) +///{ +/// uint8_t *storage; +/// int len = strnlen(str, 255); +/// storage = xzalloc(len + extra + OPT_DATA); +/// storage[OPT_CODE] = code; +/// storage[OPT_LEN] = len + extra; +/// memcpy(storage + extra + OPT_DATA, str, len); +/// return storage; +///} + +#if BB_MMU +static void client_background(void) +{ + bb_daemonize(0); + logmode &= ~LOGMODE_STDIO; + /* rewrite pidfile, as our pid is different now */ + write_pidfile(client_config.pidfile); +} +#endif + +//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_UDHCP_VERBOSE(...) +//usage:#endif +//usage:#define udhcpc6_trivial_usage +//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" +//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") +//usage:#define udhcpc6_full_usage "\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--interface IFACE Interface to use (default eth0)" +//usage: "\n -p,--pidfile FILE Create pidfile" +//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B,--broadcast Request broadcast replies" +//usage: "\n -t,--retries N Send up to N discover packets" +//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" +//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" +//usage: "\n -f,--foreground Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b,--background Background if lease is not obtained" +//usage: ) +//usage: "\n -n,--now Exit if lease is not obtained" +//usage: "\n -q,--quit Exit after obtaining lease" +//usage: "\n -R,--release Release IP on exit" +//usage: "\n -S,--syslog Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P,--client-port N Use port N (default 546)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a,--arping Use arping to validate offered address" +////usage: ) +//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" +//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" +//usage: "\n -r,--request IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i IFACE Interface to use (default eth0)" +//usage: "\n -p FILE Create pidfile" +//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B Request broadcast replies" +//usage: "\n -t N Send up to N discover packets" +//usage: "\n -T N Pause between packets (default 3 seconds)" +//usage: "\n -A N Wait N seconds (default 20) after failure" +//usage: "\n -f Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b Background if lease is not obtained" +//usage: ) +//usage: "\n -n Exit if lease is not obtained" +//usage: "\n -q Exit after obtaining lease" +//usage: "\n -R Release IP on exit" +//usage: "\n -S Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P N Use port N (default 546)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a Use arping to validate offered address" +////usage: ) +//usage: "\n -O OPT Request option OPT from server (cumulative)" +//usage: "\n -o Don't request any options (unless -O is given)" +//usage: "\n -r IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: "\nSignals:" +//usage: "\n USR1 Renew lease" +//usage: "\n USR2 Release lease" + + +int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int udhcpc6_main(int argc UNUSED_PARAM, char **argv) +{ + const char *str_r; + IF_FEATURE_UDHCP_PORT(char *str_P;) + void *clientid_mac_ptr; + llist_t *list_O = NULL; + llist_t *list_x = NULL; + int tryagain_timeout = 20; + int discover_timeout = 3; + int discover_retries = 3; + struct in6_addr srv6_buf; + struct in6_addr ipv6_buf; + struct in6_addr *requested_ipv6; + uint32_t xid = 0; + int packet_num; + int timeout; /* must be signed */ + unsigned already_waited_sec; + unsigned opt; + int max_fd; + int retval; + fd_set rfds; + + /* Default options */ + IF_FEATURE_UDHCP_PORT(SERVER_PORT = 547;) + IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 546;) + client_config.interface = "eth0"; + client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; + + /* Parse command line */ + /* O,x: list; -T,-t,-A take numeric param */ + opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; + IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) + opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f" + USE_FOR_MMU("b") + ///IF_FEATURE_UDHCPC_ARPING("a") + IF_FEATURE_UDHCP_PORT("P:") + "v" + , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ + , &client_config.script /* s */ + , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ + , &list_O + , &list_x + IF_FEATURE_UDHCP_PORT(, &str_P) + IF_UDHCP_VERBOSE(, &dhcp_verbose) + ); + requested_ipv6 = NULL; + if (opt & OPT_r) { + if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) + bb_error_msg_and_die("bad IPv6 address '%s'", str_r); + requested_ipv6 = &ipv6_buf; + } +#if ENABLE_FEATURE_UDHCP_PORT + if (opt & OPT_P) { + CLIENT_PORT = xatou16(str_P); + SERVER_PORT = CLIENT_PORT - 1; + } +#endif + if (opt & OPT_o) + client_config.no_default_options = 1; + while (list_O) { + char *optstr = llist_pop(&list_O); + unsigned n = bb_strtou(optstr, NULL, 0); + if (errno || n > 254) { + n = udhcp_option_idx(optstr); + n = dhcp_optflags[n].code; + } + client_config.opt_mask[n >> 3] |= 1 << (n & 7); + } + while (list_x) { + char *optstr = llist_pop(&list_x); + char *colon = strchr(optstr, ':'); + if (colon) + *colon = ' '; + /* now it looks similar to udhcpd's config file line: + * "optname optval", using the common routine: */ + udhcp_str2optset(optstr, &client_config.options); + } + + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + return 1; + } + + /* Create client ID based on mac, set clientid_mac_ptr */ + { + struct d6_option *clientid; + clientid = xzalloc(2+2+2+2+6); + clientid->code = D6_OPT_CLIENTID; + clientid->len = 2+2+6; + clientid->data[1] = 3; /* DUID-LL */ + clientid->data[3] = 1; /* ethernet */ + clientid_mac_ptr = clientid->data + 2+2; + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + client_config.clientid = (void*)clientid; + } + +#if !BB_MMU + /* on NOMMU reexec (i.e., background) early */ + if (!(opt & OPT_f)) { + bb_daemonize_or_rexec(0 /* flags */, argv); + logmode = LOGMODE_NONE; + } +#endif + if (opt & OPT_S) { + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode |= LOGMODE_SYSLOG; + } + + /* Make sure fd 0,1,2 are open */ + bb_sanitize_stdio(); + /* Equivalent of doing a fflush after every \n */ + setlinebuf(stdout); + /* Create pidfile */ + write_pidfile(client_config.pidfile); + /* Goes to stdout (unless NOMMU) and possibly syslog */ + bb_info_msg("%s (v"BB_VER") started", applet_name); + /* Set up the signal pipe */ + udhcp_sp_setup(); + /* We want random_xid to be random... */ + srand(monotonic_us()); + + state = INIT_SELECTING; + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + packet_num = 0; + timeout = 0; + already_waited_sec = 0; + + /* Main event loop. select() waits on signal pipe and possibly + * on sockfd. + * "continue" statements in code below jump to the top of the loop. + */ + for (;;) { + struct timeval tv; + struct d6_packet packet; + uint8_t *packet_end; + /* silence "uninitialized!" warning */ + unsigned timestamp_before_wait = timestamp_before_wait; + + //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); + + /* Was opening raw or udp socket here + * if (listen_mode != LISTEN_NONE && sockfd < 0), + * but on fast network renew responses return faster + * than we open sockets. Thus this code is moved + * to change_listen_mode(). Thus we open listen socket + * BEFORE we send renew request (see "case BOUND:"). */ + + max_fd = udhcp_sp_fd_set(&rfds, sockfd); + + tv.tv_sec = timeout - already_waited_sec; + tv.tv_usec = 0; + retval = 0; + /* If we already timed out, fall through with retval = 0, else... */ + if ((int)tv.tv_sec > 0) { + timestamp_before_wait = (unsigned)monotonic_sec(); + log1("Waiting on select..."); + retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); + if (retval < 0) { + /* EINTR? A signal was caught, don't panic */ + if (errno == EINTR) { + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + continue; + } + /* Else: an error occured, panic! */ + bb_perror_msg_and_die("select"); + } + } + + /* If timeout dropped to zero, time to become active: + * resend discover/renew/whatever + */ + if (retval == 0) { + /* When running on a bridge, the ifindex may have changed + * (e.g. if member interfaces were added/removed + * or if the status of the bridge changed). + * Refresh ifindex and client_mac: + */ + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + goto ret0; /* iface is gone? */ + } + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + + /* We will restart the wait in any case */ + already_waited_sec = 0; + + switch (state) { + case INIT_SELECTING: + if (packet_num < discover_retries) { + if (packet_num == 0) + xid = random_xid(); + /* multicast */ + send_d6_discover(xid, requested_ipv6); + timeout = discover_timeout; + packet_num++; + continue; + } + leasefail: + d6_run_script(NULL, "leasefail"); +#if BB_MMU /* -b is not supported on NOMMU */ + if (opt & OPT_b) { /* background if no lease */ + bb_info_msg("No lease, forking to background"); + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } else +#endif + if (opt & OPT_n) { /* abort if no lease */ + bb_info_msg("No lease, failing"); + retval = 1; + goto ret; + } + /* wait before trying again */ + timeout = tryagain_timeout; + packet_num = 0; + continue; + case REQUESTING: + if (packet_num < discover_retries) { + /* send multicast select packet */ + send_d6_select(xid); + timeout = discover_timeout; + packet_num++; + continue; + } + /* Timed out, go back to init state. + * "discover...select...discover..." loops + * were seen in the wild. Treat them similarly + * to "no response to discover" case */ + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + goto leasefail; + case BOUND: + /* 1/2 lease passed, enter renewing state */ + state = RENEWING; + client_config.first_secs = 0; /* make secs field count from 0 */ + change_listen_mode(LISTEN_KERNEL); + log1("Entering renew state"); + /* fall right through */ + case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ + case_RENEW_REQUESTED: + case RENEWING: + if (timeout > 60) { + /* send an unicast renew request */ + /* Sometimes observed to fail (EADDRNOTAVAIL) to bind + * a new UDP socket for sending inside send_renew. + * I hazard to guess existing listening socket + * is somehow conflicting with it, but why is it + * not deterministic then?! Strange. + * Anyway, it does recover by eventually failing through + * into INIT_SELECTING state. + */ + send_d6_renew(xid, &srv6_buf, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter rebinding state */ + log1("Entering rebinding state"); + state = REBINDING; + /* fall right through */ + case REBINDING: + /* Switch to bcast receive */ + change_listen_mode(LISTEN_RAW); + /* Lease is *really* about to run out, + * try to find DHCP server using broadcast */ + if (timeout > 0) { + /* send a broadcast renew request */ + send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter init state */ + bb_info_msg("Lease lost, entering init state"); + d6_run_script(NULL, "deconfig"); + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + /*timeout = 0; - already is */ + packet_num = 0; + continue; + /* case RELEASED: */ + } + /* yah, I know, *you* say it would never happen */ + timeout = INT_MAX; + continue; /* back to main loop */ + } /* if select timed out */ + + /* select() didn't timeout, something happened */ + + /* Is it a signal? */ + /* note: udhcp_sp_read checks FD_ISSET before reading */ + switch (udhcp_sp_read(&rfds)) { + case SIGUSR1: + client_config.first_secs = 0; /* make secs field count from 0 */ + already_waited_sec = 0; + perform_renew(); + if (state == RENEW_REQUESTED) { + /* We might be either on the same network + * (in which case renew might work), + * or we might be on a completely different one + * (in which case renew won't ever succeed). + * For the second case, must make sure timeout + * is not too big, or else we can send + * futile renew requests for hours. + * (Ab)use -A TIMEOUT value (usually 20 sec) + * as a cap on the timeout. + */ + if (timeout > tryagain_timeout) + timeout = tryagain_timeout; + goto case_RENEW_REQUESTED; + } + /* Start things over */ + packet_num = 0; + /* Kill any timeouts, user wants this to hurry along */ + timeout = 0; + continue; + case SIGUSR2: + perform_d6_release(&srv6_buf, requested_ipv6); + timeout = INT_MAX; + continue; + case SIGTERM: + bb_info_msg("Received SIGTERM"); + goto ret0; + } + + /* Is it a packet? */ + if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) + continue; /* no */ + + { + int len; + + /* A packet is ready, read it */ + if (listen_mode == LISTEN_KERNEL) + len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd); + else + len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd); + if (len == -1) { + /* Error is severe, reopen socket */ + bb_info_msg("Read error: %s, reopening socket", strerror(errno)); + sleep(discover_timeout); /* 3 seconds by default */ + change_listen_mode(listen_mode); /* just close and reopen */ + } + /* If this packet will turn out to be unrelated/bogus, + * we will go back and wait for next one. + * Be sure timeout is properly decreased. */ + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + if (len < 0) + continue; + packet_end = (uint8_t*)&packet + len; + } + + if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) { + log1("xid %x (our is %x), ignoring packet", + (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid); + continue; + } + + switch (state) { + case INIT_SELECTING: + if (packet.d6_msg_type == D6_MSG_ADVERTISE) + goto type_is_ok; + /* DHCPv6 has "Rapid Commit", when instead of Advertise, + * server sends Reply right away. + * Fall through to check for this case. + */ + case REQUESTING: + case RENEWING: + case RENEW_REQUESTED: + case REBINDING: + if (packet.d6_msg_type == D6_MSG_REPLY) { + uint32_t lease_seconds; + struct d6_option *option, *iaaddr; + type_is_ok: + option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); + if (option && option->data[4] != 0) { + /* return to init state */ + bb_info_msg("Received DHCP NAK (%u)", option->data[4]); + d6_run_script(&packet, "nak"); + if (state != REQUESTING) + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + sleep(3); /* avoid excessive network traffic */ + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + requested_ipv6 = NULL; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); + if (!option) { + bb_error_msg("no server ID, ignoring packet"); + continue; + /* still selecting - this server looks bad */ + } +//Note: we do not bother comparing server IDs in Advertise and Reply msgs. +//server_id variable is used solely for creation of proper server_id option +//in outgoing packets. (why DHCPv6 even introduced it is a mystery). + free(client6_data.server_id); + client6_data.server_id = option; + if (packet.d6_msg_type == D6_MSG_ADVERTISE) { + /* enter requesting state */ + state = REQUESTING; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + /* It's a D6_MSG_REPLY */ +/* + * RFC 3315 18.1.8. Receipt of Reply Messages + * + * Upon the receipt of a valid Reply message in response to a Solicit + * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or + * Information-request message, the client extracts the configuration + * information contained in the Reply. The client MAY choose to report + * any status code or message from the status code option in the Reply + * message. + * + * The client SHOULD perform duplicate address detection [17] on each of + * the addresses in any IAs it receives in the Reply message before + * using that address for traffic. If any of the addresses are found to + * be in use on the link, the client sends a Decline message to the + * server as described in section 18.1.7. + * + * If the Reply was received in response to a Solicit (with a Rapid + * Commit option), Request, Renew or Rebind message, the client updates + * the information it has recorded about IAs from the IA options + * contained in the Reply message: + * + * - Record T1 and T2 times. + * + * - Add any new addresses in the IA option to the IA as recorded by + * the client. + * + * - Update lifetimes for any addresses in the IA option that the + * client already has recorded in the IA. + * + * - Discard any addresses from the IA, as recorded by the client, that + * have a valid lifetime of 0 in the IA Address option. + * + * - Leave unchanged any information about addresses the client has + * recorded in the IA but that were not included in the IA from the + * server. + * + * Management of the specific configuration information is detailed in + * the definition of each option in section 22. + * + * If the client receives a Reply message with a Status Code containing + * UnspecFail, the server is indicating that it was unable to process + * the message due to an unspecified failure condition. If the client + * retransmits the original message to the same server to retry the + * desired operation, the client MUST limit the rate at which it + * retransmits the message and limit the duration of the time during + * which it retransmits the message. + * + * When the client receives a Reply message with a Status Code option + * with the value UseMulticast, the client records the receipt of the + * message and sends subsequent messages to the server through the + * interface on which the message was received using multicast. The + * client resends the original message using multicast. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IA_NA | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IAID (4 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * . IA_NA-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . IAaddr-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + free(client6_data.ia_na); + client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); + if (!client6_data.ia_na) { + bb_error_msg("no %s option, ignoring packet", "IA_NA"); + continue; + } + if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { + bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); + continue; + } + iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, + client6_data.ia_na->data + client6_data.ia_na->len, + D6_OPT_IAADDR + ); + if (!iaaddr) { + bb_error_msg("no %s option, ignoring packet", "IAADDR"); + continue; + } + if (iaaddr->len < (16 + 4 + 4)) { + bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); + continue; + } + /* Note: the address is sufficiently aligned for cast: + * we _copied_ IA-NA, and copy is always well-aligned. + */ + requested_ipv6 = (struct in6_addr*) iaaddr->data; + move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); + lease_seconds = ntohl(lease_seconds); + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; +/// TODO: check for 0 lease time? + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; + /* enter bound state */ + timeout = lease_seconds / 2; + bb_info_msg("Lease obtained, lease time %u", + /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); + d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); + + state = BOUND; + change_listen_mode(LISTEN_NONE); + if (opt & OPT_q) { /* quit after lease */ + goto ret0; + } + /* future renew failures should not exit (JM) */ + opt &= ~OPT_n; +#if BB_MMU /* NOMMU case backgrounded earlier */ + if (!(opt & OPT_f)) { + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } +#endif + already_waited_sec = 0; + continue; /* back to main loop */ + } + continue; + /* case BOUND: - ignore all packets */ + /* case RELEASED: - ignore all packets */ + } + /* back to main loop */ + } /* for (;;) - main loop ends */ + + ret0: + if (opt & OPT_R) /* release on quit */ + perform_d6_release(&srv6_buf, requested_ipv6); + retval = 0; + ret: + /*if (client_config.pidfile) - remove_pidfile has its own check */ + remove_pidfile(client_config.pidfile); + return retval; +} diff --git a/release/src/router/busybox/networking/udhcp/d6_packet.c b/release/src/router/busybox/networking/udhcp/d6_packet.c new file mode 100644 index 0000000000..79b2946ef8 --- /dev/null +++ b/release/src/router/busybox/networking/udhcp/d6_packet.c @@ -0,0 +1,172 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include "dhcpd.h" +#include +#include +#include + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +void FAST_FUNC d6_dump_packet(struct d6_packet *packet) +{ + if (dhcp_verbose < 2) + return; + + bb_info_msg( + " xid %x" + , packet->d6_xid32 + ); + //*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; + //bb_info_msg(" chaddr %s", buf); +} +#endif + +int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *packet, int fd) +{ + int bytes; + + memset(packet, 0, sizeof(*packet)); + bytes = safe_read(fd, packet, sizeof(*packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + return bytes; /* returns -1 */ + } + + if (bytes < offsetof(struct d6_packet, d6_options)) { + bb_info_msg("Packet with bad magic, ignoring"); + return -2; + } + log1("Received a packet"); + d6_dump_packet(packet); + + return bytes; +} + +/* Construct a ipv6+udp header for a packet, send packet */ +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex) +{ + struct sockaddr_ll dest_sll; + struct ip6_udp_d6_packet packet; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + + memset(&dest_sll, 0, sizeof(dest_sll)); + memset(&packet, 0, offsetof(struct ip6_udp_d6_packet, data)); + packet.data = *d6_pkt; /* struct copy */ + + dest_sll.sll_family = AF_PACKET; + dest_sll.sll_protocol = htons(ETH_P_IPV6); + dest_sll.sll_ifindex = ifindex; + dest_sll.sll_halen = 6; + memcpy(dest_sll.sll_addr, dest_arp, 6); + + if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { + msg = "bind(%s)"; + goto ret_close; + } + + packet.ip6.ip6_vfc = (6 << 4); /* 4 bits version, top 4 bits of tclass */ + if (src_ipv6) + packet.ip6.ip6_src = *src_ipv6; /* struct copy */ + packet.ip6.ip6_dst = *dst_ipv6; /* struct copy */ + packet.udp.source = htons(source_port); + packet.udp.dest = htons(dest_port); + /* size, excluding IP header: */ + packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size); + packet.ip6.ip6_plen = packet.udp.len; + /* + * Someone was smoking weed (at least) while inventing UDP checksumming: + * UDP checksum skips first four bytes of IPv6 header. + * 'next header' field should be summed as if it is one more byte + * to the right, therefore we write its value (IPPROTO_UDP) + * into ip6_hlim, and its 'real' location remains zero-filled for now. + */ + packet.ip6.ip6_hlim = IPPROTO_UDP; + packet.udp.check = inet_cksum( + (uint16_t *)&packet + 2, + offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size + ); + /* fix 'hop limit' and 'next header' after UDP checksumming */ + packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */ + packet.ip6.ip6_nxt = IPPROTO_UDP; + + d6_dump_packet(d6_pkt); + result = sendto(fd, &packet, offsetof(struct ip6_udp_d6_packet, data) + d6_pkt_size, + /*flags:*/ 0, + (struct sockaddr *) &dest_sll, sizeof(dest_sll) + ); + msg = "sendto"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "PACKET"); + } + return result; +} + +/* Let the kernel do all the work for packet generation */ +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port) +{ + struct sockaddr_in6 sa; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + setsockopt_reuseaddr(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(source_port); + sa.sin6_addr = *src_ipv6; /* struct copy */ + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "bind(%s)"; + goto ret_close; + } + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(dest_port); + sa.sin6_addr = *dst_ipv6; /* struct copy */ + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "connect"; + goto ret_close; + } + + d6_dump_packet(d6_pkt); + result = safe_write(fd, d6_pkt, d6_pkt_size); + msg = "write"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "UDP"); + } + return result; +} diff --git a/release/src/router/busybox/networking/udhcp/d6_socket.c b/release/src/router/busybox/networking/udhcp/d6_socket.c new file mode 100644 index 0000000000..56f69f6a1b --- /dev/null +++ b/release/src/router/busybox/networking/udhcp/d6_socket.c @@ -0,0 +1,34 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include + +int FAST_FUNC d6_listen_socket(int port, const char *inf) +{ + int fd; + struct sockaddr_in6 addr; + + log1("Opening listen socket on *:%d %s", port, inf); + fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + setsockopt_reuseaddr(fd); + if (setsockopt_broadcast(fd) == -1) + bb_perror_msg_and_die("SO_BROADCAST"); + + /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ + if (setsockopt_bindtodevice(fd, inf)) + xfunc_die(); /* warning is already printed */ + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + /* addr.sin6_addr is all-zeros */ + xbind(fd, (struct sockaddr *)&addr, sizeof(addr)); + + return fd; +} diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.c b/release/src/router/busybox/networking/udhcp/dhcpc.c index 7009ae101b..d7b7862e78 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpc.c +++ b/release/src/router/busybox/networking/udhcp/dhcpc.c @@ -133,25 +133,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); } -#if ENABLE_FEATURE_UDHCP_RFC5969 -static int sprint_nip6(char *dest, const char *pre, const uint8_t *ip) -{ - int len = 0; - int off; - uint16_t word; - - len += sprintf(dest, "%s", pre); - - for (off = 0; off < 16; off += 2) - { - move_from_unaligned16(word, &ip[off]); - len += sprintf(dest+len, "%s%04X", off ? ":" : "", htons(word)); - } - - return len; -} -#endif - /* really simple implementation, just count the bits */ static int mton(uint32_t mask) { @@ -341,7 +322,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ len--; /* 6rdPrefix */ - dest += sprint_nip6(dest, "", option); + dest += sprint_nip6(dest, /* "", */ option); option += 16; len -= 16; @@ -801,7 +782,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) /* verify IP checksum */ check = packet.ip.check; packet.ip.check = 0; - if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { + if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { log1("Bad IP header checksum, ignoring"); return -2; } @@ -812,7 +793,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ check = packet.udp.check; packet.udp.check = 0; - if (check && check != udhcp_checksum(&packet, bytes)) { + if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { log1("Packet with bad UDP checksum received, ignoring"); return -2; } diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.c b/release/src/router/busybox/networking/udhcp/dhcpc.c.20 similarity index 82% copy from release/src/router/busybox/networking/udhcp/dhcpc.c copy to release/src/router/busybox/networking/udhcp/dhcpc.c.20 index 7009ae101b..4d93fe02e9 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpc.c +++ b/release/src/router/busybox/networking/udhcp/dhcpc.c.20 @@ -35,8 +35,7 @@ #endif #include -/* struct client_config_t client_config is in bb_common_bufsiz1 */ - +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ #if ENABLE_LONG_OPTS static const char udhcpc_longopts[] ALIGN1 = @@ -111,6 +110,7 @@ static const uint8_t len_of_option_as_string[] = { [OPTION_6RD ] = sizeof("32 128 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 255.255.255.255 "), #endif [OPTION_STRING ] = 1, + [OPTION_STRING_HOST ] = 1, #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING ] = 1, /* unused */ /* Hmmm, this severely overestimates size if SIP_SERVERS option @@ -133,25 +133,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); } -#if ENABLE_FEATURE_UDHCP_RFC5969 -static int sprint_nip6(char *dest, const char *pre, const uint8_t *ip) -{ - int len = 0; - int off; - uint16_t word; - - len += sprintf(dest, "%s", pre); - - for (off = 0; off < 16; off += 2) - { - move_from_unaligned16(word, &ip[off]); - len += sprintf(dest+len, "%s%04X", off ? ":" : "", htons(word)); - } - - return len; -} -#endif - /* really simple implementation, just count the bits */ static int mton(uint32_t mask) { @@ -164,6 +145,63 @@ static int mton(uint32_t mask) return i; } +/* Check if a given label represents a valid DNS label + * Return pointer to the first character after the label upon success, + * NULL otherwise. + * See RFC1035, 2.3.1 + */ +/* We don't need to be particularly anal. For example, allowing _, hyphen + * at the end, or leading and trailing dots would be ok, since it + * can't be used for attacks. (Leading hyphen can be, if someone uses + * cmd "$hostname" + * in the script: then hostname may be treated as an option) + */ +static const char *valid_domain_label(const char *label) +{ + unsigned char ch; + unsigned pos = 0; + + for (;;) { + ch = *label; + if ((ch|0x20) < 'a' || (ch|0x20) > 'z') { + if (pos == 0) { + /* label must begin with letter */ + return NULL; + } + if (ch < '0' || ch > '9') { + if (ch == '\0' || ch == '.') + return label; + /* DNS allows only '-', but we are more permissive */ + if (ch != '-' && ch != '_') + return NULL; + } + } + label++; + pos++; + //Do we want this? + //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */ + // return NULL; + } +} + +/* Check if a given name represents a valid DNS name */ +/* See RFC1035, 2.3.1 */ +static int good_hostname(const char *name) +{ + //const char *start = name; + + for (;;) { + name = valid_domain_label(name); + if (!name) + return 0; + if (!name[0]) + return 1; + //Do we want this? + //return ((name - start) < 1025); /* NS_MAXDNAME */ + name++; + } +} + /* Create "opt_name=opt_value" string */ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) { @@ -171,27 +209,25 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ int len, type, optlen; char *dest, *ret; - /* option points to OPT_DATA, need to go back and get OPT_LEN */ - len = option[OPT_LEN - OPT_DATA]; + /* option points to OPT_DATA, need to go back to get OPT_LEN */ + len = option[-OPT_DATA + OPT_LEN]; type = optflag->flags & OPTION_TYPE_MASK; optlen = dhcp_option_lengths[type]; - upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); + upper_length = len_of_option_as_string[type] + * ((unsigned)(len + optlen - 1) / (unsigned)optlen); dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); dest += sprintf(ret, "%s=", opt_name); while (len >= optlen) { - unsigned ip_ofs = 0; - switch (type) { + case OPTION_IP: case OPTION_IP_PAIR: dest += sprint_nip(dest, "", option); - *dest++ = '/'; - ip_ofs = 4; - /* fall through */ - case OPTION_IP: - dest += sprint_nip(dest, "", option + ip_ofs); + if (type == OPTION_IP) + break; + dest += sprint_nip(dest, "/", option + 4); break; // case OPTION_BOOLEAN: // dest += sprintf(dest, *option ? "yes" : "no"); @@ -213,10 +249,17 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); break; } + /* Note: options which use 'return' instead of 'break' + * (for example, OPTION_STRING) skip the code which handles + * the case of list of options. + */ case OPTION_STRING: + case OPTION_STRING_HOST: memcpy(dest, option, len); dest[len] = '\0'; - return ret; /* Short circuit this case */ + if (type == OPTION_STRING_HOST && !good_hostname(dest)) + safe_strncpy(dest, "bad", len); + return ret; case OPTION_STATIC_ROUTES: { /* Option binary format: * mask [one byte, 0..32] @@ -261,6 +304,53 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ return ret; } + case OPTION_6RD: + /* Option binary format (see RFC 5969): + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 6rdPrefix | + * ... (16 octets) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ... 6rdBRIPv4Address(es) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * We convert it to a string + * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..." + * + * Sanity check: ensure that our length is at least 22 bytes, that + * IPv4MaskLen <= 32, + * 6rdPrefixLen <= 128, + * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 + * (2nd condition need no check - it follows from 1st and 3rd). + * Else, return envvar with empty value ("optname=") + */ + if (len >= (1 + 1 + 16 + 4) + && option[0] <= 32 + && (option[1] + 32 - option[0]) <= 128 + ) { + /* IPv4MaskLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefixLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefix */ + dest += sprint_nip6(dest, /* "", */ option); + option += 16; + len -= 1 + 1 + 16 + 4; + /* "+ 4" above corresponds to the length of IPv4 addr + * we consume in the loop below */ + while (1) { + /* 6rdBRIPv4Address(es) */ + dest += sprint_nip(dest, " ", option); + option += 4; + len -= 4; /* do we have yet another 4+ bytes? */ + if (len < 0) + break; /* no */ + } + } + + return ret; #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: /* unpack option into dest; use ret for prefix (i.e., "optname=") */ @@ -299,82 +389,22 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ } return ret; #endif -#if ENABLE_FEATURE_UDHCP_RFC5969 - case OPTION_6RD: - /* Option binary format: - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * | 6rdPrefix | - * | (16 octets) | - * | | - * | | - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | 6rdBRIPv4Address(es) | - * . . - * . . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * We convert it to a string "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address" - */ - - /* Sanity check: ensure that our length is at least 22 bytes, that - * IPv4MaskLen is <= 32, 6rdPrefixLen <= 128 and that the sum of - * (32 - IPv4MaskLen) + 6rdPrefixLen is less than or equal to 128. - * If any of these requirements is not fulfilled, return with empty - * value. - */ - if ((len >= 22) && (*option <= 32) && (*(option+1) <= 128) && - (((32 - *option) + *(option+1)) <= 128)) - { - /* IPv4MaskLen */ - dest += sprintf(dest, "%u ", *option++); - len--; - - /* 6rdPrefixLen */ - dest += sprintf(dest, "%u ", *option++); - len--; - - /* 6rdPrefix */ - dest += sprint_nip6(dest, "", option); - option += 16; - len -= 16; - - /* 6rdBRIPv4Addresses */ - while (len >= 4) - { - dest += sprint_nip(dest, " ", option); - option += 4; - len -= 4; - - /* the code to determine the option size fails to work with - * lengths that are not a multiple of the minimum length, - * adding all advertised 6rdBRIPv4Addresses here would - * overflow the destination buffer, therefore skip the rest - * for now - */ - break; - } - } - - return ret; -#endif } /* switch */ + + /* If we are here, try to format any remaining data + * in the option as another, similarly-formatted option + */ option += optlen; len -= optlen; // TODO: it can be a list only if (optflag->flags & OPTION_LIST). // Should we bail out/warn if we see multi-ip option which is // not allowed to be such (for example, DHCP_BROADCAST)? - - if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */) + if (len < optlen /* || !(optflag->flags & OPTION_LIST) */) break; *dest++ = ' '; *dest = '\0'; - } + } /* while */ + return ret; } @@ -388,6 +418,14 @@ static char **fill_envp(struct dhcp_packet *packet) uint8_t *temp; uint8_t overload = 0; +#define BITMAP unsigned +#define BBITS (sizeof(BITMAP) * 8) +#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1))) +#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS]) + BITMAP found_opts[256 / BBITS]; + + memset(found_opts, 0, sizeof(found_opts)); + /* We need 6 elements for: * "interface=IFACE" * "ip=N.N.N.N" from packet->yiaddr @@ -399,18 +437,22 @@ static char **fill_envp(struct dhcp_packet *packet) envc = 6; /* +1 element for each option, +2 for subnet option: */ if (packet) { - for (i = 0; dhcp_optflags[i].code; i++) { - if (udhcp_get_option(packet, dhcp_optflags[i].code)) { - if (dhcp_optflags[i].code == DHCP_SUBNET) - envc++; /* for mton */ + /* note: do not search for "pad" (0) and "end" (255) options */ +//TODO: change logic to scan packet _once_ + for (i = 1; i < 255; i++) { + temp = udhcp_get_option(packet, i); + if (temp) { + if (i == DHCP_OPTION_OVERLOAD) + overload = *temp; + else if (i == DHCP_SUBNET) + envc++; /* for $mask */ envc++; + /*if (i != DHCP_MESSAGE_TYPE)*/ + FOUND_OPTS(i) |= BMASK(i); } } - temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); - if (temp) - overload = *temp; } - curr = envp = xzalloc(sizeof(char *) * envc); + curr = envp = xzalloc(sizeof(envp[0]) * envc); *curr = xasprintf("interface=%s", client_config.interface); putenv(*curr++); @@ -418,44 +460,88 @@ static char **fill_envp(struct dhcp_packet *packet) if (!packet) return envp; + /* Export BOOTP fields. Fields we don't (yet?) export: + * uint8_t op; // always BOOTREPLY + * uint8_t htype; // hardware address type. 1 = 10mb ethernet + * uint8_t hlen; // hardware address length + * uint8_t hops; // used by relay agents only + * uint32_t xid; + * uint16_t secs; // elapsed since client began acquisition/renewal + * uint16_t flags; // only one flag so far: bcast. Never set by server + * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different + * // if during renew server wants to give us differn IP?) + * uint32_t gateway_nip; // relay agent IP address + * uint8_t chaddr[16]; // link-layer client hardware address (MAC) + * TODO: export gateway_nip as $giaddr? + */ + /* Most important one: yiaddr as $ip */ *curr = xmalloc(sizeof("ip=255.255.255.255")); sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); putenv(*curr++); + if (packet->siaddr_nip) { + /* IP address of next server to use in bootstrap */ + *curr = xmalloc(sizeof("siaddr=255.255.255.255")); + sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); + putenv(*curr++); + } + if (!(overload & FILE_FIELD) && packet->file[0]) { + /* watch out for invalid packets */ + *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); + putenv(*curr++); + } + if (!(overload & SNAME_FIELD) && packet->sname[0]) { + /* watch out for invalid packets */ + *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); + putenv(*curr++); + } + /* Export known DHCP options */ opt_name = dhcp_option_strings; i = 0; while (*opt_name) { - temp = udhcp_get_option(packet, dhcp_optflags[i].code); - if (!temp) + uint8_t code = dhcp_optflags[i].code; + BITMAP *found_ptr = &FOUND_OPTS(code); + BITMAP found_mask = BMASK(code); + if (!(*found_ptr & found_mask)) goto next; + *found_ptr &= ~found_mask; /* leave only unknown options */ + temp = udhcp_get_option(packet, code); *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); putenv(*curr++); - if (dhcp_optflags[i].code == DHCP_SUBNET) { + if (code == DHCP_SUBNET) { /* Subnet option: make things like "$ip/$mask" possible */ uint32_t subnet; move_from_unaligned32(subnet, temp); - *curr = xasprintf("mask=%d", mton(subnet)); + *curr = xasprintf("mask=%u", mton(subnet)); putenv(*curr++); } next: opt_name += strlen(opt_name) + 1; i++; } - if (packet->siaddr_nip) { - *curr = xmalloc(sizeof("siaddr=255.255.255.255")); - sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); - putenv(*curr++); - } - if (!(overload & FILE_FIELD) && packet->file[0]) { - /* watch out for invalid packets */ - *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); - putenv(*curr++); - } - if (!(overload & SNAME_FIELD) && packet->sname[0]) { - /* watch out for invalid packets */ - *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); - putenv(*curr++); + /* Export unknown options */ + for (i = 0; i < 256;) { + BITMAP bitmap = FOUND_OPTS(i); + if (!bitmap) { + i += BBITS; + continue; + } + if (bitmap & BMASK(i)) { + unsigned len, ofs; + + temp = udhcp_get_option(packet, i); + /* udhcp_get_option returns ptr to data portion, + * need to go back to get len + */ + len = temp[-OPT_DATA + OPT_LEN]; + *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); + ofs = sprintf(*curr, "opt%u=", i); + *bin2hex(*curr + ofs, (void*) temp, len) = '\0'; + putenv(*curr++); + } + i++; } + return envp; } @@ -465,9 +551,6 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) char **envp, **curr; char *argv[3]; - if (client_config.script == NULL) - return; - envp = fill_envp(packet); /* call script */ @@ -555,6 +638,10 @@ static void add_client_options(struct dhcp_packet *packet) if ((option_mask32 & OPT_B) && packet->ciaddr == 0) packet->flags |= htons(BROADCAST_FLAG); + /* Request broadcast replies if we have no IP addr */ + if ((option_mask32 & OPT_B) && packet->ciaddr == 0) + packet->flags |= htons(BROADCAST_FLAG); + /* Add -x options if any */ { struct option_set *curr = client_config.options; @@ -567,6 +654,12 @@ static void add_client_options(struct dhcp_packet *packet) // if (client_config.boot_file) // strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); } + + // This will be needed if we remove -V VENDOR_STR in favor of + // -x vendor:VENDOR_STR + //if (!udhcp_find_option(packet.options, DHCP_VENDOR)) + // /* not set, set the default vendor ID */ + // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... } /* RFC 2131 @@ -713,7 +806,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) #if ENABLE_FEATURE_UDHCPC_ARPING /* Broadcast a DHCP decline message */ /* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) +static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) { struct dhcp_packet packet; @@ -722,12 +815,14 @@ static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t request */ init_packet(&packet, DHCPDECLINE); +#if 0 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, * but in case the server is buggy and wants DHCPDECLINE's xid * to match the xid which started entire handshake, * we use the same xid we used in initial DHCPDISCOVER: */ packet.xid = xid; +#endif /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); @@ -765,7 +860,6 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) struct ip_udp_dhcp_packet packet; uint16_t check; - memset(&packet, 0, sizeof(packet)); bytes = safe_read(fd, &packet, sizeof(packet)); if (bytes < 0) { log1("Packet read error, ignoring"); @@ -788,7 +882,8 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) bytes = ntohs(packet.ip.tot_len); /* make sure its the right packet for us, and that it passes sanity checks */ - if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION + if (packet.ip.protocol != IPPROTO_UDP + || packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2) || packet.udp.dest != htons(CLIENT_PORT) /* || bytes > (int) sizeof(packet) - can't happen */ @@ -801,7 +896,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) /* verify IP checksum */ check = packet.ip.check; packet.ip.check = 0; - if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { + if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { log1("Bad IP header checksum, ignoring"); return -2; } @@ -812,20 +907,22 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ check = packet.udp.check; packet.udp.check = 0; - if (check && check != udhcp_checksum(&packet, bytes)) { + if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { log1("Packet with bad UDP checksum received, ignoring"); return -2; } - memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); - - if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { + if (packet.data.cookie != htonl(DHCP_MAGIC)) { bb_info_msg("Packet with bad magic, ignoring"); return -2; } - log1("Got valid DHCP packet"); - udhcp_dump_packet(dhcp_pkt); - return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); + + log1("Received a packet"); + udhcp_dump_packet(&packet.data); + + bytes -= sizeof(packet.ip) + sizeof(packet.udp); + memcpy(dhcp_pkt, &packet.data, bytes); + return bytes; } @@ -971,7 +1068,7 @@ static void perform_renew(void) } } -static void perform_release(uint32_t requested_ip, uint32_t server_addr) +static void perform_release(uint32_t server_addr, uint32_t requested_ip) { char buffer[sizeof("255.255.255.255")]; struct in_addr temp_addr; @@ -1020,7 +1117,7 @@ static void client_background(void) //usage:#endif //usage:#define udhcpc_trivial_usage //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" -//usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") +//usage: " [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") //usage:#define udhcpc_full_usage "\n" //usage: IF_LONG_OPTS( //usage: "\n -i,--interface IFACE Interface to use (default eth0)" @@ -1053,7 +1150,6 @@ static void client_background(void) //usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" //usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" -//usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" //usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" //usage: "\n -C,--clientid-none Don't send MAC as client identifier" //usage: IF_UDHCP_VERBOSE( @@ -1117,16 +1213,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) int discover_retries = 5; uint32_t server_addr = server_addr; /* for compiler */ uint32_t requested_ip = 0; - uint32_t xid = 0; - uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */ + uint32_t xid = xid; /* for compiler */ int packet_num; int timeout; /* must be signed */ unsigned already_waited_sec; unsigned opt; int max_fd; int retval; - struct timeval tv; - struct dhcp_packet packet; fd_set rfds; /* Default options */ @@ -1138,11 +1231,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* Parse command line */ /* O,x: list; -T,-t,-A take numeric param */ - opt_complementary = "O::x::T+:t+:A+" -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - ":vv" -#endif - ; + opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; + IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" "m" // zzz @@ -1157,12 +1247,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) , &list_O , &list_x IF_FEATURE_UDHCP_PORT(, &str_P) -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose -#endif - ); - if (opt & (OPT_h|OPT_H)) + IF_UDHCP_VERBOSE(, &dhcp_verbose) + ); + if (opt & (OPT_h|OPT_H)) { + //msg added 2011-11 + bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); + } if (opt & OPT_F) { /* FQDN option format: [0x51][len][flags][0][0] */ client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); @@ -1190,8 +1281,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) client_config.no_default_options = 1; while (list_O) { char *optstr = llist_pop(&list_O); - unsigned n = udhcp_option_idx(optstr); - n = dhcp_optflags[n].code; + unsigned n = bb_strtou(optstr, NULL, 0); + if (errno || n > 254) { + n = udhcp_option_idx(optstr); + n = dhcp_optflags[n].code; + } client_config.opt_mask[n >> 3] |= 1 << (n & 7); } while (list_x) { @@ -1224,8 +1318,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) clientid_mac_ptr = client_config.clientid + OPT_DATA+1; memcpy(clientid_mac_ptr, client_config.client_mac, 6); } - if (str_V[0] != '\0') + if (str_V[0] != '\0') { + // can drop -V, str_V, client_config.vendorclass, + // but need to add "vendor" to the list of recognized + // string opts for this to work; + // and need to tweak add_client_options() too... + // ...so the question is, should we? + //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); + } + #if !BB_MMU /* on NOMMU reexec (i.e., background) early */ if (!(opt & OPT_f)) { @@ -1263,6 +1365,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * "continue" statements in code below jump to the top of the loop. */ for (;;) { + struct timeval tv; + struct dhcp_packet packet; /* silence "uninitialized!" warning */ unsigned timestamp_before_wait = timestamp_before_wait; @@ -1311,7 +1415,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) client_config.client_mac, &client_config.client_mtu) ) { - return 1; /* iface is gone? */ + goto ret0; /* iface is gone? */ } if (clientid_mac_ptr) memcpy(clientid_mac_ptr, client_config.client_mac, 6); @@ -1425,8 +1529,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read(&rfds)) { case SIGUSR1: client_config.first_secs = 0; /* make secs field count from 0 */ + already_waited_sec = 0; perform_renew(); if (state == RENEW_REQUESTED) + if (timeout > tryagain_timeout) + timeout = tryagain_timeout; goto case_RENEW_REQUESTED; /* Start things over */ packet_num = 0; @@ -1434,13 +1541,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) timeout = 0; continue; case SIGUSR2: - perform_release(requested_ip, server_addr); + perform_release(server_addr, requested_ip); timeout = INT_MAX; continue; case SIGTERM: bb_info_msg("Received SIGTERM"); - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } @@ -1493,9 +1598,27 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (state) { case INIT_SELECTING: - /* Must be a DHCPOFFER to one of our xid's */ + /* Must be a DHCPOFFER */ if (*message == DHCPOFFER) { - /* TODO: why we don't just fetch server's IP from IP header? */ +/* What exactly is server's IP? There are several values. + * Example DHCP offer captured with tchdump: + * + * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src + * BOOTP fields: + * Your-IP 10.34.25.202 + * Server-IP 10.34.32.125 // "next server" IP + * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use) + * DHCP options: + * DHCP-Message Option 53, length 1: Offer + * Server-ID Option 54, length 4: 10.34.255.7 // "server ID" + * Default-Gateway Option 3, length 4: 10.34.25.254 // router + * + * We think that real server IP (one to use in renew/release) + * is one in Server-ID option. But I am not 100% sure. + * IP header's src and Gateway-IP (same in this example) + * might work too. + * "Next server" and router are definitely wrong ones to use, though... + */ temp = udhcp_get_option(&packet, DHCP_SERVER_ID); if (!temp) { bb_error_msg("no server ID, ignoring packet"); @@ -1519,6 +1642,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: case REBINDING: if (*message == DHCPACK) { + uint32_t lease_seconds; + struct in_addr temp_addr; + temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); if (!temp) { bb_error_msg("no lease time with ACK, using 1 hour lease"); @@ -1527,9 +1653,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* it IS unaligned sometimes, don't "optimize" */ move_from_unaligned32(lease_seconds, temp); lease_seconds = ntohl(lease_seconds); - lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ - if (lease_seconds < 10) /* and not too small */ - lease_seconds = 10; + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; } #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { @@ -1550,7 +1678,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) ) { bb_info_msg("Offered address is in use " "(got ARP reply), declining"); - send_decline(xid, server_addr, packet.yiaddr); + send_decline(/*xid,*/ server_addr, packet.yiaddr); if (state != REQUESTING) udhcp_run_script(NULL, "deconfig"); @@ -1567,20 +1695,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) #endif /* enter bound state */ timeout = lease_seconds / 2; - { - struct in_addr temp_addr; - temp_addr.s_addr = packet.yiaddr; - bb_info_msg("Lease of %s obtained, lease time %u", - inet_ntoa(temp_addr), (unsigned)lease_seconds); - } + temp_addr.s_addr = packet.yiaddr; + bb_info_msg("Lease of %s obtained, lease time %u", + inet_ntoa(temp_addr), (unsigned)lease_seconds); requested_ip = packet.yiaddr; udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); state = BOUND; change_listen_mode(LISTEN_NONE); if (opt & OPT_q) { /* quit after lease */ - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } /* future renew failures should not exit (JM) */ @@ -1592,6 +1715,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) opt = ((opt & ~OPT_b) | OPT_f); } #endif + /* make future renew packets use different xid */ + /* xid = random_xid(); ...but why bother? */ already_waited_sec = 0; continue; /* back to main loop */ } @@ -1618,6 +1743,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } /* for (;;) - main loop ends */ ret0: + if (opt & OPT_R) /* release on quit */ + perform_release(server_addr, requested_ip); retval = 0; ret: /*if (client_config.pidfile) - remove_pidfile has its own check */ diff --git a/release/src/router/busybox/networking/udhcp/dhcpd.c b/release/src/router/busybox/networking/udhcp/dhcpd.c index f5a600dcc8..d85c11490c 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpd.c +++ b/release/src/router/busybox/networking/udhcp/dhcpd.c @@ -20,6 +20,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +//usage:#define udhcpd_trivial_usage +//usage: "[-fS]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" +//usage:#define udhcpd_full_usage "\n\n" +//usage: "DHCP server\n" +//usage: "\n -f Run in foreground" +//usage: "\n -S Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P N Use port N (default 67)" +//usage: ) + #include #include "common.h" #include "dhcpc.h" @@ -133,7 +144,10 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) /* We got a DHCP DISCOVER. Send an OFFER. */ /* NOINLINE: limit stack usage in caller */ -static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) +static NOINLINE void send_offer(struct dhcp_packet *oldpacket, + uint32_t static_lease_nip, + struct dyn_lease *lease, + uint8_t *requested_ip_opt) { struct dhcp_packet packet; uint32_t lease_time_sec; @@ -147,7 +161,6 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l if (!static_lease_nip) { /* We have no static lease for client's chaddr */ uint32_t req_nip; - uint8_t *req_ip_opt; const char *p_host_name; if (lease) { @@ -158,9 +171,9 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l packet.yiaddr = lease->lease_nip; } /* Or: if client has requested an IP */ - else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL + else if (requested_ip_opt != NULL /* (read IP) */ - && (move_from_unaligned32(req_nip, req_ip_opt), 1) + && (move_from_unaligned32(req_nip, requested_ip_opt), 1) /* and the IP is in the lease range */ && ntohl(req_nip) >= server_config.start_ip && ntohl(req_nip) <= server_config.end_ip @@ -283,16 +296,12 @@ struct dyn_lease *g_leases; int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpd_main(int argc UNUSED_PARAM, char **argv) { - fd_set rfds; int server_socket = -1, retval, max_sock; - struct dhcp_packet packet; uint8_t *state; - uint32_t static_lease_nip; unsigned timeout_end; unsigned num_ips; unsigned opt; struct option_set *option; - struct dyn_lease *lease, fake_lease; IF_FEATURE_UDHCP_PORT(char *str_P;) #if ENABLE_FEATURE_UDHCP_PORT @@ -305,9 +314,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "fSv" IF_FEATURE_UDHCP_PORT("P:", &str_P) -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose -#endif + IF_UDHCP_VERBOSE(, &dhcp_verbose) ); if (!(opt & 1)) { /* no -f */ bb_daemonize_or_rexec(0, argv); @@ -373,11 +380,15 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) timeout_end = monotonic_sec() + server_config.auto_time; while (1) { /* loop until universe collapses */ + fd_set rfds; + struct dhcp_packet packet; int bytes; struct timeval tv; uint8_t *server_id_opt; - uint8_t *requested_opt; + uint8_t *requested_ip_opt; uint32_t requested_nip = requested_nip; /* for compiler */ + uint32_t static_lease_nip; + struct dyn_lease *lease, fake_lease; if (server_socket < 0) { server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, @@ -444,6 +455,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) continue; } + /* Get SERVER_ID if present */ + server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); + if (server_id_opt) { + uint32_t server_id_network_order; + move_from_unaligned32(server_id_network_order, server_id_opt); + if (server_id_network_order != server_config.server_nip) { + /* client talks to somebody else */ + log1("server ID doesn't match, ignoring"); + continue; + } + } + /* Look for a static/dynamic lease */ static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); if (static_lease_nip) { @@ -456,20 +479,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) lease = find_lease_by_mac(packet.chaddr); } - /* Get REQUESTED_IP and SERVER_ID if present */ - server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); - if (server_id_opt) { - uint32_t server_id_net; - move_from_unaligned32(server_id_net, server_id_opt); - if (server_id_net != server_config.server_nip) { - /* client talks to somebody else */ - log1("server ID doesn't match, ignoring"); - continue; - } - } - requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); - if (requested_opt) { - move_from_unaligned32(requested_nip, requested_opt); + /* Get REQUESTED_IP if present */ + requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); + if (requested_ip_opt) { + move_from_unaligned32(requested_nip, requested_ip_opt); } switch (state[0]) { @@ -477,7 +490,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) case DHCPDISCOVER: log1("Received DISCOVER"); - send_offer(&packet, static_lease_nip, lease); + send_offer(&packet, static_lease_nip, lease, requested_ip_opt); break; case DHCPREQUEST: @@ -568,7 +581,7 @@ o DHCPREQUEST generated during REBINDING state: A DHCP server MAY extend a client's lease only if it has local administrative authority to do so. */ - if (!requested_opt) { + if (!requested_ip_opt) { requested_nip = packet.ciaddr; if (requested_nip == 0) { log1("no requested IP and no ciaddr, ignoring"); @@ -581,11 +594,15 @@ o DHCPREQUEST generated during REBINDING state: send_ACK(&packet, lease->lease_nip); break; } - if (server_id_opt) { - /* client was talking specifically to us. - * "No, we don't have this IP for you". */ + /* No lease for this MAC, or lease IP != requested IP */ + + if (server_id_opt /* client is in SELECTING state */ + || requested_ip_opt /* client is in INIT-REBOOT state */ + ) { + /* "No, we don't have this IP for you" */ send_NAK(&packet); - } + } /* else: client is in RENEWING or REBINDING, do not answer */ + break; case DHCPDECLINE: @@ -604,7 +621,7 @@ o DHCPREQUEST generated during REBINDING state: */ log1("Received DECLINE"); if (server_id_opt - && requested_opt + && requested_ip_opt && lease /* chaddr matches this lease */ && requested_nip == lease->lease_nip ) { diff --git a/release/src/router/busybox/networking/udhcp/dhcprelay.c b/release/src/router/busybox/networking/udhcp/dhcprelay.c index 4240e926f9..a17a2bf4be 100644 --- a/release/src/router/busybox/networking/udhcp/dhcprelay.c +++ b/release/src/router/busybox/networking/udhcp/dhcprelay.c @@ -9,6 +9,12 @@ * Netbeat AG * Upstream has GPL v2 or later */ + +//usage:#define dhcprelay_trivial_usage +//usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" +//usage:#define dhcprelay_full_usage "\n\n" +//usage: "Relay DHCP requests between clients and server" + #include "common.h" #define SERVER_PORT 67 @@ -25,7 +31,7 @@ struct xid_item { uint32_t xid; struct sockaddr_in ip; struct xid_item *next; -}; +} FIX_ALIASING; #define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1) diff --git a/release/src/router/busybox/networking/udhcp/dumpleases.c b/release/src/router/busybox/networking/udhcp/dumpleases.c index 21d62a2d29..64cd73ec77 100644 --- a/release/src/router/busybox/networking/udhcp/dumpleases.c +++ b/release/src/router/busybox/networking/udhcp/dumpleases.c @@ -2,6 +2,22 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define dumpleases_trivial_usage +//usage: "[-r|-a] [-f LEASEFILE]" +//usage:#define dumpleases_full_usage "\n\n" +//usage: "Display DHCP leases granted by udhcpd\n" +//usage: IF_LONG_OPTS( +//usage: "\n -f,--file=FILE Lease file" +//usage: "\n -r,--remaining Show remaining time" +//usage: "\n -a,--absolute Show expiration time" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -f FILE Lease file" +//usage: "\n -r Show remaining time" +//usage: "\n -a Show expiration time" +//usage: ) + #include "common.h" #include "dhcpd.h" #include "unicode.h" diff --git a/release/src/router/busybox/networking/udhcp/files.c b/release/src/router/busybox/networking/udhcp/files.c index 49bcafb9c2..6840f3c259 100644 --- a/release/src/router/busybox/networking/udhcp/files.c +++ b/release/src/router/busybox/networking/udhcp/files.c @@ -80,9 +80,9 @@ static const struct config_keyword keywords[] = { /* keywords with no defaults must be last! */ {"option" , udhcp_str2optset, &server_config.options , ""}, {"opt" , udhcp_str2optset, &server_config.options , ""}, - {"notify_file" , read_str , &server_config.notify_file , ""}, - {"sname" , read_str , &server_config.sname , ""}, - {"boot_file" , read_str , &server_config.boot_file , ""}, + {"notify_file" , read_str , &server_config.notify_file , NULL}, + {"sname" , read_str , &server_config.sname , NULL}, + {"boot_file" , read_str , &server_config.boot_file , NULL}, {"static_lease" , read_staticlease, &server_config.static_leases, ""}, }; enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; diff --git a/release/src/router/busybox/networking/udhcp/leases.c b/release/src/router/busybox/networking/udhcp/leases.c index 7aeb37baec..c5b60b1083 100644 --- a/release/src/router/busybox/networking/udhcp/leases.c +++ b/release/src/router/busybox/networking/udhcp/leases.c @@ -137,21 +137,42 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) uint32_t addr; struct dyn_lease *oldest_lease = NULL; - addr = server_config.start_ip; /* addr is in host order here */ - for (; addr <= server_config.end_ip; addr++) { +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + uint32_t stop; + unsigned i, hash; + + /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good + * dispersal even with similarly-valued "strings". + */ + hash = 0; + for (i = 0; i < 6; i++) + hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; + + /* pick a seed based on hwaddr then iterate until we find a free address. */ + addr = server_config.start_ip + + (hash % (1 + server_config.end_ip - server_config.start_ip)); + stop = addr; +#else + addr = server_config.start_ip; +#define stop (server_config.end_ip + 1) +#endif + do { uint32_t nip; struct dyn_lease *lease; /* ie, 192.168.55.0 */ if ((addr & 0xff) == 0) - continue; + goto next_addr; /* ie, 192.168.55.255 */ if ((addr & 0xff) == 0xff) - continue; + goto next_addr; nip = htonl(addr); + /* skip our own address */ + if (nip == server_config.server_nip) + goto next_addr; /* is this a static lease addr? */ if (is_nip_reserved(server_config.static_leases, nip)) - continue; + goto next_addr; lease = find_lease_by_nip(nip); if (!lease) { @@ -162,7 +183,14 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) if (!oldest_lease || lease->expires < oldest_lease->expires) oldest_lease = lease; } - } + + next_addr: + addr++; +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + if (addr > server_config.end_ip) + addr = server_config.start_ip; +#endif + } while (addr != stop); if (oldest_lease && is_expired_lease(oldest_lease) diff --git a/release/src/router/busybox/networking/udhcp/packet.c b/release/src/router/busybox/networking/udhcp/packet.c index 8932e405f1..ab2482af97 100644 --- a/release/src/router/busybox/networking/udhcp/packet.c +++ b/release/src/router/busybox/networking/udhcp/packet.c @@ -6,18 +6,11 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION -# include -# include -#else -# include -# include -# include -#endif - #include "common.h" #include "dhcpd.h" +#include +#include +#include int minpkt = 0; // zzz @@ -90,7 +83,6 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) { int bytes; - unsigned char *vendor; memset(packet, 0, sizeof(*packet)); bytes = safe_read(fd, packet, sizeof(*packet)); @@ -99,74 +91,18 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) return bytes; /* returns -1 */ } - if (packet->cookie != htonl(DHCP_MAGIC)) { + if (bytes < offsetof(struct dhcp_packet, options) + || packet->cookie != htonl(DHCP_MAGIC) + ) { bb_info_msg("Packet with bad magic, ignoring"); return -2; } log1("Received a packet"); udhcp_dump_packet(packet); - if (packet->op == BOOTREQUEST) { - vendor = udhcp_get_option(packet, DHCP_VENDOR); - if (vendor) { -#if 0 - static const char broken_vendors[][8] = { - "MSFT 98", - "" - }; - int i; - for (i = 0; broken_vendors[i][0]; i++) { - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i]) - && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", - broken_vendors[i]); - packet->flags |= htons(BROADCAST_FLAG); - } - } -#else - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1) - && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); - packet->flags |= htons(BROADCAST_FLAG); - } -#endif - } - } - return bytes; } -uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) -{ - /* Compute Internet Checksum for "count" bytes - * beginning at location "addr". - */ - int32_t sum = 0; - uint16_t *source = (uint16_t *) addr; - - while (count > 1) { - /* This is the inner loop */ - sum += *source++; - count -= 2; - } - - /* Add left-over byte, if any */ - if (count > 0) { - /* Make sure that the left-over byte is added correctly both - * with little and big endian hosts */ - uint16_t tmp = 0; - *(uint8_t*)&tmp = *(uint8_t*)source; - sum += tmp; - } - /* Fold 32-bit sum to 16 bits */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - /* Construct a ip/udp header for a packet, send packet */ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, uint32_t source_nip, int source_port, @@ -221,13 +157,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, packet.udp.len = htons(UDP_DHCP_SIZE - padding); /* for UDP checksumming, ip.len is set to UDP packet len */ packet.ip.tot_len = packet.udp.len; - packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); + packet.udp.check = inet_cksum((uint16_t *)&packet, + IP_UDP_DHCP_SIZE - padding); /* but for sending, it is set to IP packet len */ packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); packet.ip.ihl = sizeof(packet.ip) >> 2; packet.ip.version = IPVERSION; packet.ip.ttl = IPDEFTTL * 2; - packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); + packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); udhcp_dump_packet(dhcp_pkt); result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, @@ -247,7 +184,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, uint32_t source_nip, int source_port, uint32_t dest_nip, int dest_port) { - struct sockaddr_in client; + struct sockaddr_in sa; unsigned padding; int fd; int result = -1; @@ -260,20 +197,20 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, } setsockopt_reuseaddr(fd); - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_nip; - if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(source_port); + sa.sin_addr.s_addr = source_nip; + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "bind(%s)"; goto ret_close; } - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_nip; - if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(dest_port); + sa.sin_addr.s_addr = dest_nip; + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "connect"; goto ret_close; } diff --git a/release/src/router/busybox/networking/udhcp/socket.c b/release/src/router/busybox/networking/udhcp/socket.c index aa17e55587..35915e8964 100644 --- a/release/src/router/busybox/networking/udhcp/socket.c +++ b/release/src/router/busybox/networking/udhcp/socket.c @@ -36,53 +36,57 @@ int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac, uint16_t *mtu) { + + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char ifr_buf[sizeof(struct ifreq)]; + struct ifreq *const ifr = (void *)ifr_buf; + int fd; - struct ifreq ifr; struct sockaddr_in *our_ip; - memset(&ifr, 0, sizeof(ifr)); + memset(ifr, 0, sizeof(*ifr)); fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); - ifr.ifr_addr.sa_family = AF_INET; - strncpy_IFNAMSIZ(ifr.ifr_name, interface); + ifr->ifr_addr.sa_family = AF_INET; + strncpy_IFNAMSIZ(ifr->ifr_name, interface); if (nip) { - if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, + if (ioctl_or_perror(fd, SIOCGIFADDR, ifr, "is interface %s up and configured?", interface) ) { close(fd); return -1; } - our_ip = (struct sockaddr_in *) &ifr.ifr_addr; + our_ip = (struct sockaddr_in *) &ifr->ifr_addr; *nip = our_ip->sin_addr.s_addr; log1("IP %s", inet_ntoa(our_ip->sin_addr)); } if (ifindex) { - if (ioctl_or_warn(fd, SIOCGIFINDEX, &ifr) != 0) { + if (ioctl_or_warn(fd, SIOCGIFINDEX, ifr) != 0) { close(fd); return -1; } - log1("Adapter index %d", ifr.ifr_ifindex); - *ifindex = ifr.ifr_ifindex; + log1("Adapter index %d", ifr->ifr_ifindex); + *ifindex = ifr->ifr_ifindex; } if (mac) { - if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) { + if (ioctl_or_warn(fd, SIOCGIFHWADDR, ifr) != 0) { close(fd); return -1; } - memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); + memcpy(mac, ifr->ifr_hwaddr.sa_data, 6); log1("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } if (mtu) { - if (ioctl_or_warn(fd, SIOCGIFMTU, &ifr) != 0) { + if (ioctl_or_warn(fd, SIOCGIFMTU, ifr) != 0) { close(fd); return -1; } - log1("Adapter mtu %d", ifr.ifr_mtu); - *mtu = ifr.ifr_mtu; + log1("Adapter mtu %d", ifr->ifr_mtu); + *mtu = ifr->ifr_mtu; } close(fd); diff --git a/release/src/router/busybox/networking/vconfig.c b/release/src/router/busybox/networking/vconfig.c index 13c65ad781..924b2f0096 100644 --- a/release/src/router/busybox/networking/vconfig.c +++ b/release/src/router/busybox/networking/vconfig.c @@ -9,6 +9,17 @@ /* BB_AUDIT SUSv3 N/A */ +//usage:#define vconfig_trivial_usage +//usage: "COMMAND [OPTIONS]" +//usage:#define vconfig_full_usage "\n\n" +//usage: "Create and remove virtual ethernet devices\n" +//usage: "\n add IFACE VLAN_ID" +//usage: "\n rem VLAN_NAME" +//usage: "\n set_flag IFACE 0|1 VLAN_QOS" +//usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_name_type NAME_TYPE" + #include "libbb.h" #include @@ -55,58 +66,40 @@ struct vlan_ioctl_args { * The return value is the last data entry for the matching string. */ static const char *xfind_str(const char *table, const char *str) { - while (strcasecmp(str, table+1) != 0) { - table += table[0]; - if (!*table) { + while (strcasecmp(str, table + 1) != 0) { + if (!table[0]) bb_show_usage(); - } + table += table[0]; } return table - 1; } static const char cmds[] ALIGN1 = { 4, ADD_VLAN_CMD, 7, - 'a', 'd', 'd', 0, + 'a','d','d',0, 3, DEL_VLAN_CMD, 7, - 'r', 'e', 'm', 0, + 'r','e','m',0, 3, SET_VLAN_NAME_TYPE_CMD, 17, - 's', 'e', 't', '_', - 'n', 'a', 'm', 'e', '_', - 't', 'y', 'p', 'e', 0, + 's','e','t','_','n','a','m','e','_','t','y','p','e',0, 5, SET_VLAN_FLAG_CMD, 12, - 's', 'e', 't', '_', - 'f', 'l', 'a', 'g', 0, + 's','e','t','_','f','l','a','g',0, 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18, - 's', 'e', 't', '_', - 'e', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, - 5, SET_VLAN_INGRESS_PRIORITY_CMD, 16, - 's', 'e', 't', '_', - 'i', 'n', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, + 's','e','t','_','e','g','r','e','s','s','_','m','a','p',0, + 5, SET_VLAN_INGRESS_PRIORITY_CMD, 0, + 's','e','t','_','i','n','g','r','e','s','s','_','m','a','p',0, }; static const char name_types[] ALIGN1 = { VLAN_NAME_TYPE_PLUS_VID, 16, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D',0, VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, VLAN_NAME_TYPE_RAW_PLUS_VID, 15, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, - VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 20, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'D','E','V','_','P','L','U','S','_','V','I','D',0, + VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 0, + 'D','E','V','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, }; -static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; - int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vconfig_main(int argc, char **argv) { @@ -114,25 +107,19 @@ int vconfig_main(int argc, char **argv) const char *p; int fd; - if (argc < 3) { - bb_show_usage(); - } - - /* Don't bother closing the filedes. It will be closed on cleanup. */ - /* Will die if 802.1q is not present */ - xopen(conf_file_name, O_RDONLY); - memset(&ifr, 0, sizeof(ifr)); ++argv; - p = xfind_str(cmds+2, *argv); + if (!argv[0]) + bb_show_usage(); + p = xfind_str(cmds + 2, argv[0]); ifr.cmd = *p; - if (argc != p[-1]) { + if (argc != p[-1]) bb_show_usage(); - } - if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ - ifr.u.name_type = *xfind_str(name_types+1, argv[1]); + if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { + /* set_name_type */ + ifr.u.name_type = *xfind_str(name_types + 1, argv[1]); } else { strncpy_IFNAMSIZ(ifr.device1, argv[1]); p = argv[2]; @@ -141,22 +128,26 @@ int vconfig_main(int argc, char **argv) * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized * (unsigned) int members of a unions. But because of the range checking, * doing so wouldn't save that much space and would also make maintainence - * more of a pain. */ - if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ - ifr.u.flag = xatoul_range(p, 0, 1); + * more of a pain. + */ + if (ifr.cmd == SET_VLAN_FLAG_CMD) { + /* set_flag */ + ifr.u.flag = xatou_range(p, 0, 1); /* DM: in order to set reorder header, qos must be set */ - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); - } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ - ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); - } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ + ifr.vlan_qos = xatou_range(argv[3], 0, 7); + } else if (ifr.cmd == ADD_VLAN_CMD) { + /* add */ + ifr.u.VID = xatou_range(p, 0, VLAN_GROUP_ARRAY_LEN - 1); + } else if (ifr.cmd != DEL_VLAN_CMD) { + /* set_{egress|ingress}_map */ ifr.u.skb_priority = xatou(p); - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); + ifr.vlan_qos = xatou_range(argv[3], 0, 7); } } fd = xsocket(AF_INET, SOCK_STREAM, 0); ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr, - "ioctl error for %s", *argv); + "ioctl error for %s", argv[0]); return 0; } diff --git a/release/src/router/busybox/networking/wget.c b/release/src/router/busybox/networking/wget.c index afe0d3ab76..1991a10728 100644 --- a/release/src/router/busybox/networking/wget.c +++ b/release/src/router/busybox/networking/wget.c @@ -8,11 +8,39 @@ * Copyright (C) 2010 Bradley M. Kuhn * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. */ + +//usage:#define wget_trivial_usage +//usage: IF_FEATURE_WGET_LONG_OPTIONS( +//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" +//usage: " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" +//usage: " [--no-check-certificate] [-U|--user-agent AGENT]" +//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." +//usage: ) +//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( +//usage: "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]" +//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." +//usage: ) +//usage:#define wget_full_usage "\n\n" +//usage: "Retrieve files via HTTP or FTP\n" +//usage: "\n -s Spider mode - only check file existence" +//usage: "\n -c Continue retrieval of aborted transfer" +//usage: "\n -q Quiet" +//usage: "\n -P DIR Save to DIR (default .)" +//usage: IF_FEATURE_WGET_TIMEOUT( +//usage: "\n -T SEC Network read timeout is SEC seconds" +//usage: ) +//usage: "\n -O FILE Save to FILE ('-' for stdout)" +//usage: "\n -U STR Use STR for User-Agent header" +//usage: "\n -Y Use proxy ('on' or 'off')" + #include "libbb.h" +//#define log_io(...) bb_error_msg(__VA_ARGS__) +#define log_io(...) ((void)0) + + struct host_info { - // May be used if we ever will want to free() all xstrdup()s... - /* char *allocated; */ + char *allocated; const char *path; const char *user; char *host; @@ -30,17 +58,31 @@ struct globals { const char *curfile; /* Name of current file being transferred */ bb_progress_t pmt; #endif + char *dir_prefix; +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + char *post_data; + char *extra_headers; +#endif + char *fname_out; /* where to direct output (-O) */ + const char *proxy_flag; /* Use proxies if env vars are set */ + const char *user_agent; /* "User-Agent" header field */ #if ENABLE_FEATURE_WGET_TIMEOUT unsigned timeout_seconds; #endif + int output_fd; + int o_flags; smallint chunked; /* chunked transfer encoding */ smallint got_clen; /* got content-length: from server */ + /* Local downloads do benefit from big buffer. + * With 512 byte buffer, it was measured to be + * an order of magnitude slower than with big one. + */ + uint64_t just_to_align_next_member; + char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024]; } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) -struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; -}; +#define G (*ptr_to_globals) #define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ } while (0) @@ -73,12 +115,16 @@ static void progress_meter(int flag) return; if (flag == PROGRESS_START) - bb_progress_init(&G.pmt); + bb_progress_init(&G.pmt, G.curfile); - bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, - G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); + bb_progress_update(&G.pmt, + G.beg_range, + G.transferred, + (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len + ); if (flag == PROGRESS_END) { + bb_progress_free(&G.pmt); bb_putchar_stderr('\n'); G.transferred = 0; } @@ -124,48 +170,15 @@ static void strip_ipv6_scope_id(char *host) overlapping_strcpy(scope, cp); } -/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, - * and a short count if an eof or non-interrupt error is encountered. */ -static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) -{ - size_t ret; - char *p = (char*)ptr; - - do { - clearerr(stream); - errno = 0; - ret = fread(p, 1, nmemb, stream); - p += ret; - nmemb -= ret; - } while (nmemb && ferror(stream) && errno == EINTR); - - return p - (char*)ptr; -} - -/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM. - * Returns S, or NULL if an eof or non-interrupt error is encountered. */ -static char *safe_fgets(char *s, int size, FILE *stream) -{ - char *ret; - - do { - clearerr(stream); - errno = 0; - ret = fgets(s, size, stream); - } while (ret == NULL && ferror(stream) && errno == EINTR); - - return ret; -} - #if ENABLE_FEATURE_WGET_AUTHENTICATION -/* Base64-encode character string. buf is assumed to be char buf[512]. */ -static char *base64enc_512(char buf[512], const char *str) +/* Base64-encode character string. */ +static char *base64enc(const char *str) { unsigned len = strlen(str); - if (len > 512/4*3 - 10) /* paranoia */ - len = 512/4*3 - 10; - bb_uuencode(buf, str, len, bb_uuenc_tbl_base64); - return buf; + if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */ + len = sizeof(G.wget_buf)/4*3 - 10; + bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64); + return G.wget_buf; } #endif @@ -186,43 +199,58 @@ static FILE *open_socket(len_and_sockaddr *lsa) /* hopefully it understands what ESPIPE means... */ fp = fdopen(xconnect_stream(lsa), "r+"); if (fp == NULL) - bb_perror_msg_and_die("fdopen"); + bb_perror_msg_and_die(bb_msg_memory_exhausted); return fp; } -static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) +/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ +static char fgets_and_trim(FILE *fp) +{ + char c; + char *buf_ptr; + + if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL) + bb_perror_msg_and_die("error getting response"); + + buf_ptr = strchrnul(G.wget_buf, '\n'); + c = *buf_ptr; + *buf_ptr = '\0'; + buf_ptr = strchrnul(G.wget_buf, '\r'); + *buf_ptr = '\0'; + + log_io("< %s", G.wget_buf); + + return c; +} + +static int ftpcmd(const char *s1, const char *s2, FILE *fp) { int result; if (s1) { - if (!s2) s2 = ""; + if (!s2) + s2 = ""; fprintf(fp, "%s%s\r\n", s1, s2); fflush(fp); + log_io("> %s%s", s1, s2); } do { - char *buf_ptr; - - if (fgets(buf, 510, fp) == NULL) { - bb_perror_msg_and_die("error getting response"); - } - buf_ptr = strstr(buf, "\r\n"); - if (buf_ptr) { - *buf_ptr = '\0'; - } - } while (!isdigit(buf[0]) || buf[3] != ' '); + fgets_and_trim(fp); + } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); - buf[3] = '\0'; - result = xatoi_positive(buf); - buf[3] = ' '; + G.wget_buf[3] = '\0'; + result = xatoi_positive(G.wget_buf); + G.wget_buf[3] = ' '; return result; } -static void parse_url(char *src_url, struct host_info *h) +static void parse_url(const char *src_url, struct host_info *h) { char *url, *p, *sp; - /* h->allocated = */ url = xstrdup(src_url); + free(h->allocated); + h->allocated = url = xstrdup(src_url); if (strncmp(url, "http://", 7) == 0) { h->port = bb_lookup_port("http", "tcp", 80); @@ -270,15 +298,20 @@ static void parse_url(char *src_url, struct host_info *h) sp = strrchr(h->host, '@'); if (sp != NULL) { - h->user = h->host; + // URL-decode "user:password" string before base64-encoding: + // wget http://test:my%20pass@example.com should send + // Authorization: Basic dGVzdDpteSBwYXNz + // which decodes to "test:my pass". + // Standard wget and curl do this too. *sp = '\0'; + h->user = percent_decode_in_place(h->host, /*strict:*/ 0); h->host = sp + 1; } sp = h->host; } -static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) +static char *gethdr(FILE *fp) { char *s, *hdrval; int c; @@ -286,87 +319,37 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) /* *istrunc = 0; */ /* retrieve header line */ - if (fgets(buf, bufsiz, fp) == NULL) - return NULL; + c = fgets_and_trim(fp); - /* see if we are at the end of the headers */ - for (s = buf; *s == '\r'; ++s) - continue; - if (*s == '\n') + /* end of the headers? */ + if (G.wget_buf[0] == '\0') return NULL; /* convert the header name to lower case */ - for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { + for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { /* tolower for "A-Z", no-op for "0-9a-z-." */ - *s = (*s | 0x20); + *s |= 0x20; } /* verify we are at the end of the header name */ if (*s != ':') - bb_error_msg_and_die("bad header line: %s", sanitize_string(buf)); + bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf)); /* locate the start of the header value */ *s++ = '\0'; hdrval = skip_whitespace(s); - /* locate the end of header */ - while (*s && *s != '\r' && *s != '\n') - ++s; - - /* end of header found */ - if (*s) { - *s = '\0'; - return hdrval; + if (c != '\n') { + /* Rats! The buffer isn't big enough to hold the entire header value */ + while (c = getc(fp), c != EOF && c != '\n') + continue; } - /* Rats! The buffer isn't big enough to hold the entire header value */ - while (c = getc(fp), c != EOF && c != '\n') - continue; - /* *istrunc = 1; */ return hdrval; } -#if ENABLE_FEATURE_WGET_LONG_OPTIONS -static char *URL_escape(const char *str) -{ - /* URL encode, see RFC 2396 */ - char *dst; - char *res = dst = xmalloc(strlen(str) * 3 + 1); - unsigned char c; - - while (1) { - c = *str++; - if (c == '\0' - /* || strchr("!&'()*-.=_~", c) - more code */ - || c == '!' - || c == '&' - || c == '\'' - || c == '(' - || c == ')' - || c == '*' - || c == '-' - || c == '.' - || c == '=' - || c == '_' - || c == '~' - || (c >= '0' && c <= '9') - || ((c|0x20) >= 'a' && (c|0x20) <= 'z') - ) { - *dst++ = c; - if (c == '\0') - return res; - } else { - *dst++ = '%'; - *dst++ = bb_hexdigits_upcase[c >> 4]; - *dst++ = bb_hexdigits_upcase[c & 0xf]; - } - } -} -#endif - static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) { - char buf[512]; FILE *sfp; char *str; int port; @@ -375,8 +358,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ target->user = xstrdup("anonymous:busybox@"); sfp = open_socket(lsa); - if (ftpcmd(NULL, NULL, sfp, buf) != 220) - bb_error_msg_and_die("%s", sanitize_string(buf+4)); + if (ftpcmd(NULL, NULL, sfp) != 220) + bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4)); /* * Splitting username:password pair, @@ -385,24 +368,24 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ str = strchr(target->user, ':'); if (str) *str++ = '\0'; - switch (ftpcmd("USER ", target->user, sfp, buf)) { + switch (ftpcmd("USER ", target->user, sfp)) { case 230: break; case 331: - if (ftpcmd("PASS ", str, sfp, buf) == 230) + if (ftpcmd("PASS ", str, sfp) == 230) break; /* fall through (failed login) */ default: - bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4)); + bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4)); } - ftpcmd("TYPE I", NULL, sfp, buf); + ftpcmd("TYPE I", NULL, sfp); /* * Querying file size */ - if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) { - G.content_len = BB_STRTOOFF(buf+4, NULL, 10); + if (ftpcmd("SIZE ", target->path, sfp) == 213) { + G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("SIZE value is garbage"); } @@ -412,41 +395,40 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ /* * Entering passive mode */ - if (ftpcmd("PASV", NULL, sfp, buf) != 227) { + if (ftpcmd("PASV", NULL, sfp) != 227) { pasv_error: - bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf)); + bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf)); } // Response is "227 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 - str = strrchr(buf, ')'); + str = strrchr(G.wget_buf, ')'); if (str) str[0] = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port = xatou_range(str+1, 0, 255); *str = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port += xatou_range(str+1, 0, 255) * 256; - set_nport(lsa, htons(port)); + set_nport(&lsa->u.sa, htons(port)); *dfpp = open_socket(lsa); if (G.beg_range) { - sprintf(buf, "REST %"OFF_FMT"u", G.beg_range); - if (ftpcmd(buf, NULL, sfp, buf) == 350) + sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range); + if (ftpcmd(G.wget_buf, NULL, sfp) == 350) G.content_len -= G.beg_range; } - if (ftpcmd("RETR ", target->path, sfp, buf) > 150) - bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf)); + if (ftpcmd("RETR ", target->path, sfp) > 150) + bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf)); return sfp; } -static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) +static void NOINLINE retrieve_file_data(FILE *dfp) { - char buf[4*1024]; /* made bigger to speed up local xfers */ #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT # if ENABLE_FEATURE_WGET_TIMEOUT unsigned second_cnt; @@ -465,20 +447,28 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) while (1) { #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + /* Must use nonblocking I/O, otherwise fread will loop + * and *block* until it reads full buffer, + * which messes up progress bar and/or timeout logic. + * Because of nonblocking I/O, we need to dance + * very carefully around EAGAIN. See explanation at + * clearerr() call. + */ ndelay_on(polldata.fd); #endif while (1) { int n; unsigned rdsz; - rdsz = sizeof(buf); + rdsz = sizeof(G.wget_buf); if (G.got_clen) { - if (G.content_len < (off_t)sizeof(buf)) { + if (G.content_len < (off_t)sizeof(G.wget_buf)) { if ((int)G.content_len <= 0) break; rdsz = (unsigned)G.content_len; } } + #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT # if ENABLE_FEATURE_WGET_TIMEOUT second_cnt = G.timeout_seconds; @@ -489,13 +479,13 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) # if ENABLE_FEATURE_WGET_TIMEOUT if (second_cnt != 0 && --second_cnt == 0) { progress_meter(PROGRESS_END); - bb_perror_msg_and_die("download timed out"); + bb_error_msg_and_die("download timed out"); } # endif /* Needed for "stalled" indicator */ progress_meter(PROGRESS_BUMP); } -#endif + /* fread internally uses read loop, which in our case * is usually exited when we get EAGAIN. * In this case, libc sets error marker on the stream. @@ -506,7 +496,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) */ clearerr(dfp); errno = 0; - n = safe_fread(buf, rdsz, dfp); +#endif + n = fread(G.wget_buf, 1, rdsz, dfp); /* man fread: * If error occurs, or EOF is reached, the return value * is a short item count (or zero). @@ -522,7 +513,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) break; /* EOF, not error */ } - xwrite(output_fd, buf, n); + xwrite(G.output_fd, G.wget_buf, n); + #if ENABLE_FEATURE_WGET_STATUSBAR G.transferred += n; progress_meter(PROGRESS_BUMP); @@ -534,128 +526,61 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) } } #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT - ndelay_off(polldata.fd); + clearerr(dfp); + ndelay_off(polldata.fd); /* else fgets can get very unhappy */ #endif - if (!G.chunked) break; - safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ + fgets_and_trim(dfp); /* Eat empty line */ get_clen: - safe_fgets(buf, sizeof(buf), dfp); - G.content_len = STRTOOFF(buf, NULL, 16); + fgets_and_trim(dfp); + G.content_len = STRTOOFF(G.wget_buf, NULL, 16); /* FIXME: error check? */ if (G.content_len == 0) break; /* all done! */ G.got_clen = 1; } + /* Draw full bar and free its resources */ + G.chunked = 0; /* makes it show 100% even for chunked download */ + G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ progress_meter(PROGRESS_END); } -int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int wget_main(int argc UNUSED_PARAM, char **argv) +static void download_one_url(const char *url) { - char buf[512]; - struct host_info server, target; - len_and_sockaddr *lsa; - unsigned opt; + bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; - char *proxy = NULL; - char *dir_prefix = NULL; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - char *post_data; - char *extra_headers = NULL; - llist_t *headers_llist = NULL; -#endif + len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ - char *fname_out; /* where to direct output (-O) */ - int output_fd = -1; - bool use_proxy; /* Use proxies if env vars are set */ - const char *proxy_flag = "on"; /* Use proxies if env vars are set */ - const char *user_agent = "Wget";/* "User-Agent" header field */ - - static const char keywords[] ALIGN1 = - "content-length\0""transfer-encoding\0""chunked\0""location\0"; - enum { - KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location - }; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - static const char wget_longopts[] ALIGN1 = - /* name, has_arg, val */ - "continue\0" No_argument "c" - "spider\0" No_argument "s" - "quiet\0" No_argument "q" - "output-document\0" Required_argument "O" - "directory-prefix\0" Required_argument "P" - "proxy\0" Required_argument "Y" - "user-agent\0" Required_argument "U" -#if ENABLE_FEATURE_WGET_TIMEOUT - "timeout\0" Required_argument "T" -#endif - /* Ignored: */ - // "tries\0" Required_argument "t" - /* Ignored (we always use PASV): */ - "passive-ftp\0" No_argument "\xff" - "header\0" Required_argument "\xfe" - "post-data\0" Required_argument "\xfd" - /* Ignored (we don't do ssl) */ - "no-check-certificate\0" No_argument "\xfc" - ; -#endif - - INIT_G(); - -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - applet_long_options = wget_longopts; -#endif - /* server.allocated = target.allocated = NULL; */ - opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); - opt = getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", - &fname_out, &dir_prefix, - &proxy_flag, &user_agent, - IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), - NULL /* -t RETRIES */ - IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) - IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) - ); -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (headers_llist) { - int size = 1; - char *cp; - llist_t *ll = headers_llist; - while (ll) { - size += strlen(ll->data) + 2; - ll = ll->link; - } - extra_headers = cp = xmalloc(size); - while (headers_llist) { - cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); - } - } -#endif - - /* TODO: compat issue: should handle "wget URL1 URL2..." */ - + char *proxy = NULL; + char *fname_out_alloc; + char *redirected_path = NULL; + struct host_info server; + struct host_info target; + + server.allocated = NULL; + target.allocated = NULL; + server.user = NULL; target.user = NULL; - parse_url(argv[optind], &target); + + parse_url(url, &target); /* Use the proxy if necessary */ - use_proxy = (strcmp(proxy_flag, "off") != 0); + use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); - if (proxy && proxy[0]) { - server.user = NULL; + use_proxy = (proxy && proxy[0]); + if (use_proxy) parse_url(proxy, &server); - } else { - use_proxy = 0; - } } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { - server.host = xstrdup(target.host); + //free(server.allocated); - can't be non-NULL + server.host = server.allocated = xstrdup(target.host); } else { server.host = target.host; } @@ -664,50 +589,50 @@ int wget_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); - /* Guess an output filename, if there was no -O FILE */ - if (!(opt & WGET_OPT_OUTNAME)) { - fname_out = bb_get_last_path_component_nostrip(target.path); + /* If there was no -O FILE, guess output filename */ + fname_out_alloc = NULL; + if (!(option_mask32 & WGET_OPT_OUTNAME)) { + G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ - if (fname_out[0] == '/' || !fname_out[0]) - fname_out = (char*)"index.html"; + if (G.fname_out[0] == '/' || !G.fname_out[0]) + G.fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ - if (dir_prefix) - fname_out = concat_path_file(dir_prefix, fname_out); - } else { - if (LONE_DASH(fname_out)) { - /* -O - */ - output_fd = 1; - opt &= ~WGET_OPT_CONTINUE; + else { + if (G.dir_prefix) + G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); + else { + /* redirects may free target.path later, need to make a copy */ + G.fname_out = fname_out_alloc = xstrdup(G.fname_out); + } } } #if ENABLE_FEATURE_WGET_STATUSBAR - G.curfile = bb_get_last_path_component_nostrip(fname_out); + G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif - /* Impossible? - if ((opt & WGET_OPT_CONTINUE) && !fname_out) - bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)"); - */ - /* Determine where to start transfer */ - if (opt & WGET_OPT_CONTINUE) { - output_fd = open(fname_out, O_WRONLY); - if (output_fd >= 0) { - G.beg_range = xlseek(output_fd, 0, SEEK_END); + G.beg_range = 0; + if (option_mask32 & WGET_OPT_CONTINUE) { + G.output_fd = open(G.fname_out, O_WRONLY); + if (G.output_fd >= 0) { + G.beg_range = xlseek(G.output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. - * We are not sure it exists on remove side */ + * We are not sure it exists on remote side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); - if (!(opt & WGET_OPT_QUIET)) { + if (!(option_mask32 & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: + /*G.content_len = 0; - redundant, got_clen = 0 is enough */ + G.got_clen = 0; + G.chunked = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session @@ -715,6 +640,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) char *str; int status; + /* Open socket to http server */ sfp = open_socket(lsa); @@ -724,14 +650,14 @@ int wget_main(int argc UNUSED_PARAM, char **argv) target.is_ftp ? "f" : "ht", target.host, target.path); } else { - if (opt & WGET_OPT_POST_DATA) + if (option_mask32 & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", - target.host, user_agent); + target.host, G.user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) @@ -741,11 +667,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, - base64enc_512(buf, target.user)); + base64enc(target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", - base64enc_512(buf, server.user)); + base64enc(server.user)); } #endif @@ -753,19 +679,17 @@ int wget_main(int argc UNUSED_PARAM, char **argv) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (extra_headers) - fputs(extra_headers, sfp); + if (G.extra_headers) + fputs(G.extra_headers, sfp); - if (opt & WGET_OPT_POST_DATA) { - char *estr = URL_escape(post_data); + if (option_mask32 & WGET_OPT_POST_DATA) { fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %u\r\n" "\r\n" "%s", - (int) strlen(estr), estr + (int) strlen(G.post_data), G.post_data ); - free(estr); } else #endif { @@ -778,10 +702,9 @@ int wget_main(int argc UNUSED_PARAM, char **argv) * Retrieve HTTP response line and check for "200" status code. */ read_response: - if (fgets(buf, sizeof(buf), sfp) == NULL) - bb_error_msg_and_die("no response from server"); + fgets_and_trim(sfp); - str = buf; + str = G.wget_buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check @@ -790,7 +713,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) switch (status) { case 0: case 100: - while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) + while (gethdr(sfp) != NULL) /* eat all remaining headers */; goto read_response; case 200: @@ -830,22 +753,29 @@ However, in real world it was observed that some web servers break; /* fall through */ default: - bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); + bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); } /* * Retrieve HTTP headers. */ - while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { - /* gethdr converted "FOO:" string to lowercase */ + while ((str = gethdr(sfp)) != NULL) { + static const char keywords[] ALIGN1 = + "content-length\0""transfer-encoding\0""location\0"; + enum { + KEY_content_length = 1, KEY_transfer_encoding, KEY_location + }; smalluint key; + + /* gethdr converted "FOO:" string to lowercase */ + /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } - key = index_in_strings(keywords, buf) + 1; + key = index_in_strings(keywords, G.wget_buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { @@ -855,23 +785,23 @@ However, in real world it was observed that some web servers continue; } if (key == KEY_transfer_encoding) { - if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) + if (strcmp(str_tolower(str), "chunked") != 0) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); - G.chunked = G.got_clen = 1; + G.chunked = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); - G.got_clen = 0; - G.chunked = 0; - if (str[0] == '/') - /* free(target.allocated); */ - target.path = /* target.allocated = */ xstrdup(str+1); + if (str[0] == '/') { + free(redirected_path); + target.path = redirected_path = xstrdup(str+1); /* lsa stays the same: it's on the same server */ - else { + } else { parse_url(str, &target); if (!use_proxy) { + free(server.allocated); + server.allocated = NULL; server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ @@ -896,30 +826,117 @@ However, in real world it was observed that some web servers sfp = prepare_ftp_session(&dfp, &target, lsa); } - if (opt & WGET_OPT_SPIDER) { - if (ENABLE_FEATURE_CLEAN_UP) - fclose(sfp); - return EXIT_SUCCESS; - } + free(lsa); - if (output_fd < 0) { - int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; - /* compat with wget: -O FILE can overwrite */ - if (opt & WGET_OPT_OUTNAME) - o_flags = O_WRONLY | O_CREAT | O_TRUNC; - output_fd = xopen(fname_out, o_flags); + if (!(option_mask32 & WGET_OPT_SPIDER)) { + if (G.output_fd < 0) + G.output_fd = xopen(G.fname_out, G.o_flags); + retrieve_file_data(dfp); + if (!(option_mask32 & WGET_OPT_OUTNAME)) { + xclose(G.output_fd); + G.output_fd = -1; + } } - retrieve_file_data(dfp, output_fd); - xclose(output_fd); - if (dfp != sfp) { - /* It's ftp. Close it properly */ + /* It's ftp. Close data connection properly */ fclose(dfp); - if (ftpcmd(NULL, NULL, sfp, buf) != 226) - bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); - /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ + if (ftpcmd(NULL, NULL, sfp) != 226) + bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); + /* ftpcmd("QUIT", NULL, sfp); - why bother? */ } + fclose(sfp); + + free(server.allocated); + free(target.allocated); + free(fname_out_alloc); + free(redirected_path); +} + +int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int wget_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + static const char wget_longopts[] ALIGN1 = + /* name, has_arg, val */ + "continue\0" No_argument "c" +//FIXME: -s isn't --spider, it's --save-headers! + "spider\0" No_argument "s" + "quiet\0" No_argument "q" + "output-document\0" Required_argument "O" + "directory-prefix\0" Required_argument "P" + "proxy\0" Required_argument "Y" + "user-agent\0" Required_argument "U" +#if ENABLE_FEATURE_WGET_TIMEOUT + "timeout\0" Required_argument "T" +#endif + /* Ignored: */ + // "tries\0" Required_argument "t" + /* Ignored (we always use PASV): */ + "passive-ftp\0" No_argument "\xff" + "header\0" Required_argument "\xfe" + "post-data\0" Required_argument "\xfd" + /* Ignored (we don't do ssl) */ + "no-check-certificate\0" No_argument "\xfc" + ; +#endif + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + llist_t *headers_llist = NULL; +#endif + + INIT_G(); + + IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) + G.proxy_flag = "on"; /* use proxies if env vars are set */ + G.user_agent = "Wget"; /* "User-Agent" header field */ + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + applet_long_options = wget_longopts; +#endif + opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); + getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", + &G.fname_out, &G.dir_prefix, + &G.proxy_flag, &G.user_agent, + IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), + NULL /* -t RETRIES */ + IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) + IF_FEATURE_WGET_LONG_OPTIONS(, &G.post_data) + ); + argv += optind; + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + if (headers_llist) { + int size = 1; + char *cp; + llist_t *ll = headers_llist; + while (ll) { + size += strlen(ll->data) + 2; + ll = ll->link; + } + G.extra_headers = cp = xmalloc(size); + while (headers_llist) { + cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); + } + } +#endif + + G.output_fd = -1; + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; + if (G.fname_out) { /* -O FILE ? */ + if (LONE_DASH(G.fname_out)) { /* -O - ? */ + G.output_fd = 1; + option_mask32 &= ~WGET_OPT_CONTINUE; + } + /* compat with wget: -O FILE can overwrite */ + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC; + } + + while (*argv) + download_one_url(*argv++); + + if (G.output_fd >= 0) + xclose(G.output_fd); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/networking/whois.c b/release/src/router/busybox/networking/whois.c new file mode 100644 index 0000000000..bf330334a2 --- /dev/null +++ b/release/src/router/busybox/networking/whois.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * whois - tiny client for the whois directory service + * + * Copyright (c) 2011 Pere Orga + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* TODO + * Add ipv6 support + * Add proxy support + */ + +//config:config WHOIS +//config: bool "whois" +//config: default y +//config: help +//config: whois is a client for the whois directory service + +//applet:IF_WHOIS(APPLET(whois, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_WHOIS) += whois.o + +//usage:#define whois_trivial_usage +//usage: "[-h SERVER] [-p PORT] NAME..." +//usage:#define whois_full_usage "\n\n" +//usage: "Query WHOIS info about NAME\n" +//usage: "\n -h,-p Server to query" + +#include "libbb.h" + +static void pipe_out(int fd) +{ + FILE *fp; + char buf[1024]; + + fp = xfdopen_for_read(fd); + while (fgets(buf, sizeof(buf), fp)) { + char *p = strpbrk(buf, "\r\n"); + if (p) + *p = '\0'; + puts(buf); + } + + fclose(fp); /* closes fd too */ +} + +int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int whois_main(int argc UNUSED_PARAM, char **argv) +{ + int port = 43; + const char *host = "whois-servers.net"; + + opt_complementary = "-1:p+"; + getopt32(argv, "h:p:", &host, &port); + + argv += optind; + do { + int fd = create_and_connect_stream_or_die(host, port); + fdprintf(fd, "%s\r\n", *argv); + pipe_out(fd); + } + while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/networking/zcip.c b/release/src/router/busybox/networking/zcip.c index 6fa265ad4d..7314ff8db7 100644 --- a/release/src/router/busybox/networking/zcip.c +++ b/release/src/router/busybox/networking/zcip.c @@ -23,14 +23,24 @@ // - avoid silent script failures, especially under load... // - link status monitoring (restart on link-up; stop on link-down) +//usage:#define zcip_trivial_usage +//usage: "[OPTIONS] IFACE SCRIPT" +//usage:#define zcip_full_usage "\n\n" +//usage: "Manage a ZeroConf IPv4 link-local address\n" +//usage: "\n -f Run in foreground" +//usage: "\n -q Quit after obtaining address" +//usage: "\n -r 169.254.x.x Request this address first" +//usage: "\n -v Verbose" +//usage: "\n" +//usage: "\nWith no -q, runs continuously monitoring for ARP conflicts," +//usage: "\nexits only on I/O errors (link down etc)" + +#include "libbb.h" #include -#include #include #include -#include #include -#include "libbb.h" #include /* We don't need more than 32 bits of the counter */ @@ -81,6 +91,7 @@ struct globals { #define G (*(struct globals*)&bb_common_bufsiz1) #define saddr (G.saddr ) #define eth_addr (G.eth_addr) +#define INIT_G() do { } while (0) /** @@ -213,6 +224,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) #define verbose (L.verbose ) memset(&L, 0, sizeof(L)); + INIT_G(); #define FOREGROUND (opts & 1) #define QUIT (opts & 2) diff --git a/release/src/router/busybox/printutils/lpd.c b/release/src/router/busybox/printutils/lpd.c index 157cbe8ae7..642e8a89e7 100644 --- a/release/src/router/busybox/printutils/lpd.c +++ b/release/src/router/busybox/printutils/lpd.c @@ -70,6 +70,17 @@ * mv -f ./"$DATAFILE" save/ */ +//usage:#define lpd_trivial_usage +//usage: "SPOOLDIR [HELPER [ARGS]]" +//usage:#define lpd_full_usage "\n\n" +//usage: "SPOOLDIR must contain (symlinks to) device nodes or directories" +//usage: "\nwith names matching print queue names. In the first case, jobs are" +//usage: "\nsent directly to the device. Otherwise each job is stored in queue" +//usage: "\ndirectory and HELPER program is called. Name of file to print" +//usage: "\nis passed in $DATAFILE variable." +//usage: "\nExample:" +//usage: "\n tcpsvd -E 0 515 softlimit -m 999999 lpd /var/spool ./print" + #include "libbb.h" // strip argument of bad chars @@ -91,7 +102,7 @@ static char *xmalloc_read_stdin(void) { // SECURITY: size_t max = 4 * 1024; // more than enough for commands! - return xmalloc_reads(STDIN_FILENO, NULL, &max); + return xmalloc_reads(STDIN_FILENO, &max); } int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/printutils/lpr.c b/release/src/router/busybox/printutils/lpr.c index 2849179263..fc6bca9e8d 100644 --- a/release/src/router/busybox/printutils/lpr.c +++ b/release/src/router/busybox/printutils/lpr.c @@ -11,6 +11,25 @@ * * See RFC 1179 for protocol description. */ + +//usage:#define lpr_trivial_usage +//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 */ +//usage:#define lpr_full_usage "\n\n" +//usage: " -P lp service to connect to (else uses $PRINTER)" +//usage: "\n -m Send mail on completion" +//usage: "\n -h Print banner page too" +//usage: "\n -V Verbose" +//usage: +//usage:#define lpq_trivial_usage +//usage: "[-P queue[@host[:port]]] [-U USERNAME] [-d JOBID]... [-fs]" +//usage:#define lpq_full_usage "\n\n" +//usage: " -P lp service to connect to (else uses $PRINTER)" +//usage: "\n -d Delete jobs" +//usage: "\n -f Force any waiting job to be printed" +//usage: "\n -s Short display" + #include "libbb.h" /* diff --git a/release/src/router/busybox/procps/Config.src b/release/src/router/busybox/procps/Config.src index 1ff6dfd30c..5cd47c84f5 100644 --- a/release/src/router/busybox/procps/Config.src +++ b/release/src/router/busybox/procps/Config.src @@ -10,7 +10,7 @@ INSERT config FREE bool "free" default y - depends on PLATFORM_LINUX #sysinfo() + select PLATFORM_LINUX #sysinfo() help free displays the total amount of free and used physical and swap memory in the system, as well as the buffers used by the kernel. @@ -46,12 +46,6 @@ config KILLALL5 default y depends on KILL -config NMETER - bool "nmeter" - default y - help - Prints selected system stats continuously, one line per update. - config PGREP bool "pgrep" default y @@ -96,16 +90,25 @@ config PS config FEATURE_PS_WIDE bool "Enable wide output option (-w)" default y - depends on PS + depends on PS && !DESKTOP help Support argument 'w' for wide output. If given once, 132 chars are printed, and if given more than once, the length is unlimited. +config FEATURE_PS_LONG + bool "Enable long output option (-l)" + default y + depends on PS && !DESKTOP + help + Support argument 'l' for long output. + Adds fields PPID, RSS, START, TIME & TTY + config FEATURE_PS_TIME bool "Enable time and elapsed time output" default y - depends on PS && DESKTOP && PLATFORM_LINUX #sysinfo() + depends on PS && DESKTOP + select PLATFORM_LINUX help Support -o time and -o etime output specifiers. @@ -192,20 +195,12 @@ config FEATURE_TOPMEM Enable 's' in top (gives lots of memory info). config FEATURE_SHOW_THREADS - bool "Support for showing threads in ps/top" - default y - depends on PS || TOP - help - Enables ps -T option and 'h' command in top - -config UPTIME - bool "uptime" + bool "Support for showing threads in ps/pstree/top" default y - depends on PLATFORM_LINUX #sysinfo() + depends on PS || TOP || PSTREE help - uptime gives a one line display of the current time, how long - the system has been running, how many users are currently logged - on, and the system load averages for the past 1, 5, and 15 minutes. + Enables the ps -T option, showing of threads in pstree, + and 'h' command in top. config WATCH bool "watch" diff --git a/release/src/router/busybox/procps/Kbuild.src b/release/src/router/busybox/procps/Kbuild.src index 791d65670f..89b1cc0941 100644 --- a/release/src/router/busybox/procps/Kbuild.src +++ b/release/src/router/busybox/procps/Kbuild.src @@ -11,7 +11,6 @@ lib-$(CONFIG_FREE) += free.o lib-$(CONFIG_FUSER) += fuser.o lib-$(CONFIG_KILL) += kill.o lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash -lib-$(CONFIG_NMETER) += nmeter.o lib-$(CONFIG_PGREP) += pgrep.o lib-$(CONFIG_PKILL) += pgrep.o lib-$(CONFIG_PIDOF) += pidof.o diff --git a/release/src/router/busybox/procps/free.c b/release/src/router/busybox/procps/free.c index efbac5ba63..47f2fc3b25 100644 --- a/release/src/router/busybox/procps/free.c +++ b/release/src/router/busybox/procps/free.c @@ -9,7 +9,22 @@ /* getopt not needed */ +//usage:#define free_trivial_usage +//usage: "" IF_DESKTOP("[-b/k/m/g]") +//usage:#define free_full_usage "\n\n" +//usage: "Display the amount of free and used system memory" +//usage: +//usage:#define free_example_usage +//usage: "$ free\n" +//usage: " total used free shared buffers\n" +//usage: " Mem: 257628 248724 8904 59644 93124\n" +//usage: " Swap: 128516 8404 120112\n" +//usage: "Total: 386144 257128 129016\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif struct globals { unsigned mem_unit; @@ -19,7 +34,7 @@ struct globals { #else # define G_unit_steps 10 #endif -}; +} FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) diff --git a/release/src/router/busybox/procps/fuser.c b/release/src/router/busybox/procps/fuser.c dissimilarity index 65% index be19098dde..05b52abb1c 100644 --- a/release/src/router/busybox/procps/fuser.c +++ b/release/src/router/busybox/procps/fuser.c @@ -1,317 +1,321 @@ -/* vi: set sw=4 ts=4: */ -/* - * tiny fuser implementation - * - * Copyright 2004 Tony J. White - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ - -#include "libbb.h" - -#define MAX_LINE 255 - -#define OPTION_STRING "mks64" -enum { - OPT_MOUNT = (1 << 0), - OPT_KILL = (1 << 1), - OPT_SILENT = (1 << 2), - OPT_IP6 = (1 << 3), - OPT_IP4 = (1 << 4), -}; - -typedef struct inode_list { - struct inode_list *next; - ino_t inode; - dev_t dev; -} inode_list; - -typedef struct pid_list { - struct pid_list *next; - pid_t pid; -} pid_list; - - -struct globals { - pid_list *pid_list_head; - inode_list *inode_list_head; -}; -#define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) - - -static void add_pid(const pid_t pid) -{ - pid_list **curr = &G.pid_list_head; - - while (*curr) { - if ((*curr)->pid == pid) - return; - curr = &(*curr)->next; - } - - *curr = xzalloc(sizeof(pid_list)); - (*curr)->pid = pid; -} - -static void add_inode(const struct stat *st) -{ - inode_list **curr = &G.inode_list_head; - - while (*curr) { - if ((*curr)->dev == st->st_dev - && (*curr)->inode == st->st_ino - ) { - return; - } - curr = &(*curr)->next; - } - - *curr = xzalloc(sizeof(inode_list)); - (*curr)->dev = st->st_dev; - (*curr)->inode = st->st_ino; -} - -static void scan_proc_net(const char *path, unsigned port) -{ - char line[MAX_LINE + 1]; - long long uint64_inode; - unsigned tmp_port; - FILE *f; - struct stat st; - int fd; - - /* find socket dev */ - st.st_dev = 0; - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd >= 0) { - fstat(fd, &st); - close(fd); - } - - f = fopen_for_read(path); - if (!f) - return; - - while (fgets(line, MAX_LINE, f)) { - char addr[68]; - if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " - "%*x:%*x %*x %*d %*d %llu", - addr, &tmp_port, &uint64_inode) == 3 - ) { - int len = strlen(addr); - if (len == 8 && (option_mask32 & OPT_IP6)) - continue; - if (len > 8 && (option_mask32 & OPT_IP4)) - continue; - if (tmp_port == port) { - st.st_ino = uint64_inode; - add_inode(&st); - } - } - } - fclose(f); -} - -static int search_dev_inode(const struct stat *st) -{ - inode_list *ilist = G.inode_list_head; - - while (ilist) { - if (ilist->dev == st->st_dev) { - if (option_mask32 & OPT_MOUNT) - return 1; - if (ilist->inode == st->st_ino) - return 1; - } - ilist = ilist->next; - } - return 0; -} - -static void scan_pid_maps(const char *fname, pid_t pid) -{ - FILE *file; - char line[MAX_LINE + 1]; - int major, minor; - long long uint64_inode; - struct stat st; - - file = fopen_for_read(fname); - if (!file) - return; - - while (fgets(line, MAX_LINE, file)) { - if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) - continue; - st.st_ino = uint64_inode; - if (major == 0 && minor == 0 && st.st_ino == 0) - continue; - st.st_dev = makedev(major, minor); - if (search_dev_inode(&st)) - add_pid(pid); - } - fclose(file); -} - -static void scan_link(const char *lname, pid_t pid) -{ - struct stat st; - - if (stat(lname, &st) >= 0) { - if (search_dev_inode(&st)) - add_pid(pid); - } -} - -static void scan_dir_links(const char *dname, pid_t pid) -{ - DIR *d; - struct dirent *de; - char *lname; - - d = opendir(dname); - if (!d) - return; - - while ((de = readdir(d)) != NULL) { - lname = concat_subpath_file(dname, de->d_name); - if (lname == NULL) - continue; - scan_link(lname, pid); - free(lname); - } - closedir(d); -} - -/* NB: does chdir internally */ -static void scan_proc_pids(void) -{ - DIR *d; - struct dirent *de; - pid_t pid; - - xchdir("/proc"); - d = opendir("/proc"); - if (!d) - return; - - while ((de = readdir(d)) != NULL) { - pid = (pid_t)bb_strtou(de->d_name, NULL, 10); - if (errno) - continue; - if (chdir(de->d_name) < 0) - continue; - scan_link("cwd", pid); - scan_link("exe", pid); - scan_link("root", pid); - - scan_dir_links("fd", pid); - scan_dir_links("lib", pid); - scan_dir_links("mmap", pid); - - scan_pid_maps("maps", pid); - xchdir("/proc"); - } - closedir(d); -} - -int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int fuser_main(int argc UNUSED_PARAM, char **argv) -{ - pid_list *plist; - pid_t mypid; - char **pp; - struct stat st; - unsigned port; - int opt; - int exitcode; - int killsig; -/* -fuser [OPTIONS] FILE or PORT/PROTO -Find processes which use FILEs or PORTs - -m Find processes which use same fs as FILEs - -4 Search only IPv4 space - -6 Search only IPv6 space - -s Don't display PIDs - -k Kill found processes - -SIGNAL Signal to send (default: KILL) -*/ - /* Handle -SIGNAL. Oh my... */ - killsig = SIGKILL; /* yes, the default is not SIGTERM */ - pp = argv; - while (*++pp) { - char *arg = *pp; - if (arg[0] != '-') - continue; - if (arg[1] == '-' && arg[2] == '\0') /* "--" */ - break; - if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') - continue; /* it's "-4" or "-6" */ - opt = get_signum(&arg[1]); - if (opt < 0) - continue; - /* "-SIGNAL" option found. Remove it and bail out */ - killsig = opt; - do { - pp[0] = arg = pp[1]; - pp++; - } while (arg); - break; - } - - opt_complementary = "-1"; /* at least one param */ - opt = getopt32(argv, OPTION_STRING); - argv += optind; - - pp = argv; - while (*pp) { - /* parse net arg */ - char path[20], tproto[5]; - if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) - goto file; - sprintf(path, "/proc/net/%s", tproto); - if (access(path, R_OK) == 0) { /* PORT/PROTO */ - scan_proc_net(path, port); - } else { /* FILE */ - file: - xstat(*pp, &st); - add_inode(&st); - } - pp++; - } - - scan_proc_pids(); /* changes dir to "/proc" */ - - mypid = getpid(); - plist = G.pid_list_head; - while (1) { - if (!plist) - return EXIT_FAILURE; - if (plist->pid != mypid) - break; - plist = plist->next; - } - - exitcode = EXIT_SUCCESS; - do { - if (plist->pid != mypid) { - if (opt & OPT_KILL) { - if (kill(plist->pid, killsig) != 0) { - bb_perror_msg("kill pid %u", (unsigned)plist->pid); - exitcode = EXIT_FAILURE; - } - } - if (!(opt & OPT_SILENT)) { - printf("%u ", (unsigned)plist->pid); - } - } - plist = plist->next; - } while (plist); - - if (!(opt & (OPT_SILENT))) { - bb_putchar('\n'); - } - - return exitcode; -} +/* vi: set sw=4 ts=4: */ +/* + * tiny fuser implementation + * + * Copyright 2004 Tony J. White + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//usage:#define fuser_trivial_usage +//usage: "[OPTIONS] FILE or PORT/PROTO" +//usage:#define fuser_full_usage "\n\n" +//usage: "Find processes which use FILEs or PORTs\n" +//usage: "\n -m Find processes which use same fs as FILEs" +//usage: "\n -4,-6 Search only IPv4/IPv6 space" +//usage: "\n -s Don't display PIDs" +//usage: "\n -k Kill found processes" +//usage: "\n -SIGNAL Signal to send (default: KILL)" + +#include "libbb.h" + +#define MAX_LINE 255 + +#define OPTION_STRING "mks64" +enum { + OPT_MOUNT = (1 << 0), + OPT_KILL = (1 << 1), + OPT_SILENT = (1 << 2), + OPT_IP6 = (1 << 3), + OPT_IP4 = (1 << 4), +}; + +typedef struct inode_list { + struct inode_list *next; + ino_t inode; + dev_t dev; +} inode_list; + +struct globals { + int recursion_depth; + pid_t mypid; + inode_list *inode_list_head; + smallint kill_failed; + int killsig; +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { \ + G.mypid = getpid(); \ + G.killsig = SIGKILL; \ +} while (0) + +static void add_inode(const struct stat *st) +{ + inode_list **curr = &G.inode_list_head; + + while (*curr) { + if ((*curr)->dev == st->st_dev + && (*curr)->inode == st->st_ino + ) { + return; + } + curr = &(*curr)->next; + } + + *curr = xzalloc(sizeof(inode_list)); + (*curr)->dev = st->st_dev; + (*curr)->inode = st->st_ino; +} + +static smallint search_dev_inode(const struct stat *st) +{ + inode_list *ilist = G.inode_list_head; + + while (ilist) { + if (ilist->dev == st->st_dev) { + if (option_mask32 & OPT_MOUNT) + return 1; + if (ilist->inode == st->st_ino) + return 1; + } + ilist = ilist->next; + } + return 0; +} + +enum { + PROC_NET = 0, + PROC_DIR, + PROC_DIR_LINKS, + PROC_SUBDIR_LINKS, +}; + +static smallint scan_proc_net_or_maps(const char *path, unsigned port) +{ + FILE *f; + char line[MAX_LINE + 1], addr[68]; + int major, minor, r; + long long uint64_inode; + unsigned tmp_port; + smallint retval; + struct stat statbuf; + const char *fmt; + void *fag, *sag; + + f = fopen_for_read(path); + if (!f) + return 0; + + if (G.recursion_depth == PROC_NET) { + int fd; + + /* find socket dev */ + statbuf.st_dev = 0; + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd >= 0) { + fstat(fd, &statbuf); + close(fd); + } + + fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x " + "%*x:%*x %*x:%*x %*x %*d %*d %llu"; + fag = addr; + sag = &tmp_port; + } else { + fmt = "%*s %*s %*s %x:%x %llu"; + fag = &major; + sag = &minor; + } + + retval = 0; + while (fgets(line, MAX_LINE, f)) { + r = sscanf(line, fmt, fag, sag, &uint64_inode); + if (r != 3) + continue; + + statbuf.st_ino = uint64_inode; + if (G.recursion_depth == PROC_NET) { + r = strlen(addr); + if (r == 8 && (option_mask32 & OPT_IP6)) + continue; + if (r > 8 && (option_mask32 & OPT_IP4)) + continue; + if (tmp_port == port) + add_inode(&statbuf); + } else { + if (major != 0 && minor != 0 && statbuf.st_ino != 0) { + statbuf.st_dev = makedev(major, minor); + retval = search_dev_inode(&statbuf); + if (retval) + break; + } + } + } + fclose(f); + + return retval; +} + +static smallint scan_recursive(const char *path) +{ + DIR *d; + struct dirent *d_ent; + smallint stop_scan; + smallint retval; + + d = opendir(path); + if (d == NULL) + return 0; + + G.recursion_depth++; + retval = 0; + stop_scan = 0; + while (!stop_scan && (d_ent = readdir(d)) != NULL) { + struct stat statbuf; + pid_t pid; + char *subpath; + + subpath = concat_subpath_file(path, d_ent->d_name); + if (subpath == NULL) + continue; /* . or .. */ + + switch (G.recursion_depth) { + case PROC_DIR: + pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10); + if (errno != 0 + || pid == G.mypid + /* "this PID doesn't use specified FILEs or PORT/PROTO": */ + || scan_recursive(subpath) == 0 + ) { + break; + } + if (option_mask32 & OPT_KILL) { + if (kill(pid, G.killsig) != 0) { + bb_perror_msg("kill pid %s", d_ent->d_name); + G.kill_failed = 1; + } + } + if (!(option_mask32 & OPT_SILENT)) + printf("%s ", d_ent->d_name); + retval = 1; + break; + + case PROC_DIR_LINKS: + switch ( + index_in_substrings( + "cwd" "\0" "exe" "\0" + "root" "\0" "fd" "\0" + "lib" "\0" "mmap" "\0" + "maps" "\0", + d_ent->d_name + ) + ) { + enum { + CWD_LINK, + EXE_LINK, + ROOT_LINK, + FD_DIR_LINKS, + LIB_DIR_LINKS, + MMAP_DIR_LINKS, + MAPS, + }; + case CWD_LINK: + case EXE_LINK: + case ROOT_LINK: + goto scan_link; + case FD_DIR_LINKS: + case LIB_DIR_LINKS: + case MMAP_DIR_LINKS: + stop_scan = scan_recursive(subpath); + if (stop_scan) + retval = stop_scan; + break; + case MAPS: + stop_scan = scan_proc_net_or_maps(subpath, 0); + if (stop_scan) + retval = stop_scan; + default: + break; + } + break; + case PROC_SUBDIR_LINKS: + scan_link: + if (stat(subpath, &statbuf) < 0) + break; + stop_scan = search_dev_inode(&statbuf); + if (stop_scan) + retval = stop_scan; + default: + break; + } + free(subpath); + } + closedir(d); + G.recursion_depth--; + return retval; +} + +int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fuser_main(int argc UNUSED_PARAM, char **argv) +{ + char **pp; + + INIT_G(); + + /* Handle -SIGNAL. Oh my... */ + pp = argv; + while (*++pp) { + int sig; + char *arg = *pp; + + if (arg[0] != '-') + continue; + if (arg[1] == '-' && arg[2] == '\0') /* "--" */ + break; + if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') + continue; /* it's "-4" or "-6" */ + sig = get_signum(&arg[1]); + if (sig < 0) + continue; + /* "-SIGNAL" option found. Remove it and bail out */ + G.killsig = sig; + do { + pp[0] = arg = pp[1]; + pp++; + } while (arg); + break; + } + + opt_complementary = "-1"; /* at least one param */ + getopt32(argv, OPTION_STRING); + argv += optind; + + pp = argv; + while (*pp) { + /* parse net arg */ + unsigned port; + char path[sizeof("/proc/net/TCP6")]; + + strcpy(path, "/proc/net/"); + if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2 + && access(path, R_OK) == 0 + ) { + /* PORT/PROTO */ + scan_proc_net_or_maps(path, port); + } else { + /* FILE */ + struct stat statbuf; + xstat(*pp, &statbuf); + add_inode(&statbuf); + } + pp++; + } + + if (scan_recursive("/proc")) { + if (!(option_mask32 & OPT_SILENT)) + bb_putchar('\n'); + return G.kill_failed; + } + + return EXIT_FAILURE; +} diff --git a/release/src/router/busybox/procps/iostat.c b/release/src/router/busybox/procps/iostat.c index a9ff13a058..978d234305 100644 --- a/release/src/router/busybox/procps/iostat.c +++ b/release/src/router/busybox/procps/iostat.c @@ -7,25 +7,24 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_IOSTAT(APPLET(iostat, _BB_DIR_BIN, _BB_SUID_DROP)) - -//kbuild:lib-$(CONFIG_IOSTAT) += iostat.o - //config:config IOSTAT //config: bool "iostat" //config: default y //config: help //config: Report CPU and I/O statistics +//applet:IF_IOSTAT(APPLET(iostat, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_IOSTAT) += iostat.o + #include "libbb.h" -#include /* Need struct utsname */ +#include /* struct utsname */ //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define debug(fmt, ...) ((void)0) #define MAX_DEVICE_NAME 12 -#define CURRENT 0 -#define LAST 1 +#define MAX_DEVICE_NAME_STR "12" #if 1 typedef unsigned long long cputime_t; @@ -39,44 +38,65 @@ typedef long icputime_t; # define CPUTIME_MAX (~0UL) #endif -struct stats_cpu { - cputime_t cpu_user; - cputime_t cpu_nice; - cputime_t cpu_system; - cputime_t cpu_idle; - cputime_t cpu_iowait; - cputime_t cpu_steal; - cputime_t cpu_irq; - cputime_t cpu_softirq; - cputime_t cpu_guest; +enum { + STATS_CPU_USER, + STATS_CPU_NICE, + STATS_CPU_SYSTEM, + STATS_CPU_IDLE, + STATS_CPU_IOWAIT, + STATS_CPU_IRQ, + STATS_CPU_SOFTIRQ, + STATS_CPU_STEAL, + STATS_CPU_GUEST, + + GLOBAL_UPTIME, + SMP_UPTIME, + + N_STATS_CPU, }; -struct stats_dev { - char dname[MAX_DEVICE_NAME]; +typedef struct { + cputime_t vector[N_STATS_CPU]; +} stats_cpu_t; + +typedef struct { + stats_cpu_t *prev; + stats_cpu_t *curr; + cputime_t itv; +} stats_cpu_pair_t; + +typedef struct { unsigned long long rd_sectors; unsigned long long wr_sectors; unsigned long rd_ops; unsigned long wr_ops; -}; +} stats_dev_data_t; -/* List of devices entered on the command line */ -struct device_list { - char dname[MAX_DEVICE_NAME]; -}; +typedef struct stats_dev { + struct stats_dev *next; + char dname[MAX_DEVICE_NAME + 1]; + stats_dev_data_t prev_data; + stats_dev_data_t curr_data; +} stats_dev_t; /* Globals. Sort by size and access frequency. */ struct globals { smallint show_all; - unsigned devlist_i; /* Index to the list of devices */ unsigned total_cpus; /* Number of CPUs */ unsigned clk_tck; /* Number of clock ticks per second */ - struct device_list *dlist; - struct stats_dev *saved_stats_dev; + llist_t *dev_name_list; /* List of devices entered on the command line */ + stats_dev_t *stats_dev_list; struct tm tmtime; + struct { + const char *str; + unsigned div; + } unit; }; #define G (*ptr_to_globals) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + G.unit.str = "Blk"; \ + G.unit.div = 1; \ } while (0) /* Must match option string! */ @@ -101,15 +121,15 @@ static ALWAYS_INLINE int this_is_smp(void) static void print_header(void) { - char buf[16]; + char buf[32]; struct utsname uts; - if (uname(&uts) < 0) - bb_perror_msg_and_die("uname"); + uname(&uts); /* never fails */ + /* Date representation for the current locale */ strftime(buf, sizeof(buf), "%x", &G.tmtime); - printf("%s %s (%s) \t%s \t_%s_\t(%d CPU)\n\n", + printf("%s %s (%s) \t%s \t_%s_\t(%u CPU)\n\n", uts.sysname, uts.release, uts.nodename, buf, uts.machine, G.total_cpus); } @@ -123,62 +143,63 @@ static void get_localtime(struct tm *ptm) static void print_timestamp(void) { - char buf[20]; + char buf[64]; + /* %x: date representation for the current locale */ + /* %X: time representation for the current locale */ strftime(buf, sizeof(buf), "%x %X", &G.tmtime); printf("%s\n", buf); } -/* Fetch CPU statistics from /proc/stat */ -static void get_cpu_statistics(struct stats_cpu *sc) +static cputime_t get_smp_uptime(void) { FILE *fp; - char buf[1024]; - - fp = xfopen_for_read("/proc/stat"); + unsigned long sec, dec; - memset(sc, 0, sizeof(*sc)); + fp = xfopen_for_read("/proc/uptime"); - while (fgets(buf, sizeof(buf), fp)) { - /* Does the line starts with "cpu "? */ - if (starts_with_cpu(buf) && buf[3] == ' ') { - sscanf(buf + 4 + 1, - "%"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %" - FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u", - &sc->cpu_user, &sc->cpu_nice, &sc->cpu_system, - &sc->cpu_idle, &sc->cpu_iowait, &sc->cpu_irq, - &sc->cpu_softirq, &sc->cpu_steal, &sc->cpu_guest); - } - } + if (fscanf(fp, "%lu.%lu", &sec, &dec) != 2) + bb_error_msg_and_die("can't read '%s'", "/proc/uptime"); fclose(fp); + + return (cputime_t)sec * G.clk_tck + dec * G.clk_tck / 100; } -static cputime_t get_smp_uptime(void) +/* Fetch CPU statistics from /proc/stat */ +static void get_cpu_statistics(stats_cpu_t *sc) { FILE *fp; - char buf[sizeof(long)*3 * 2 + 4]; - unsigned long sec, dec; + char buf[1024]; - fp = xfopen_for_read("/proc/uptime"); + fp = xfopen_for_read("/proc/stat"); - if (fgets(buf, sizeof(buf), fp)) - if (sscanf(buf, "%lu.%lu", &sec, &dec) != 2) - bb_error_msg_and_die("can't read /proc/uptime"); + memset(sc, 0, sizeof(*sc)); - fclose(fp); + while (fgets(buf, sizeof(buf), fp)) { + int i; + char *ibuf; - return (cputime_t)sec * G.clk_tck + dec * G.clk_tck / 100; -} + /* Does the line start with "cpu "? */ + if (!starts_with_cpu(buf) || buf[3] != ' ') { + continue; + } + ibuf = buf + 4; + for (i = STATS_CPU_USER; i <= STATS_CPU_GUEST; i++) { + ibuf = skip_whitespace(ibuf); + sscanf(ibuf, "%"FMT_DATA"u", &sc->vector[i]); + if (i != STATS_CPU_GUEST) { + sc->vector[GLOBAL_UPTIME] += sc->vector[i]; + } + ibuf = skip_non_whitespace(ibuf); + } + break; + } -/* - * Obtain current uptime in jiffies. - * Uptime is sum of individual CPUs' uptimes. - */ -static cputime_t get_uptime(const struct stats_cpu *sc) -{ - /* NB: Don't include cpu_guest, it is already in cpu_user */ - return sc->cpu_user + sc->cpu_nice + sc->cpu_system + sc->cpu_idle + - + sc->cpu_iowait + sc->cpu_irq + sc->cpu_steal + sc->cpu_softirq; + if (this_is_smp()) { + sc->vector[SMP_UPTIME] = get_smp_uptime(); + } + + fclose(fp); } static ALWAYS_INLINE cputime_t get_interval(cputime_t old, cputime_t new) @@ -219,65 +240,55 @@ static double percent_value(cputime_t prev, cputime_t curr, cputime_t itv) return ((double)overflow_safe_sub(prev, curr)) / itv * 100; } -static void print_stats_cpu_struct(const struct stats_cpu *p, - const struct stats_cpu *c, cputime_t itv) +static void print_stats_cpu_struct(stats_cpu_pair_t *stats) { - printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", - percent_value(p->cpu_user , c->cpu_user , itv), - percent_value(p->cpu_nice , c->cpu_nice , itv), - percent_value(p->cpu_system + p->cpu_softirq + p->cpu_irq, - c->cpu_system + c->cpu_softirq + c->cpu_irq, itv), - percent_value(p->cpu_iowait , c->cpu_iowait , itv), - percent_value(p->cpu_steal , c->cpu_steal , itv), - percent_value(p->cpu_idle , c->cpu_idle , itv) + cputime_t *p = stats->prev->vector; + cputime_t *c = stats->curr->vector; + printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", + percent_value(p[STATS_CPU_USER] , c[STATS_CPU_USER] , stats->itv), + percent_value(p[STATS_CPU_NICE] , c[STATS_CPU_NICE] , stats->itv), + percent_value(p[STATS_CPU_SYSTEM] + p[STATS_CPU_SOFTIRQ] + p[STATS_CPU_IRQ], + c[STATS_CPU_SYSTEM] + c[STATS_CPU_SOFTIRQ] + c[STATS_CPU_IRQ], stats->itv), + percent_value(p[STATS_CPU_IOWAIT], c[STATS_CPU_IOWAIT], stats->itv), + percent_value(p[STATS_CPU_STEAL] , c[STATS_CPU_STEAL] , stats->itv), + percent_value(p[STATS_CPU_IDLE] , c[STATS_CPU_IDLE] , stats->itv) ); } -static void print_stats_dev_struct(const struct stats_dev *p, - const struct stats_dev *c, cputime_t itv) +static void cpu_report(stats_cpu_pair_t *stats) { - int unit = 1; + /* Always print a header */ + puts("avg-cpu: %user %nice %system %iowait %steal %idle"); - if (option_mask32 & OPT_k) - unit = 2; - else if (option_mask32 & OPT_m) - unit = 2048; + /* Print current statistics */ + print_stats_cpu_struct(stats); +} +static void print_stats_dev_struct(stats_dev_t *stats_dev, cputime_t itv) +{ + stats_dev_data_t *p = &stats_dev->prev_data; + stats_dev_data_t *c = &stats_dev->curr_data; if (option_mask32 & OPT_z) if (p->rd_ops == c->rd_ops && p->wr_ops == c->wr_ops) return; - printf("%-13s", c->dname); - printf(" %8.2f %12.2f %12.2f %10llu %10llu \n", - percent_value(p->rd_ops + p->wr_ops , - /**/ c->rd_ops + c->wr_ops , itv), - percent_value(p->rd_sectors, c->rd_sectors, itv) / unit, - percent_value(p->wr_sectors, c->wr_sectors, itv) / unit, - (c->rd_sectors - p->rd_sectors) / unit, - (c->wr_sectors - p->wr_sectors) / unit); -} - -static void cpu_report(const struct stats_cpu *last, - const struct stats_cpu *cur, - cputime_t itv) -{ - /* Always print a header */ - puts("avg-cpu: %user %nice %system %iowait %steal %idle"); - - /* Print current statistics */ - print_stats_cpu_struct(last, cur, itv); + printf("%-13s %8.2f %12.2f %12.2f %10llu %10llu\n", + stats_dev->dname, + percent_value(p->rd_ops + p->wr_ops, c->rd_ops + c->wr_ops, itv), + percent_value(p->rd_sectors, c->rd_sectors, itv) / G.unit.div, + percent_value(p->wr_sectors, c->wr_sectors, itv) / G.unit.div, + (c->rd_sectors - p->rd_sectors) / G.unit.div, + (c->wr_sectors - p->wr_sectors) / G.unit.div + ); } static void print_devstat_header(void) { - printf("Device: tps"); - - if (option_mask32 & OPT_m) - puts(" MB_read/s MB_wrtn/s MB_read MB_wrtn"); - else if (option_mask32 & OPT_k) - puts(" kB_read/s kB_wrtn/s kB_read kB_wrtn"); - else - puts(" Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn"); + printf("Device:%15s%6s%s/s%6s%s/s%6s%s%6s%s\n", + "tps", + G.unit.str, "_read", G.unit.str, "_wrtn", + G.unit.str, "_read", G.unit.str, "_wrtn" + ); } /* @@ -289,92 +300,81 @@ static int is_partition(const char *dev) return ((dev[0] - 's') | (dev[1] - 'd') | (dev[2] - 'a')) == 0 && isdigit(dev[3]); } -/* - * Return number of numbers on cmdline. - * Reasonable values are only 0 (no interval/count specified), - * 1 (interval specified) and 2 (both interval and count specified) - */ -static int numbers_on_cmdline(int argc, char *argv[]) +static stats_dev_t *stats_dev_find_or_new(const char *dev_name) { - int sum = 0; + stats_dev_t **curr = &G.stats_dev_list; - if (isdigit(argv[argc-1][0])) - sum++; - if (argc > 2 && isdigit(argv[argc-2][0])) - sum++; + while (*curr != NULL) { + if (strcmp((*curr)->dname, dev_name) == 0) + return *curr; + curr = &(*curr)->next; + } - return sum; + *curr = xzalloc(sizeof(stats_dev_t)); + strncpy((*curr)->dname, dev_name, MAX_DEVICE_NAME); + return *curr; } -static int is_dev_in_dlist(const char *dev) +static void stats_dev_free(stats_dev_t *stats_dev) { - int i; - - /* Go through the device list */ - for (i = 0; i < G.devlist_i; i++) - if (strcmp(G.dlist[i].dname, dev) == 0) - /* Found a match */ - return 1; - - /* No match found */ - return 0; + if (stats_dev) { + stats_dev_free(stats_dev->next); + free(stats_dev); + } } static void do_disk_statistics(cputime_t itv) { + char buf[128]; + char dev_name[MAX_DEVICE_NAME + 1]; + unsigned long long rd_sec_or_dummy; + unsigned long long wr_sec_or_dummy; + stats_dev_data_t *curr_data; + stats_dev_t *stats_dev; FILE *fp; int rc; - int i = 0; - char buf[128]; - unsigned major, minor; - unsigned long wr_ops, dummy; /* %*lu for suppress the conversion wouldn't work */ - unsigned long long rd_sec_or_wr_ops; - unsigned long long rd_sec_or_dummy, wr_sec_or_dummy, wr_sec; - struct stats_dev sd; fp = xfopen_for_read("/proc/diskstats"); - /* Read and possibly print stats from /proc/diskstats */ while (fgets(buf, sizeof(buf), fp)) { - rc = sscanf(buf, "%u %u %s %lu %llu %llu %llu %lu %lu %llu %lu %lu %lu %lu", - &major, &minor, sd.dname, &sd.rd_ops, - &rd_sec_or_dummy, &rd_sec_or_wr_ops, &wr_sec_or_dummy, - &wr_ops, &dummy, &wr_sec, &dummy, &dummy, &dummy, &dummy); - - switch (rc) { - case 14: - sd.wr_ops = wr_ops; - sd.rd_sectors = rd_sec_or_wr_ops; - sd.wr_sectors = wr_sec; - break; - case 7: - sd.rd_sectors = rd_sec_or_dummy; - sd.wr_ops = (unsigned long)rd_sec_or_wr_ops; - sd.wr_sectors = wr_sec_or_dummy; - break; - default: - break; + sscanf(buf, "%*s %*s %"MAX_DEVICE_NAME_STR"s", dev_name); + if (G.dev_name_list) { + /* Is device name in list? */ + if (!llist_find_str(G.dev_name_list, dev_name)) + continue; + } else if (is_partition(dev_name)) { + continue; } - if (!G.devlist_i && !is_partition(sd.dname)) { - /* User didn't specify device */ - if (!G.show_all && !sd.rd_ops && !sd.wr_ops) { - /* Don't print unused device */ - continue; - } - print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); - G.saved_stats_dev[i] = sd; - i++; - } else { - /* Is device in device list? */ - if (is_dev_in_dlist(sd.dname)) { - /* Print current statistics */ - print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); - G.saved_stats_dev[i] = sd; - i++; - } else - continue; + stats_dev = stats_dev_find_or_new(dev_name); + curr_data = &stats_dev->curr_data; + + rc = sscanf(buf, "%*s %*s %*s %lu %llu %llu %llu %lu %*s %llu", + &curr_data->rd_ops, + &rd_sec_or_dummy, + &curr_data->rd_sectors, + &wr_sec_or_dummy, + &curr_data->wr_ops, + &curr_data->wr_sectors); + if (rc != 6) { + curr_data->rd_sectors = rd_sec_or_dummy; + curr_data->wr_sectors = wr_sec_or_dummy; + //curr_data->rd_ops = ; + curr_data->wr_ops = (unsigned long)curr_data->rd_sectors; + } + + if (!G.dev_name_list /* User didn't specify device */ + && !G.show_all + && curr_data->rd_ops == 0 + && curr_data->wr_ops == 0 + ) { + /* Don't print unused device */ + continue; } + + /* Print current statistics */ + print_stats_dev_struct(stats_dev, itv); + stats_dev->prev_data = *curr_data; } fclose(fp); @@ -389,74 +389,10 @@ static void dev_report(cputime_t itv) do_disk_statistics(itv); } -static void save_to_devlist(const char *dname) -{ - int i; - struct device_list *tmp = G.dlist; - - if (strncmp(dname, "/dev/", 5) == 0) - /* We'll ignore prefix '/dev/' */ - dname += 5; - - /* Go through the list */ - for (i = 0; i < G.devlist_i; i++, tmp++) - if (strcmp(tmp->dname, dname) == 0) - /* Already in the list */ - return; - - /* Add device name to the list */ - strncpy(tmp->dname, dname, MAX_DEVICE_NAME - 1); - - /* Update device list index */ - G.devlist_i++; -} - -static unsigned get_number_of_devices(void) -{ - FILE *fp; - char buf[128]; - int rv; - unsigned n = 0; - unsigned long rd_ops, wr_ops; - char dname[MAX_DEVICE_NAME]; - - fp = xfopen_for_read("/proc/diskstats"); - - while (fgets(buf, sizeof(buf), fp)) { - rv = sscanf(buf, "%*d %*d %s %lu %*u %*u %*u %lu", - dname, &rd_ops, &wr_ops); - if (rv == 2 || is_partition(dname)) - /* A partition */ - continue; - if (!rd_ops && !wr_ops) { - /* Unused device */ - if (!G.show_all) - continue; - } - n++; - } - - fclose(fp); - return n; -} - -static int number_of_ALL_on_cmdline(char **argv) -{ - int alls = 0; - - /* Iterate over cmd line arguments, count "ALL" */ - while (*argv) - if (strcmp(*argv++, "ALL") == 0) - alls++; - - return alls; -} - //usage:#define iostat_trivial_usage //usage: "[-c] [-d] [-t] [-z] [-k|-m] [ALL|BLOCKDEV...] [INTERVAL [COUNT]]" //usage:#define iostat_full_usage "\n\n" //usage: "Report CPU and I/O statistics\n" -//usage: "\nOptions:" //usage: "\n -c Show CPU utilization" //usage: "\n -d Show device utilization" //usage: "\n -t Print current time" @@ -465,19 +401,17 @@ static int number_of_ALL_on_cmdline(char **argv) //usage: "\n -m Use Mb/s" int iostat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int iostat_main(int argc, char **argv) +int iostat_main(int argc UNUSED_PARAM, char **argv) { - int opt, dev_num; - unsigned interval = 0; + int opt; + unsigned interval; int count; - cputime_t global_uptime[2] = { 0 }; - cputime_t smp_uptime[2] = { 0 }; - cputime_t itv; - struct stats_cpu stats_cur, stats_last; + stats_cpu_t stats_data[2]; + smallint current_stats; INIT_G(); - memset(&stats_last, 0, sizeof(stats_last)); + memset(&stats_data, 0, sizeof(stats_data)); /* Get number of clock ticks per sec */ G.clk_tck = get_user_hz(); @@ -496,25 +430,22 @@ int iostat_main(int argc, char **argv) opt |= OPT_c + OPT_d; argv += optind; - argc -= optind; - - dev_num = argc - numbers_on_cmdline(argc, argv); - /* We don't want to allocate space for 'ALL' */ - dev_num -= number_of_ALL_on_cmdline(argv); - if (dev_num > 0) - /* Make space for device list */ - G.dlist = xzalloc(sizeof(G.dlist[0]) * dev_num); /* Store device names into device list */ while (*argv && !isdigit(*argv[0])) { - if (strcmp(*argv, "ALL") != 0) + if (strcmp(*argv, "ALL") != 0) { /* If not ALL, save device name */ - save_to_devlist(*argv); - else + char *dev_name = skip_dev_pfx(*argv); + if (!llist_find_str(G.dev_name_list, dev_name)) { + llist_add_to(&G.dev_name_list, dev_name); + } + } else { G.show_all = 1; + } argv++; } + interval = 0; count = 1; if (*argv) { /* Get interval */ @@ -526,35 +457,46 @@ int iostat_main(int argc, char **argv) count = xatoi_positive(*argv); } - /* Allocate space for device stats */ - if (opt & OPT_d) { - G.saved_stats_dev = xzalloc(sizeof(G.saved_stats_dev[0]) * - (dev_num ? dev_num : get_number_of_devices()) - ); + if (opt & OPT_m) { + G.unit.str = " MB"; + G.unit.div = 2048; } + if (opt & OPT_k) { + G.unit.str = " kB"; + G.unit.div = 2; + } + + get_localtime(&G.tmtime); + /* Display header */ print_header(); + current_stats = 0; /* Main loop */ for (;;) { + stats_cpu_pair_t stats; + + stats.prev = &stats_data[current_stats ^ 1]; + stats.curr = &stats_data[current_stats]; + /* Fill the time structure */ get_localtime(&G.tmtime); /* Fetch current CPU statistics */ - get_cpu_statistics(&stats_cur); - - /* Fetch current uptime */ - global_uptime[CURRENT] = get_uptime(&stats_cur); + get_cpu_statistics(stats.curr); /* Get interval */ - itv = get_interval(global_uptime[LAST], global_uptime[CURRENT]); + stats.itv = get_interval( + stats.prev->vector[GLOBAL_UPTIME], + stats.curr->vector[GLOBAL_UPTIME] + ); if (opt & OPT_t) print_timestamp(); if (opt & OPT_c) { - cpu_report(&stats_last, &stats_cur, itv); + cpu_report(&stats); if (opt & OPT_d) /* Separate outputs by a newline */ bb_putchar('\n'); @@ -562,32 +504,31 @@ int iostat_main(int argc, char **argv) if (opt & OPT_d) { if (this_is_smp()) { - smp_uptime[CURRENT] = get_smp_uptime(); - itv = get_interval(smp_uptime[LAST], smp_uptime[CURRENT]); - smp_uptime[LAST] = smp_uptime[CURRENT]; + stats.itv = get_interval( + stats.prev->vector[SMP_UPTIME], + stats.curr->vector[SMP_UPTIME] + ); } - dev_report(itv); + dev_report(stats.itv); } + bb_putchar('\n'); + if (count > 0) { if (--count == 0) break; } - /* Backup current stats */ - global_uptime[LAST] = global_uptime[CURRENT]; - stats_last = stats_cur; + /* Swap stats */ + current_stats ^= 1; - bb_putchar('\n'); sleep(interval); } - bb_putchar('\n'); - if (ENABLE_FEATURE_CLEAN_UP) { + llist_free(G.dev_name_list, NULL); + stats_dev_free(G.stats_dev_list); free(&G); - free(G.dlist); - free(G.saved_stats_dev); } return EXIT_SUCCESS; diff --git a/release/src/router/busybox/procps/kill.c b/release/src/router/busybox/procps/kill.c index b51d44a70a..cd189bcd61 100644 --- a/release/src/router/busybox/procps/kill.c +++ b/release/src/router/busybox/procps/kill.c @@ -8,6 +8,42 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define kill_trivial_usage +//usage: "[-l] [-SIG] PID..." +//usage:#define kill_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to given PIDs\n" +//usage: "\n -l List all signal names and numbers" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ +//usage: +//usage:#define kill_example_usage +//usage: "$ ps | grep apache\n" +//usage: "252 root root S [apache]\n" +//usage: "263 www-data www-data S [apache]\n" +//usage: "264 www-data www-data S [apache]\n" +//usage: "265 www-data www-data S [apache]\n" +//usage: "266 www-data www-data S [apache]\n" +//usage: "267 www-data www-data S [apache]\n" +//usage: "$ kill 252\n" +//usage: +//usage:#define killall_trivial_usage +//usage: "[-l] [-q] [-SIG] PROCESS_NAME..." +//usage:#define killall_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to given processes\n" +//usage: "\n -l List all signal names and numbers" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ +//usage: "\n -q Don't complain if no processes were killed" +//usage: +//usage:#define killall_example_usage +//usage: "$ killall apache\n" +//usage: +//usage:#define killall5_trivial_usage +//usage: "[-l] [-SIG] [-o PID]..." +//usage:#define killall5_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to all processes outside current session\n" +//usage: "\n -l List all signal names and numbers" +//usage: "\n -o PID Don't signal this PID" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ + #include "libbb.h" /* Note: kill_main is directly called from shell in order to implement @@ -127,15 +163,18 @@ int kill_main(int argc, char **argv) /* Find out our session id */ sid = getsid(pid); /* Stop all processes */ - kill(-1, SIGSTOP); + if (signo != SIGSTOP && signo != SIGCONT) + kill(-1, SIGSTOP); /* Signal all processes except those in our session */ - while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { + while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) { int i; if (p->sid == (unsigned)sid || p->pid == (unsigned)pid - || p->pid == 1) + || p->pid == 1 + ) { continue; + } /* All remaining args must be -o PID options. * Check p->pid against them. */ @@ -165,7 +204,8 @@ int kill_main(int argc, char **argv) } resume: /* And let them continue */ - kill(-1, SIGCONT); + if (signo != SIGSTOP && signo != SIGCONT) + kill(-1, SIGCONT); return ret; } @@ -206,9 +246,29 @@ int kill_main(int argc, char **argv) /* Looks like they want to do a kill. Do that */ while (arg) { - /* Support shell 'space' trick */ - if (arg[0] == ' ') - arg++; +#if ENABLE_ASH || ENABLE_HUSH + /* + * We need to support shell's "hack formats" of + * " -PRGP_ID" (yes, with a leading space) + * and " PID1 PID2 PID3" (with degenerate case "") + */ + while (*arg != '\0') { + char *end; + if (*arg == ' ') + arg++; + pid = bb_strtoi(arg, &end, 10); + if (errno && (errno != EINVAL || *end != ' ')) { + bb_error_msg("invalid number '%s'", arg); + errors++; + break; + } + if (kill(pid, signo) != 0) { + bb_perror_msg("can't kill pid %d", (int)pid); + errors++; + } + arg = end; /* can only point to ' ' or '\0' now */ + } +#else pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); @@ -217,6 +277,7 @@ int kill_main(int argc, char **argv) bb_perror_msg("can't kill pid %d", (int)pid); errors++; } +#endif arg = *++argv; } return errors; diff --git a/release/src/router/busybox/procps/lsof.c b/release/src/router/busybox/procps/lsof.c new file mode 100644 index 0000000000..7e0ffa4e5e --- /dev/null +++ b/release/src/router/busybox/procps/lsof.c @@ -0,0 +1,76 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini lsof implementation for busybox + * + * Copyright (C) 2012 by Sven Oliver 'SvOlli' Moll + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config LSOF +//config: bool "lsof" +//config: default y +//config: help +//config: Show open files in the format of: +//config: PID /path/to/executable /path/to/opened/file + +//applet:IF_LSOF(APPLET(lsof, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_LSOF) += lsof.o + +//usage:#define lsof_trivial_usage +//usage: "" +//usage:#define lsof_full_usage "\n\n" +//usage: "Show all open files" + +#include "libbb.h" + +/* + * Examples of "standard" lsof output: + * + * COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME + * init 1 root cwd DIR 8,5 4096 2 / + * init 1 root rtd DIR 8,5 4096 2 / + * init 1 root txt REG 8,5 872400 63408 /app/busybox-1.19.2/busybox + * rpc.portm 1064 root mem REG 8,5 43494 47451 /app/glibc-2.11/lib/libnss_files-2.11.so + * rpc.portm 1064 root 3u IPv4 2178 UDP *:111 + * rpc.portm 1064 root 4u IPv4 1244 TCP *:111 (LISTEN) + * runsvdir 1116 root 0r CHR 1,3 1214 /dev/null + * runsvdir 1116 root 1w CHR 1,3 1214 /dev/null + * runsvdir 1116 root 2w CHR 1,3 1214 /dev/null + * runsvdir 1116 root 3r DIR 8,6 1560 58359 /.local/var/service + * gpm 1128 root 4u unix 0xffff88007c09ccc0 1302 /dev/gpmctl + */ + +int lsof_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int lsof_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + procps_status_t *proc = NULL; + + while ((proc = procps_scan(proc, PSSCAN_PID|PSSCAN_EXE)) != NULL) { + char name[sizeof("/proc/%u/fd/0123456789") + sizeof(int)*3]; + unsigned baseofs; + DIR *d_fd; + char *fdlink; + struct dirent *entry; + + if (getpid() == proc->pid) + continue; + + baseofs = sprintf(name, "/proc/%u/fd/", proc->pid); + d_fd = opendir(name); + if (d_fd) { + while ((entry = readdir(d_fd)) != NULL) { + if (entry->d_type == DT_LNK) { + safe_strncpy(name + baseofs, entry->d_name, 10); + fdlink = xmalloc_readlink(name); + printf("%d\t%s\t%s\n", proc->pid, proc->exe, fdlink); + free(fdlink); + } + } + closedir(d_fd); + } + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/procps/mpstat.c b/release/src/router/busybox/procps/mpstat.c index 25efedf628..aa5a5c73f2 100644 --- a/release/src/router/busybox/procps/mpstat.c +++ b/release/src/router/busybox/procps/mpstat.c @@ -7,7 +7,7 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_MPSTAT(APPLET(mpstat, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o @@ -36,11 +36,10 @@ * We are printing headers in the " IRQNAME/s" form, experimentally * anything smaller than 10 chars looks ugly for /proc/softirqs stats. */ -#define INTRATE_SCRWIDTH 10 +#define INTRATE_SCRWIDTH 10 #define INTRATE_SCRWIDTH_STR "10" /* System files */ -#define SYSFS_DEVCPU "/sys/devices/system/cpu" #define PROCFS_STAT "/proc/stat" #define PROCFS_INTERRUPTS "/proc/interrupts" #define PROCFS_SOFTIRQS "/proc/softirqs" @@ -845,7 +844,6 @@ static int get_irqcpu_nr(const char *f, int max_irqs) //usage: "[-A] [-I SUM|CPU|ALL|SCPU] [-u] [-P num|ALL] [INTERVAL [COUNT]]" //usage:#define mpstat_full_usage "\n\n" //usage: "Per-processor statistics\n" -//usage: "\nOptions:" //usage: "\n -A Same as -I ALL -u -P ALL" //usage: "\n -I SUM|CPU|ALL|SCPU Report interrupt statistics" //usage: "\n -P num|ALL Processor to monitor" diff --git a/release/src/router/busybox/procps/nmeter.c b/release/src/router/busybox/procps/nmeter.c index 7836a90d51..ed54790248 100644 --- a/release/src/router/busybox/procps/nmeter.c +++ b/release/src/router/busybox/procps/nmeter.c @@ -6,6 +6,40 @@ * Contact me: vda.linux@googlemail.com */ +//config:config NMETER +//config: bool "nmeter" +//config: default y +//config: help +//config: Prints selected system stats continuously, one line per update. + +//applet:IF_NMETER(APPLET(nmeter, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NMETER) += nmeter.o + +//usage:#define nmeter_trivial_usage +//usage: "[-d MSEC] FORMAT_STRING" +//usage:#define nmeter_full_usage "\n\n" +//usage: "Monitor system in real time" +//usage: "\n" +//usage: "\n -d MSEC Milliseconds between updates (default:1000)" +//usage: "\n" +//usage: "\nFormat specifiers:" +//usage: "\n %Nc or %[cN] CPU. N - bar size (default:10)" +//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" +//usage: "\n %[nINTERFACE] Network INTERFACE" +//usage: "\n %m Allocated memory" +//usage: "\n %[mf] Free memory" +//usage: "\n %[mt] Total memory" +//usage: "\n %s Allocated swap" +//usage: "\n %f Number of used file descriptors" +//usage: "\n %Ni Total/specific IRQ rate" +//usage: "\n %x Context switch rate" +//usage: "\n %p Forks" +//usage: "\n %[pn] # of processes" +//usage: "\n %b Block io" +//usage: "\n %Nt Time (with N decimal points)" +//usage: "\n %r Print instead of at EOL" + //TODO: // simplify code // /proc/locks @@ -240,30 +274,56 @@ static int rdval_loadavg(const char* p, ullong *vec, ...) // 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 // 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933 // 3 1 hda1 0 0 0 0 <- ignore if only 4 fields +// Linux 3.0 (maybe earlier) started printing full stats for hda1 too. +// Had to add code which skips such devices. static int rdval_diskstats(const char* p, ullong *vec) { - ullong rd = rd; // for compiler - int indexline = 0; + char devname[32]; + unsigned devname_len = 0; + int value_idx = 0; + vec[0] = 0; vec[1] = 0; while (1) { - indexline++; - while (*p == ' ' || *p == '\t') p++; - if (*p == '\0') break; + value_idx++; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\0') + break; if (*p == '\n') { - indexline = 0; + value_idx = 0; p++; continue; } - if (indexline == 6) { - rd = strtoull(p, NULL, 10); - } else if (indexline == 10) { - vec[0] += rd; // TODO: *sectorsize (don't know how to find out sectorsize) + if (value_idx == 3) { + char *end = strchrnul(p, ' '); + /* If this a hda1-like device (same prefix as last one + digit)? */ + if (devname_len && strncmp(devname, p, devname_len) == 0 && isdigit(p[devname_len])) { + p = end; + goto skip_line; /* skip entire line */ + } + /* It is not. Remember the name for future checks */ + devname_len = end - p; + if (devname_len > sizeof(devname)-1) + devname_len = sizeof(devname)-1; + strncpy(devname, p, devname_len); + /* devname[devname_len] = '\0'; - not really needed */ + p = end; + } else + if (value_idx == 6) { + // TODO: *sectorsize (don't know how to find out sectorsize) + vec[0] += strtoull(p, NULL, 10); + } else + if (value_idx == 10) { + // TODO: *sectorsize (don't know how to find out sectorsize) vec[1] += strtoull(p, NULL, 10); - while (*p != '\n' && *p != '\0') p++; + skip_line: + while (*p != '\n' && *p != '\0') + p++; continue; } - while (*p > ' ') p++; // skip over value + while ((unsigned char)(*p) > ' ') // skip over value + p++; } return 0; } @@ -769,6 +829,7 @@ static void FAST_FUNC collect_info(s_stat *s) typedef s_stat* init_func(const char *param); +// Deprecated %NNNd is to be removed, -d MSEC supersedes it static const char options[] ALIGN1 = "ncmsfixptbdr"; static init_func *const init_functions[] = { init_if, @@ -792,23 +853,28 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv) s_stat *first = NULL; s_stat *last = NULL; s_stat *s; + char *opt_d; char *cur, *prev; INIT_G(); xchdir("/proc"); - if (!argv[1]) - bb_show_usage(); - if (open_read_close("version", buf, sizeof(buf)-1) > 0) { buf[sizeof(buf)-1] = '\0'; is26 = (strstr(buf, " 2.4.") == NULL); } - // Can use argv[1] directly, but this will mess up + if (getopt32(argv, "d:", &opt_d)) + init_delay(opt_d); + argv += optind; + + if (!argv[0]) + bb_show_usage(); + + // Can use argv[0] directly, but this will mess up // parameters as seen by e.g. ps. Making a copy... - cur = xstrdup(argv[1]); + cur = xstrdup(argv[0]); while (1) { char *param, *p; prev = cur; diff --git a/release/src/router/busybox/procps/pgrep.c b/release/src/router/busybox/procps/pgrep.c index 5d388a87d9..dc7ffff486 100644 --- a/release/src/router/busybox/procps/pgrep.c +++ b/release/src/router/busybox/procps/pgrep.c @@ -6,6 +6,33 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define pgrep_trivial_usage +//usage: "[-flnovx] [-s SID|-P PPID|PATTERN]" +//usage:#define pgrep_full_usage "\n\n" +//usage: "Display process(es) selected by regex PATTERN\n" +//usage: "\n -l Show command name too" +//usage: "\n -f Match against entire command line" +//usage: "\n -n Show the newest process only" +//usage: "\n -o Show the oldest process only" +//usage: "\n -v Negate the match" +//usage: "\n -x Match whole name (not substring)" +//usage: "\n -s Match session ID (0 for current)" +//usage: "\n -P Match parent process ID" +//usage: +//usage:#define pkill_trivial_usage +//usage: "[-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]" +//usage:#define pkill_full_usage "\n\n" +//usage: "Send a signal to process(es) selected by regex PATTERN\n" +//usage: "\n -l List all signals" +//usage: "\n -f Match against entire command line" +//usage: "\n -n Signal the newest process only" +//usage: "\n -o Signal the oldest process only" +//usage: "\n -v Negate the match" +//usage: "\n -x Match whole name (not substring)" +//usage: "\n -s Match session ID (0 for current)" +//usage: "\n -P Match parent process ID" + #include "libbb.h" #include "xregex.h" @@ -101,7 +128,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); if (argv[0]) - xregcomp(&re_buffer, argv[0], 0); + xregcomp(&re_buffer, argv[0], REG_EXTENDED | REG_NOSUB); matched_pid = 0; cmd_last = NULL; diff --git a/release/src/router/busybox/procps/pidof.c b/release/src/router/busybox/procps/pidof.c index 49e469ca5e..6d7b591093 100644 --- a/release/src/router/busybox/procps/pidof.c +++ b/release/src/router/busybox/procps/pidof.c @@ -7,6 +7,34 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) +//usage:#define pidof_trivial_usage +//usage: "[OPTIONS] [NAME]..." +//usage:#define USAGE_PIDOF "\n" +//usage:#else +//usage:#define pidof_trivial_usage +//usage: "[NAME]..." +//usage:#define USAGE_PIDOF /* none */ +//usage:#endif +//usage:#define pidof_full_usage "\n\n" +//usage: "List PIDs of all processes with names that match NAMEs" +//usage: USAGE_PIDOF +//usage: IF_FEATURE_PIDOF_SINGLE( +//usage: "\n -s Show only one PID" +//usage: ) +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "\n -o PID Omit given pid" +//usage: "\n Use %PPID to omit pid of pidof's parent" +//usage: ) +//usage: +//usage:#define pidof_example_usage +//usage: "$ pidof init\n" +//usage: "1\n" +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "$ pidof /bin/sh\n20351 5973 5950\n") +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "$ pidof /bin/sh -o %PPID\n20351 5950") + #include "libbb.h" enum { diff --git a/release/src/router/busybox/procps/pmap.c b/release/src/router/busybox/procps/pmap.c index bb5f9e7c21..fd995a54d2 100644 --- a/release/src/router/busybox/procps/pmap.c +++ b/release/src/router/busybox/procps/pmap.c @@ -8,22 +8,22 @@ * for details. */ -//applet:IF_PMAP(APPLET(pmap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//kbuild:lib-$(CONFIG_PMAP) += pmap.o - //config:config PMAP //config: bool "pmap" //config: default y //config: help //config: Display processes' memory mappings. +//applet:IF_PMAP(APPLET(pmap, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_PMAP) += pmap.o + //usage:#define pmap_trivial_usage -//usage: "[-x][-q] PID" +//usage: "[-xq] PID" //usage:#define pmap_full_usage "\n\n" -//usage: "Display detailed precesses' memory usage\n" -//usage: "\nOptions:" -//usage: "\n -x show details" -//usage: "\n -q quiet" +//usage: "Display detailed process memory usage" +//usage: "\n" +//usage: "\n -x Show details" +//usage: "\n -q Quiet" #include "libbb.h" diff --git a/release/src/router/busybox/procps/powertop.c b/release/src/router/busybox/procps/powertop.c index 2f977a03bd..008cdfca4e 100644 --- a/release/src/router/busybox/procps/powertop.c +++ b/release/src/router/busybox/procps/powertop.c @@ -9,7 +9,7 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_POWERTOP(APPLET(powertop, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_POWERTOP) += powertop.o @@ -393,11 +393,9 @@ static NOINLINE int process_timer_stats(void) char buf[128]; char line[15 + 3 + 128]; int n; - ullong totalticks; FILE *fp; buf[0] = '\0'; - totalticks = 0; n = 0; fp = NULL; diff --git a/release/src/router/busybox/procps/ps.c b/release/src/router/busybox/procps/ps.c index 48b55a7858..3a5af7c186 100644 --- a/release/src/router/busybox/procps/ps.c +++ b/release/src/router/busybox/procps/ps.c @@ -9,26 +9,118 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#if ENABLE_DESKTOP +//usage: +//usage:#define ps_trivial_usage +//usage: "[-o COL1,COL2=HEADER]" IF_FEATURE_SHOW_THREADS(" [-T]") +//usage:#define ps_full_usage "\n\n" +//usage: "Show list of processes\n" +//usage: "\n -o COL1,COL2=HEADER Select columns for display" +//usage: IF_FEATURE_SHOW_THREADS( +//usage: "\n -T Show threads" +//usage: ) +//usage: +//usage:#else /* !ENABLE_DESKTOP */ +//usage: +//usage:#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE +//usage:#define USAGE_PS "\nThis version of ps accepts no options" +//usage:#else +//usage:#define USAGE_PS "" +//usage:#endif +//usage: +//usage:#define ps_trivial_usage +//usage: "" +//usage:#define ps_full_usage "\n\n" +//usage: "Show list of processes\n" +//usage: USAGE_PS +//usage: IF_SELINUX( +//usage: "\n -Z Show selinux context" +//usage: ) +//usage: IF_FEATURE_PS_WIDE( +//usage: "\n w Wide output" +//usage: ) +//usage: IF_FEATURE_PS_LONG( +//usage: "\n l Long output" +//usage: ) +//usage: IF_FEATURE_SHOW_THREADS( +//usage: "\n T Show threads" +//usage: ) +//usage: +//usage:#endif /* ENABLE_DESKTOP */ +//usage: +//usage:#define ps_example_usage +//usage: "$ ps\n" +//usage: " PID Uid Gid State Command\n" +//usage: " 1 root root S init\n" +//usage: " 2 root root S [kflushd]\n" +//usage: " 3 root root S [kupdate]\n" +//usage: " 4 root root S [kpiod]\n" +//usage: " 5 root root S [kswapd]\n" +//usage: " 742 andersen andersen S [bash]\n" +//usage: " 743 andersen andersen S -bash\n" +//usage: " 745 root root S [getty]\n" +//usage: " 2990 andersen andersen R ps\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif /* Absolute maximum on output line length */ enum { MAX_WIDTH = 2*1024 }; +#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG +static long get_uptime(void) +{ +#ifdef __linux__ + struct sysinfo info; + if (sysinfo(&info) < 0) + return 0; + return info.uptime; +#elif 1 + char buf[64]; + long uptime; + if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) + bb_perror_msg_and_die("can't read %s", "/proc/uptime"); + buf[sizeof(buf)-1] = '\0'; + sscanf(buf, "%l", &uptime); + return uptime; +#else + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) + return 0; + return ts.tv_sec; +#endif +} +#endif + #if ENABLE_DESKTOP #include /* for times() */ #ifndef AT_CLKTCK -#define AT_CLKTCK 17 -#endif - - -#if ENABLE_SELINUX -#define SELINUX_O_PREFIX "label," -#define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") -#else -#define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") +# define AT_CLKTCK 17 #endif +/* TODO: + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html + * specifies (for XSI-conformant systems) following default columns + * (l and f mark columns shown with -l and -f respectively): + * F l Flags (octal and additive) associated with the process (??) + * S l The state of the process + * UID f,l The user ID; the login name is printed with -f + * PID The process ID + * PPID f,l The parent process + * C f,l Processor utilization + * PRI l The priority of the process; higher numbers mean lower priority + * NI l Nice value + * ADDR l The address of the process + * SZ l The size in blocks of the core image of the process + * WCHAN l The event for which the process is waiting or sleeping + * STIME f Starting time of the process + * TTY The controlling terminal for the process + * TIME The cumulative execution time for the process + * CMD The command name; the full command line is shown with -f + */ typedef struct { uint16_t width; char name6[6]; @@ -48,7 +140,6 @@ struct globals { unsigned kernel_HZ; unsigned long long seconds_since_boot; #endif - char default_o[sizeof(DEFAULT_O_STR)]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define out (G.out ) @@ -59,7 +150,6 @@ struct globals { #define terminal_width (G.terminal_width ) #define kernel_HZ (G.kernel_HZ ) #define seconds_since_boot (G.seconds_since_boot) -#define default_o (G.default_o ) #define INIT_G() do { } while (0) #if ENABLE_FEATURE_PS_TIME @@ -68,7 +158,8 @@ static ptrdiff_t find_elf_note(ptrdiff_t findme) { ptrdiff_t *ep = (ptrdiff_t *) environ; - while (*ep++); + while (*ep++) + continue; while (*ep) { if (ep[0] == findme) { return ep[1]; @@ -131,8 +222,6 @@ static inline unsigned get_HZ_by_waiting(void) static unsigned get_kernel_HZ(void) { - //char buf[64]; - struct sysinfo info; if (kernel_HZ) return kernel_HZ; @@ -142,12 +231,7 @@ static unsigned get_kernel_HZ(void) if (kernel_HZ == (unsigned)-1) kernel_HZ = get_HZ_by_waiting(); - //if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) - // bb_perror_msg_and_die("can't read %s", "/proc/uptime"); - //buf[sizeof(buf)-1] = '\0'; - ///sscanf(buf, "%llu", &seconds_since_boot); - sysinfo(&info); - seconds_since_boot = info.uptime; + seconds_since_boot = get_uptime(); return kernel_HZ; } @@ -184,6 +268,11 @@ static void func_comm(char *buf, int size, const procps_status_t *ps) safe_strncpy(buf, ps->comm, size+1); } +static void func_state(char *buf, int size, const procps_status_t *ps) +{ + safe_strncpy(buf, ps->state, size+1); +} + static void func_args(char *buf, int size, const procps_status_t *ps) { read_cmdline(buf, size+1, ps->pid, ps->comm); @@ -300,7 +389,7 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps) */ static const ps_out_t out_spec[] = { -// Mandated by POSIX: +/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, @@ -322,7 +411,8 @@ static const ps_out_t out_spec[] = { #endif { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, -// Not mandated by POSIX, but useful: +/* Not mandated, but useful: */ + { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, #if ENABLE_SELINUX { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, @@ -459,11 +549,19 @@ static void format_process(const procps_status_t *ps) printf("%.*s\n", terminal_width, buffer); } +#if ENABLE_SELINUX +# define SELINUX_O_PREFIX "label," +# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") +#else +# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") +#endif + int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ps_main(int argc UNUSED_PARAM, char **argv) { procps_status_t *p; llist_t* opt_o = NULL; + char default_o[sizeof(DEFAULT_O_STR)]; int opt; enum { OPT_Z = (1 << 0), @@ -501,7 +599,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) parse_o(llist_pop(&opt_o)); } while (opt_o); } else { - /* Below: parse_o() needs char*, NOT const char*... */ + /* Below: parse_o() needs char*, NOT const char*, can't give it default_o */ #if ENABLE_SELINUX if (!(opt & OPT_Z) || !is_selinux_enabled()) { /* no -Z or no SELinux: do not show LABEL */ @@ -551,15 +649,21 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) enum { OPT_Z = (1 << 0) * ENABLE_SELINUX, OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, + OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG, }; +#if ENABLE_FEATURE_PS_LONG + time_t now = now; + long uptime; +#endif int opts = 0; /* If we support any options, parse argv */ -#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE +#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG # if ENABLE_FEATURE_PS_WIDE /* -w is a bit complicated */ int w_count = 0; opt_complementary = "-:ww"; - opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); + opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") + "w", &w_count); /* if w is given once, GNU ps sets the width to 132, * if w is given more than once, it is "unlimited" */ @@ -574,23 +678,51 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) # else /* -w is not supported, only -Z and/or -T */ opt_complementary = "-"; - opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); + opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); # endif -#endif -#if ENABLE_SELINUX +# if ENABLE_SELINUX if ((opts & OPT_Z) && is_selinux_enabled()) { psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT | PSSCAN_STATE | PSSCAN_COMM; puts(" PID CONTEXT STAT COMMAND"); } else +# endif + if (opts & OPT_l) { + psscan_flags = PSSCAN_STATE | PSSCAN_UIDGID | PSSCAN_PID | PSSCAN_PPID + | PSSCAN_TTY | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_COMM + | PSSCAN_VSZ | PSSCAN_RSS; +/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html + * mandates for -l: + * -F Flags (?) + * S State + * UID,PID,PPID + * -C CPU usage + * -PRI The priority of the process; higher numbers mean lower priority + * -NI Nice value + * -ADDR The address of the process (?) + * SZ The size in blocks of the core image + * -WCHAN The event for which the process is waiting or sleeping + * TTY + * TIME The cumulative execution time + * CMD + * We don't show fields marked with '-'. + * We show VSZ and RSS instead of SZ. + * We also show STIME (standard says that -f shows it, -l doesn't). + */ + puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD"); +#if ENABLE_FEATURE_PS_LONG + now = time(NULL); + uptime = get_uptime(); #endif - { + } + else { puts(" PID USER VSZ STAT COMMAND"); } if (opts & OPT_T) { psscan_flags |= PSSCAN_TASKS; } +#endif p = NULL; while ((p = procps_scan(p, psscan_flags)) != NULL) { @@ -604,15 +736,49 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } else #endif { - const char *user = get_cached_username(p->uid); - //if (p->vsz == 0) - // len = printf("%5u %-8.8s %s ", - // p->pid, user, p->state); - //else + char buf6[6]; + smart_ulltoa5(p->vsz, buf6, " mgtpezy"); + buf6[5] = '\0'; +#if ENABLE_FEATURE_PS_LONG + if (opts & OPT_l) { + char bufr[6], stime_str[6]; + char tty[2 * sizeof(int)*3 + 2]; + char *endp; + unsigned sut = (p->stime + p->utime) / 100; + unsigned elapsed = uptime - (p->start_time / 100); + time_t start = now - elapsed; + struct tm *tm = localtime(&start); + + smart_ulltoa5(p->rss, bufr, " mgtpezy"); + bufr[5] = '\0'; + + if (p->tty_major == 136) + /* It should be pts/N, not ptsN, but N > 9 + * will overflow field width... + */ + endp = stpcpy(tty, "pts"); + else + if (p->tty_major == 4) { + endp = stpcpy(tty, "tty"); + if (p->tty_minor >= 64) { + p->tty_minor -= 64; + *endp++ = 'S'; + } + } + else + endp = tty + sprintf(tty, "%d:", p->tty_major); + strcpy(endp, utoa(p->tty_minor)); + + strftime(stime_str, 6, (elapsed >= (24 * 60 * 60)) ? "%b%d" : "%H:%M", tm); + stime_str[5] = '\0'; + // S UID PID PPID VSZ RSS TTY STIME TIME CMD + len = printf("%c %5u %5u %5u %5s %5s %-5s %s %02u:%02u:%02u ", + p->state[0], p->uid, p->pid, p->ppid, buf6, bufr, tty, + stime_str, sut / 3600, (sut % 3600) / 60, sut % 60); + } else +#endif { - char buf6[6]; - smart_ulltoa5(p->vsz, buf6, " mgtpezy"); - buf6[5] = '\0'; + const char *user = get_cached_username(p->uid); len = printf("%5u %-8.8s %s %s ", p->pid, user, buf6, p->state); } diff --git a/release/src/router/busybox/procps/pstree.c b/release/src/router/busybox/procps/pstree.c new file mode 100644 index 0000000000..8ba30795dc --- /dev/null +++ b/release/src/router/busybox/procps/pstree.c @@ -0,0 +1,407 @@ +/* + * pstree.c - display process tree + * + * Copyright (C) 1993-2002 Werner Almesberger + * Copyright (C) 2002-2009 Craig Small + * Copyright (C) 2010 Lauri Kasanen + * + * Based on pstree (PSmisc) 22.13. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config PSTREE +//config: bool "pstree" +//config: default y +//config: help +//config: Display a tree of processes. + +//applet:IF_PSTREE(APPLET(pstree, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PSTREE) += pstree.o + +//usage:#define pstree_trivial_usage +//usage: "[-p] [PID|USER]" +//usage:#define pstree_full_usage "\n\n" +//usage: "Display process tree, optionally start from USER or PID\n" +//usage: "\n -p Show pids" + +#include "libbb.h" + +#define PROC_BASE "/proc" + +#define OPT_PID (1 << 0) + +struct child; + +typedef struct proc { + char comm[COMM_LEN + 1]; +// char flags; - unused, delete? + pid_t pid; + uid_t uid; + struct child *children; + struct proc *parent; + struct proc *next; +} PROC; + +/* For flags above */ +//#define PFLAG_THREAD 0x01 + +typedef struct child { + PROC *child; + struct child *next; +} CHILD; + +#define empty_2 " " +#define branch_2 "|-" +#define vert_2 "| " +#define last_2 "`-" +#define single_3 "---" +#define first_3 "-+-" + +struct globals { + /* 0-based. IOW: the number of chars we printed on current line */ + unsigned cur_x; + unsigned output_width; + + /* The buffers will be dynamically increased in size as needed */ + unsigned capacity; + unsigned *width; + uint8_t *more; + + PROC *list; + + smallint dumped; /* used by dump_by_user */ +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + + +/* + * Allocates additional buffer space for width and more as needed. + * The first call will allocate the first buffer. + * + * bufindex the index that will be used after the call to this function. + */ +static void ensure_buffer_capacity(int bufindex) +{ + if (bufindex >= G.capacity) { + G.capacity += 0x100; + G.width = xrealloc(G.width, G.capacity * sizeof(G.width[0])); + G.more = xrealloc(G.more, G.capacity * sizeof(G.more[0])); + } +} + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_char(char c) +{ + G.cur_x++; + if (G.cur_x > G.output_width) + return; + if (G.cur_x == G.output_width) + c = '+'; + putchar(c); +} + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_string(const char *str) +{ + while (*str) + out_char(*str++); +} + +static void out_newline(void) +{ + putchar('\n'); + G.cur_x = 0; +} + +static PROC *find_proc(pid_t pid) +{ + PROC *walk; + + for (walk = G.list; walk; walk = walk->next) + if (walk->pid == pid) + break; + + return walk; +} + +static PROC *new_proc(const char *comm, pid_t pid, uid_t uid) +{ + PROC *new = xzalloc(sizeof(*new)); + + strcpy(new->comm, comm); + new->pid = pid; + new->uid = uid; + new->next = G.list; + + G.list = new; + return G.list; +} + +static void add_child(PROC *parent, PROC *child) +{ + CHILD *new, **walk; + int cmp; + + new = xmalloc(sizeof(*new)); + + new->child = child; + for (walk = &parent->children; *walk; walk = &(*walk)->next) { + cmp = strcmp((*walk)->child->comm, child->comm); + if (cmp > 0) + break; + if (cmp == 0 && (*walk)->child->uid > child->uid) + break; + } + new->next = *walk; + *walk = new; +} + +static void add_proc(const char *comm, pid_t pid, pid_t ppid, + uid_t uid /*, char isthread*/) +{ + PROC *this, *parent; + + this = find_proc(pid); + if (!this) + this = new_proc(comm, pid, uid); + else { + strcpy(this->comm, comm); + this->uid = uid; + } + + if (pid == ppid) + ppid = 0; +// if (isthread) +// this->flags |= PFLAG_THREAD; + + parent = find_proc(ppid); + if (!parent) + parent = new_proc("?", ppid, 0); + + add_child(parent, this); + this->parent = parent; +} + +static int tree_equal(const PROC *a, const PROC *b) +{ + const CHILD *walk_a, *walk_b; + + if (strcmp(a->comm, b->comm) != 0) + return 0; + if ((option_mask32 /*& OPT_PID*/) && a->pid != b->pid) + return 0; + + for (walk_a = a->children, walk_b = b->children; + walk_a && walk_b; + walk_a = walk_a->next, walk_b = walk_b->next + ) { + if (!tree_equal(walk_a->child, walk_b->child)) + return 0; + } + + return !(walk_a || walk_b); +} + +static int out_args(const char *mystr) +{ + const char *here; + int strcount = 0; + char tmpstr[5]; + + for (here = mystr; *here; here++) { + if (*here == '\\') { + out_string("\\\\"); + strcount += 2; + } else if (*here >= ' ' && *here < 0x7f) { + out_char(*here); + strcount++; + } else { + sprintf(tmpstr, "\\%03o", (unsigned char) *here); + out_string(tmpstr); + strcount += 4; + } + } + + return strcount; +} + +static void +dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) +{ + CHILD *walk, *next, **scan; + int lvl, i, add, offset, count, comm_len, first; + char tmp[sizeof(int)*3 + 4]; + + if (!current) + return; + + if (!leaf) { + for (lvl = 0; lvl < level; lvl++) { + i = G.width[lvl] + 1; + while (--i >= 0) + out_char(' '); + + if (lvl == level - 1) { + if (last) { + out_string(last_2); + } else { + out_string(branch_2); + } + } else { + if (G.more[lvl + 1]) { + out_string(vert_2); + } else { + out_string(empty_2); + } + } + } + } + + add = 0; + if (rep > 1) { + add += sprintf(tmp, "%d*[", rep); + out_string(tmp); + } + comm_len = out_args(current->comm); + if (option_mask32 /*& OPT_PID*/) { + comm_len += sprintf(tmp, "(%d)", (int)current->pid); + out_string(tmp); + } + offset = G.cur_x; + + if (!current->children) { + while (closing--) + out_char(']'); + out_newline(); + } + ensure_buffer_capacity(level); + G.more[level] = !last; + + G.width[level] = comm_len + G.cur_x - offset + add; + if (G.cur_x >= G.output_width) { + //out_string(first_3); - why? it won't print anything + //out_char('+'); + out_newline(); + return; + } + + first = 1; + for (walk = current->children; walk; walk = next) { + count = 0; + next = walk->next; + scan = &walk->next; + while (*scan) { + if (!tree_equal(walk->child, (*scan)->child)) + scan = &(*scan)->next; + else { + if (next == *scan) + next = (*scan)->next; + count++; + *scan = (*scan)->next; + } + } + if (first) { + out_string(next ? first_3 : single_3); + first = 0; + } + + dump_tree(walk->child, level + 1, count + 1, + walk == current->children, !next, + closing + (count ? 1 : 0)); + } +} + +static void dump_by_user(PROC *current, uid_t uid) +{ + const CHILD *walk; + + if (!current) + return; + + if (current->uid == uid) { + if (G.dumped) + putchar('\n'); + dump_tree(current, 0, 1, 1, 1, 0); + G.dumped = 1; + return; + } + for (walk = current->children; walk; walk = walk->next) + dump_by_user(walk->child, uid); +} + +#if ENABLE_FEATURE_SHOW_THREADS +static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid) +{ + char threadname[COMM_LEN + 2]; + sprintf(threadname, "{%.*s}", COMM_LEN - 2, comm); + add_proc(threadname, pid, ppid, uid/*, 1*/); +} +#endif + +static void mread_proc(void) +{ + procps_status_t *p = NULL; + pid_t parent = 0; + int flags = PSSCAN_COMM | PSSCAN_PID | PSSCAN_PPID | PSSCAN_UIDGID | PSSCAN_TASKS; + + while ((p = procps_scan(p, flags)) != NULL) { +#if ENABLE_FEATURE_SHOW_THREADS + if (p->pid != p->main_thread_pid) + handle_thread(p->comm, p->pid, parent, p->uid); + else +#endif + { + add_proc(p->comm, p->pid, p->ppid, p->uid/*, 0*/); + parent = p->pid; + } + } +} + +int pstree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pstree_main(int argc UNUSED_PARAM, char **argv) +{ + pid_t pid = 1; + long uid = 0; + + INIT_G(); + + get_terminal_width_height(0, &G.output_width, NULL); + + opt_complementary = "?1"; + getopt32(argv, "p"); + argv += optind; + + if (argv[0]) { + if (argv[0][0] >= '0' && argv[0][0] <= '9') { + pid = xatoi(argv[0]); + } else { + uid = xuname2uid(argv[0]); + } + } + + mread_proc(); + + if (!uid) + dump_tree(find_proc(pid), 0, 1, 1, 1, 0); + else { + dump_by_user(find_proc(1), uid); + if (!G.dumped) { + bb_error_msg_and_die("no processes found"); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + free(G.width); + free(G.more); + } + return 0; +} diff --git a/release/src/router/busybox/procps/pwdx.c b/release/src/router/busybox/procps/pwdx.c new file mode 100644 index 0000000000..7818104885 --- /dev/null +++ b/release/src/router/busybox/procps/pwdx.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * pwdx implementation for busybox + * + * Copyright (c) 2004 Nicholas Miell + * ported from procps by Pere Orga 2011 + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config PWDX +//config: bool "pwdx" +//config: default y +//config: help +//config: Report current working directory of a process + +//applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PWDX) += pwdx.o + +//usage:#define pwdx_trivial_usage +//usage: "PID..." +//usage:#define pwdx_full_usage "\n\n" +//usage: "Show current directory for PIDs\n" + +#include "libbb.h" + +int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pwdx_main(int argc UNUSED_PARAM, char **argv) +{ + opt_complementary = "-1"; + getopt32(argv, ""); + argv += optind; + + do { + char buf[sizeof("/proc/%u/cwd") + sizeof(int)*3]; + unsigned pid; + char *s; + char *arg = *argv; + + // Allowed on the command line: + // /proc/NUM + // NUM + if (strncmp(arg, "/proc/", 6) == 0) + arg += 6; + + pid = bb_strtou(arg, NULL, 10); + if (errno) + bb_error_msg_and_die("invalid process id: '%s'", arg); + + sprintf(buf, "/proc/%u/cwd", pid); + + s = xmalloc_readlink(buf); + // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" + printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); + free(s); + } while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/procps/renice.c b/release/src/router/busybox/procps/renice.c index 59194b5f4e..77f400a1d6 100644 --- a/release/src/router/busybox/procps/renice.c +++ b/release/src/router/busybox/procps/renice.c @@ -19,6 +19,15 @@ * following IDs (if any). Multiple switches are allowed. */ +//usage:#define renice_trivial_usage +//usage: "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" +//usage:#define renice_full_usage "\n\n" +//usage: "Change scheduling priority for a running process\n" +//usage: "\n -n Adjust current nice value (smaller is faster)" +//usage: "\n -p Process id(s) (default)" +//usage: "\n -g Process group id(s)" +//usage: "\n -u Process user name(s) and/or id(s)" + #include "libbb.h" #include diff --git a/release/src/router/busybox/procps/smemcap.c b/release/src/router/busybox/procps/smemcap.c index 200df67957..9d1126a49a 100644 --- a/release/src/router/busybox/procps/smemcap.c +++ b/release/src/router/busybox/procps/smemcap.c @@ -8,7 +8,7 @@ herein by reference. */ -//applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +//applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o @@ -20,7 +20,7 @@ //config: a memory usage statistic tool. #include "libbb.h" -#include "archive.h" +#include "bb_archive.h" struct fileblock { struct fileblock *next; diff --git a/release/src/router/busybox/procps/sysctl.c b/release/src/router/busybox/procps/sysctl.c index aba966e7f0..5296d0f581 100644 --- a/release/src/router/busybox/procps/sysctl.c +++ b/release/src/router/busybox/procps/sysctl.c @@ -11,6 +11,24 @@ * v1.01.1 - busybox applet aware by */ +//usage:#define sysctl_trivial_usage +//usage: "[OPTIONS] [VALUE]..." +//usage:#define sysctl_full_usage "\n\n" +//usage: "Configure kernel parameters at runtime\n" +//usage: "\n -n Don't print key names" +//usage: "\n -e Don't warn about unknown keys" +//usage: "\n -w Change sysctl setting" +//usage: "\n -p FILE Load sysctl settings from FILE (default /etc/sysctl.conf)" +//usage: "\n -a Display all values" +//usage: "\n -A Display all values in table form" +//usage: +//usage:#define sysctl_example_usage +//usage: "sysctl [-n] [-e] variable...\n" +//usage: "sysctl [-n] [-e] -w variable=value...\n" +//usage: "sysctl [-n] [-e] -a\n" +//usage: "sysctl [-n] [-e] -p file (default /etc/sysctl.conf)\n" +//usage: "sysctl [-n] [-e] -A\n" + #include "libbb.h" enum { @@ -206,7 +224,7 @@ static int sysctl_handle_preload_file(const char *filename) parser = config_open(filename); /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ //TODO: ';' is comment char too //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value @@ -242,7 +260,7 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); } xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { return sysctl_act_recursive("."); } diff --git a/release/src/router/busybox/procps/top.c b/release/src/router/busybox/procps/top.c index f9106fac7a..15eb624cce 100644 --- a/release/src/router/busybox/procps/top.c +++ b/release/src/router/busybox/procps/top.c @@ -19,9 +19,9 @@ * * Sept 2008: Vineet Gupta * Added Support for reporting SMP Information - * - CPU where Process was last seen running + * - CPU where process was last seen running * (to see effect of sched_setaffinity() etc) - * - CPU Time Split (idle/IO/wait etc) PER CPU + * - CPU time split (idle/IO/wait etc) per CPU * * Copyright (c) 1992 Branko Lankester * Copyright (c) 1992 Roger Binns @@ -30,6 +30,25 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ +/* How to snapshot /proc for debugging top problems: + * for f in /proc/[0-9]*""/stat; do + * n=${f#/proc/} + * n=${n%/stat}_stat + * cp $f $n + * done + * cp /proc/stat /proc/meminfo /proc/loadavg . + * top -bn1 >top.out + * + * ...and how to run top on it on another machine: + * rm -rf proc; mkdir proc + * for f in [0-9]*_stat; do + * p=${f%_stat} + * mkdir -p proc/$p + * cp $f proc/$p/stat + * done + * cp stat meminfo loadavg proc + * chroot . ./top -bn1 >top1.out + */ #include "libbb.h" @@ -73,9 +92,9 @@ enum { SORT_DEPTH = 3 }; struct globals { top_status_t *top; int ntop; + smallint inverted; #if ENABLE_FEATURE_TOPMEM smallint sort_field; - smallint inverted; #endif #if ENABLE_FEATURE_TOP_SMP_CPU smallint smp_cpu_info; /* one/many cpu info lines? */ @@ -107,7 +126,6 @@ struct BUG_bad_size { char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; char BUG_line_buf_too_small[LINE_BUF_SIZE > 80 ? 1 : -1]; }; -#define INIT_G() do { } while (0) #define top (G.top ) #define ntop (G.ntop ) #define sort_field (G.sort_field ) @@ -124,6 +142,7 @@ struct BUG_bad_size { #define num_cpus (G.num_cpus ) #define total_pcpu (G.total_pcpu ) #define line_buf (G.line_buf ) +#define INIT_G() do { } while (0) enum { OPT_d = (1 << 0), @@ -175,9 +194,9 @@ static int mult_lvl_cmp(void* a, void* b) for (i = 0; i < SORT_DEPTH; i++) { cmp_val = (*sort_function[i])(a, b); if (cmp_val != 0) - return cmp_val; + break; } - return 0; + return inverted ? -cmp_val : cmp_val; } static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) @@ -519,7 +538,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) /* what info of the processes is shown */ printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width, - " PID PPID USER STAT VSZ %MEM" + " PID PPID USER STAT VSZ %VSZ" IF_FEATURE_TOP_SMP_PROCESS(" CPU") IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") " COMMAND"); @@ -537,7 +556,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) # define FMT "%4u%%" #endif /* - * MEM% = s->vsz/MemTotal + * %VSZ = s->vsz/MemTotal */ pmem_shift = BITS_PER_INT-11; pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory; @@ -546,7 +565,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) pmem_scale /= 4; pmem_shift -= 2; } - pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); + pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE busy_jifs = cur_jif.busy - prev_jif.busy; /* This happens if there were lots of short-lived processes @@ -577,7 +596,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) pcpu_scale /= 4; pcpu_shift -= 2; } - pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); + pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ #endif @@ -597,7 +616,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); else sprintf(vsz_str_buf, "%7ld", s->vsz); - /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */ + /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ col = snprintf(line_buf, scr_width, "\n" "%5u%6u %-8.8s %s%s" FMT IF_FEATURE_TOP_SMP_PROCESS(" %3d") @@ -778,7 +797,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) display_topmem_header(scr_width, &lines_rem); strcpy(line_buf, HDR_STR " COMMAND"); - line_buf[5 + sort_field * 6] = '*'; + line_buf[11 + sort_field * 6] = "^_"[inverted]; printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); lines_rem--; @@ -831,24 +850,173 @@ enum { | PSSCAN_PID | PSSCAN_SMAPS | PSSCAN_COMM, + EXIT_MASK = (unsigned)-1, }; +#if ENABLE_FEATURE_USE_TERMIOS +static unsigned handle_input(unsigned scan_mask, unsigned interval) +{ + unsigned char c; + struct pollfd pfd[1]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; + + while (1) { + if (safe_poll(pfd, 1, interval * 1000) <= 0) + return scan_mask; + interval = 0; + + if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ + option_mask32 |= OPT_EOF; + return scan_mask; + } + + if (c == initial_settings.c_cc[VINTR]) + return EXIT_MASK; + if (c == initial_settings.c_cc[VEOF]) + return EXIT_MASK; + c |= 0x20; /* lowercase */ + if (c == 'q') + return EXIT_MASK; + + if (c == 'n') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = pid_sort; + continue; + } + if (c == 'm') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = mem_sort; +# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + sort_function[1] = pcpu_sort; + sort_function[2] = time_sort; +# endif + continue; + } +# if ENABLE_FEATURE_SHOW_THREADS + if (c == 'h' + IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) + ) { + scan_mask ^= PSSCAN_TASKS; + continue; + } +# endif +# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + if (c == 'p') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = pcpu_sort; + sort_function[1] = mem_sort; + sort_function[2] = time_sort; + continue; + } + if (c == 't') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = time_sort; + sort_function[1] = mem_sort; + sort_function[2] = pcpu_sort; + continue; + } +# if ENABLE_FEATURE_TOPMEM + if (c == 's') { + scan_mask = TOPMEM_MASK; + free(prev_hist); + prev_hist = NULL; + prev_hist_count = 0; + sort_field = (sort_field + 1) % NUM_SORT_FIELD; + continue; + } +# endif + if (c == 'r') { + inverted ^= 1; + continue; + } +# if ENABLE_FEATURE_TOP_SMP_CPU + /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ + if (c == 'c' || c == '1') { + /* User wants to toggle per cpu <> aggregate */ + if (smp_cpu_info) { + free(cpu_prev_jif); + free(cpu_jif); + cpu_jif = &cur_jif; + cpu_prev_jif = &prev_jif; + } else { + /* Prepare for xrealloc() */ + cpu_jif = cpu_prev_jif = NULL; + } + num_cpus = 0; + smp_cpu_info = !smp_cpu_info; + get_jiffy_counts(); + continue; + } +# endif +# endif + break; /* unknown key -> force refresh */ + } + + return scan_mask; +} +#endif + +//usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU +//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) +//usage:#endif +//usage:#define top_trivial_usage +//usage: "[-b] [-nCOUNT] [-dSECONDS]" IF_FEATURE_TOPMEM(" [-m]") +//usage:#define top_full_usage "\n\n" +//usage: "Provide a view of process activity in real time." +//usage: "\n""Read the status of all processes from /proc each SECONDS" +//usage: "\n""and display a screenful of them." +//usage: "\n""Keys:" +//usage: "\n"" N/M" +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/P") +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/T") +//usage: ": " IF_FEATURE_TOPMEM("show CPU usage, ") "sort by pid/mem" +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") +//usage: IF_FEATURE_TOPMEM( +//usage: "\n"" S: show memory" +//usage: ) +//usage: "\n"" R: reverse sort" +//usage: IF_SHOW_THREADS_OR_TOP_SMP( +//usage: "\n"" " +//usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") +//usage: IF_FEATURE_SHOW_THREADS(IF_FEATURE_TOP_SMP_CPU(", ")) +//usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") +//usage: ) +//usage: "\n"" Q,^C: exit" +//usage: "\n" +//usage: "\n""Options:" +//usage: "\n"" -b Batch mode" +//usage: "\n"" -n N Exit after N iterations" +//usage: "\n"" -d N Delay between updates" +//usage: IF_FEATURE_TOPMEM( +//usage: "\n"" -m Same as 's' key" +//usage: ) + +/* Interactive testing: + * echo sss | ./busybox top + * - shows memory screen + * echo sss | ./busybox top -bn1 >mem + * - saves memory screen - the *whole* list, not first NROWS processes! + * echo .m.s.s.s.s.s.s.q | ./busybox top -b >z + * - saves several different screens, and exits + * + * TODO: -i STRING param as a better alternative? + */ + int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int top_main(int argc UNUSED_PARAM, char **argv) { int iterations; unsigned lines, col; - int lines_rem; unsigned interval; char *str_interval, *str_iterations; unsigned scan_mask = TOP_MASK; #if ENABLE_FEATURE_USE_TERMIOS struct termios new_settings; - struct pollfd pfd[1]; - unsigned char c; - - pfd[0].fd = 0; - pfd[0].events = POLLIN; #endif INIT_G(); @@ -885,15 +1053,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) /* change to /proc */ xchdir("/proc"); -#if ENABLE_FEATURE_USE_TERMIOS - tcgetattr(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(new_settings)); - /* unbuffered input, turn off echo */ - new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); - - bb_signals(BB_FATAL_SIGS, sig_catcher); - tcsetattr_stdin_TCSANOW(&new_settings); -#endif #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE sort_function[0] = pcpu_sort; @@ -903,21 +1062,41 @@ int top_main(int argc UNUSED_PARAM, char **argv) sort_function[0] = mem_sort; #endif - while (1) { +#if ENABLE_FEATURE_USE_TERMIOS + tcgetattr(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(new_settings)); + if (!OPT_BATCH_MODE) { + /* unbuffered input, turn off echo */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + tcsetattr_stdin_TCSANOW(&new_settings); + } + + bb_signals(BB_FATAL_SIGS, sig_catcher); + + /* Eat initial input, if any */ + scan_mask = handle_input(scan_mask, 0); +#endif + + while (scan_mask != EXIT_MASK) { procps_status_t *p = NULL; - lines = 24; /* default */ - col = 79; + if (OPT_BATCH_MODE) { + lines = INT_MAX; + col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ + } else { + lines = 24; /* default */ + col = 79; #if ENABLE_FEATURE_USE_TERMIOS - /* We output to stdout, we need size of stdout (not stdin)! */ - get_terminal_width_height(STDOUT_FILENO, &col, &lines); - if (lines < 5 || col < 10) { - sleep(interval); - continue; - } + /* We output to stdout, we need size of stdout (not stdin)! */ + get_terminal_width_height(STDOUT_FILENO, &col, &lines); + if (lines < 5 || col < 10) { + sleep(interval); + continue; + } #endif - if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ - col = LINE_BUF_SIZE-2; + if (col > LINE_BUF_SIZE - 2) + col = LINE_BUF_SIZE - 2; + } /* read process IDs & status for all the processes */ while ((p = procps_scan(p, scan_mask)) != NULL) { @@ -985,15 +1164,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); } #endif - lines_rem = lines; - if (OPT_BATCH_MODE) { - lines_rem = INT_MAX; - } if (scan_mask != TOPMEM_MASK) - display_process_list(lines_rem, col); + display_process_list(lines, col); #if ENABLE_FEATURE_TOPMEM else - display_topmem_process_list(lines_rem, col); + display_topmem_process_list(lines, col); #endif clearmems(); if (iterations >= 0 && !--iterations) @@ -1001,84 +1176,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) #if !ENABLE_FEATURE_USE_TERMIOS sleep(interval); #else - if (option_mask32 & (OPT_b|OPT_EOF)) - /* batch mode, or EOF on stdin ("top 0) { - if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ - option_mask32 |= OPT_EOF; - continue; - } - if (c == initial_settings.c_cc[VINTR]) - break; - c |= 0x20; /* lowercase */ - if (c == 'q') - break; - if (c == 'n') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = pid_sort; - } - if (c == 'm') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = mem_sort; -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - sort_function[1] = pcpu_sort; - sort_function[2] = time_sort; -# endif - } -# if ENABLE_FEATURE_SHOW_THREADS - if (c == 'h' - IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) - ) { - scan_mask ^= PSSCAN_TASKS; - } -# endif -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - if (c == 'p') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = pcpu_sort; - sort_function[1] = mem_sort; - sort_function[2] = time_sort; - } - if (c == 't') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = time_sort; - sort_function[1] = mem_sort; - sort_function[2] = pcpu_sort; - } -# if ENABLE_FEATURE_TOPMEM - if (c == 's') { - scan_mask = TOPMEM_MASK; - free(prev_hist); - prev_hist = NULL; - prev_hist_count = 0; - sort_field = (sort_field + 1) % NUM_SORT_FIELD; - } - if (c == 'r') - inverted ^= 1; -# endif -# if ENABLE_FEATURE_TOP_SMP_CPU - /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ - if (c == 'c' || c == '1') { - /* User wants to toggle per cpu <> aggregate */ - if (smp_cpu_info) { - free(cpu_prev_jif); - free(cpu_jif); - cpu_jif = &cur_jif; - cpu_prev_jif = &prev_jif; - } else { - /* Prepare for xrealloc() */ - cpu_jif = cpu_prev_jif = NULL; - } - num_cpus = 0; - smp_cpu_info = !smp_cpu_info; - get_jiffy_counts(); - } -# endif -# endif - } + else + scan_mask = handle_input(scan_mask, interval); #endif /* FEATURE_USE_TERMIOS */ - } /* end of "while (1)" */ + } /* end of "while (not Q)" */ bb_putchar('\n'); #if ENABLE_FEATURE_USE_TERMIOS diff --git a/release/src/router/busybox/procps/uptime.c b/release/src/router/busybox/procps/uptime.c index 5c48795bf2..778812a6f5 100644 --- a/release/src/router/busybox/procps/uptime.c +++ b/release/src/router/busybox/procps/uptime.c @@ -7,28 +7,56 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -/* This version of uptime doesn't display the number of users on the system, - * since busybox init doesn't mess with utmp. For folks using utmp that are - * just dying to have # of users reported, feel free to write it as some type - * of CONFIG_FEATURE_UTMP_SUPPORT #define +/* 2011 Pere Orga + * + * Added FEATURE_UPTIME_UTMP_SUPPORT flag. */ /* getopt not needed */ +//config:config UPTIME +//config: bool "uptime" +//config: default y +//config: select PLATFORM_LINUX #sysinfo() +//config: help +//config: uptime gives a one line display of the current time, how long +//config: the system has been running, how many users are currently logged +//config: on, and the system load averages for the past 1, 5, and 15 minutes. +//config: +//config:config FEATURE_UPTIME_UTMP_SUPPORT +//config: bool "Support for showing the number of users" +//config: default y +//config: depends on UPTIME && FEATURE_UTMP +//config: help +//config: Makes uptime display the number of users currently logged on. + +//usage:#define uptime_trivial_usage +//usage: "" +//usage:#define uptime_full_usage "\n\n" +//usage: "Display the time since the last boot" +//usage: +//usage:#define uptime_example_usage +//usage: "$ uptime\n" +//usage: " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif + #ifndef FSHIFT # define FSHIFT 16 /* nr of bits of precision */ #endif -#define FIXED_1 (1<> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) +#define FIXED_1 (1 << FSHIFT) /* 1.0 as fixed-point */ +#define LOAD_INT(x) (unsigned)((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1 - 1)) * 100) int uptime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uptime_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - int updays, uphours, upminutes; + unsigned updays, uphours, upminutes; struct sysinfo info; struct tm *current_time; time_t current_secs; @@ -38,20 +66,32 @@ int uptime_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) sysinfo(&info); - printf(" %02d:%02d:%02d up ", + printf(" %02u:%02u:%02u up ", current_time->tm_hour, current_time->tm_min, current_time->tm_sec); - updays = (int) info.uptime / (60*60*24); + updays = (unsigned) info.uptime / (unsigned)(60*60*24); if (updays) - printf("%d day%s, ", updays, (updays != 1) ? "s" : ""); - upminutes = (int) info.uptime / 60; - uphours = (upminutes / 60) % 24; + printf("%u day%s, ", updays, (updays != 1) ? "s" : ""); + upminutes = (unsigned) info.uptime / (unsigned)60; + uphours = (upminutes / (unsigned)60) % (unsigned)24; upminutes %= 60; if (uphours) - printf("%2d:%02d, ", uphours, upminutes); + printf("%2u:%02u", uphours, upminutes); else - printf("%d min, ", upminutes); + printf("%u min", upminutes); + +#if ENABLE_FEATURE_UPTIME_UTMP_SUPPORT + { + struct utmp *ut; + unsigned users = 0; + while ((ut = getutent()) != NULL) { + if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) + users++; + } + printf(", %u users", users); + } +#endif - printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", + printf(", load average: %u.%02u, %u.%02u, %u.%02u\n", LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); diff --git a/release/src/router/busybox/procps/watch.c b/release/src/router/busybox/procps/watch.c index 36f71c469a..36af1cca7c 100644 --- a/release/src/router/busybox/procps/watch.c +++ b/release/src/router/busybox/procps/watch.c @@ -11,6 +11,19 @@ /* BB_AUDIT SUSv3 N/A */ /* BB_AUDIT GNU defects -- only option -n is supported. */ +//usage:#define watch_trivial_usage +//usage: "[-n SEC] [-t] PROG ARGS" +//usage:#define watch_full_usage "\n\n" +//usage: "Run PROG periodically\n" +//usage: "\n -n Loop period in seconds (default 2)" +//usage: "\n -t Don't print header" +//usage: +//usage:#define watch_example_usage +//usage: "$ watch date\n" +//usage: "Mon Dec 17 10:31:40 GMT 2000\n" +//usage: "Mon Dec 17 10:31:42 GMT 2000\n" +//usage: "Mon Dec 17 10:31:44 GMT 2000" + #include "libbb.h" // procps 2.0.18: diff --git a/release/src/router/busybox/runit/chpst.c b/release/src/router/busybox/runit/chpst.c index dc8a26aebd..ac296babf2 100644 --- a/release/src/router/busybox/runit/chpst.c +++ b/release/src/router/busybox/runit/chpst.c @@ -28,6 +28,68 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* Dependencies on runit_lib.c removed */ +//usage:#define chpst_trivial_usage +//usage: "[-vP012] [-u USER[:GRP]] [-U USER[:GRP]] [-e DIR]\n" +//usage: " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" +//usage: " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" +//usage:#define chpst_full_usage "\n\n" +//usage: "Change the process state, run PROG\n" +//usage: "\n -u USER[:GRP] Set uid and gid" +//usage: "\n -U USER[:GRP] Set $UID and $GID in environment" +//usage: "\n -e DIR Set environment variables as specified by files" +//usage: "\n in DIR: file=1st_line_of_file" +//usage: "\n -/ DIR Chroot to DIR" +//usage: "\n -n NICE Add NICE to nice value" +//usage: "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES" +//usage: "\n -d BYTES Limit data segment" +//usage: "\n -o N Limit number of open files per process" +//usage: "\n -p N Limit number of processes per uid" +//usage: "\n -f BYTES Limit output file sizes" +//usage: "\n -c BYTES Limit core file size" +//usage: "\n -v Verbose" +//usage: "\n -P Create new process group" +//usage: "\n -0 Close stdin" +//usage: "\n -1 Close stdout" +//usage: "\n -2 Close stderr" +//usage: +//usage:#define envdir_trivial_usage +//usage: "DIR PROG ARGS" +//usage:#define envdir_full_usage "\n\n" +//usage: "Set various environment variables as specified by files\n" +//usage: "in the directory DIR, run PROG" +//usage: +//usage:#define envuidgid_trivial_usage +//usage: "USER PROG ARGS" +//usage:#define envuidgid_full_usage "\n\n" +//usage: "Set $UID to USER's uid and $GID to USER's gid, run PROG" +//usage: +//usage:#define setuidgid_trivial_usage +//usage: "USER PROG ARGS" +//usage:#define setuidgid_full_usage "\n\n" +//usage: "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" +//usage: "run PROG" +//usage: +//usage:#define softlimit_trivial_usage +//usage: "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" +//usage: " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" +//usage: " PROG ARGS" +//usage:#define softlimit_full_usage "\n\n" +//usage: "Set soft resource limits, then run PROG\n" +//usage: "\n -a BYTES Limit total size of all segments" +//usage: "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES -a BYTES" +//usage: "\n -d BYTES Limit data segment" +//usage: "\n -s BYTES Limit stack segment" +//usage: "\n -l BYTES Limit locked memory size" +//usage: "\n -o N Limit number of open files per process" +//usage: "\n -p N Limit number of processes per uid" +//usage: "\nOptions controlling file sizes:" +//usage: "\n -f BYTES Limit output file sizes" +//usage: "\n -c BYTES Limit core file size" +//usage: "\nEfficiency opts:" +//usage: "\n -r BYTES Limit resident set size" +//usage: "\n -t N Limit CPU time, process receives" +//usage: "\n a SIGXCPU after N seconds" + #include "libbb.h" /* @@ -343,22 +405,19 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_e) edir(env_dir); - // FIXME: chrooted jail must have /etc/passwd if we move this after chroot! - // OTOH chroot fails for non-roots! - // SOLUTION: cache uid/gid before chroot, apply uid/gid after + if (opt & (OPT_u|OPT_U)) + xget_uidgid(&ugid, set_user); + + // chrooted jail must have /etc/passwd if we move this after chroot. + // OTOH chroot fails for non-roots. + // Solution: cache uid/gid before chroot, apply uid/gid after. if (opt & OPT_U) { - xget_uidgid(&ugid, env_user); xsetenv("GID", utoa(ugid.gid)); xsetenv("UID", utoa(ugid.uid)); } - if (opt & OPT_u) { - xget_uidgid(&ugid, set_user); - } - if (opt & OPT_root) { - xchdir(root); - xchroot("."); + xchroot(root); } if (opt & OPT_u) { diff --git a/release/src/router/busybox/runit/runsv.c b/release/src/router/busybox/runit/runsv.c index ebb0318370..ad8d84f74e 100644 --- a/release/src/router/busybox/runit/runsv.c +++ b/release/src/router/busybox/runit/runsv.c @@ -28,6 +28,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ +//usage:#define runsv_trivial_usage +//usage: "DIR" +//usage:#define runsv_full_usage "\n\n" +//usage: "Start and monitor a service and optionally an appendant log service" + #include #include #include "libbb.h" @@ -139,16 +144,6 @@ static void s_term(int sig_no UNUSED_PARAM) write(selfpipe.wr, "", 1); /* XXX */ } -/* libbb candidate */ -static char *bb_stpcpy(char *p, const char *to_add) -{ - while ((*p = *to_add) != '\0') { - p++; - to_add++; - } - return p; -} - static int open_trunc_or_warn(const char *name) { /* Why O_NDELAY? */ @@ -192,26 +187,26 @@ static void update_status(struct svdir *s) char *p = stat_buf; switch (s->state) { case S_DOWN: - p = bb_stpcpy(p, "down"); + p = stpcpy(p, "down"); break; case S_RUN: - p = bb_stpcpy(p, "run"); + p = stpcpy(p, "run"); break; case S_FINISH: - p = bb_stpcpy(p, "finish"); + p = stpcpy(p, "finish"); break; } if (s->ctrl & C_PAUSE) - p = bb_stpcpy(p, ", paused"); + p = stpcpy(p, ", paused"); if (s->ctrl & C_TERM) - p = bb_stpcpy(p, ", got TERM"); + p = stpcpy(p, ", got TERM"); if (s->state != S_DOWN) switch (s->sd_want) { case W_DOWN: - p = bb_stpcpy(p, ", want down"); + p = stpcpy(p, ", want down"); break; case W_EXIT: - p = bb_stpcpy(p, ", want exit"); + p = stpcpy(p, ", want exit"); break; } *p++ = '\n'; diff --git a/release/src/router/busybox/runit/runsvdir.c b/release/src/router/busybox/runit/runsvdir.c index 1666642370..32526cf4ca 100644 --- a/release/src/router/busybox/runit/runsvdir.c +++ b/release/src/router/busybox/runit/runsvdir.c @@ -28,6 +28,13 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ +//usage:#define runsvdir_trivial_usage +//usage: "[-P] [-s SCRIPT] DIR" +//usage:#define runsvdir_full_usage "\n\n" +//usage: "Start a runsv process for each subdirectory. If it exits, restart it.\n" +//usage: "\n -P Put each runsv in a new session" +//usage: "\n -s SCRIPT Run SCRIPT after signal is processed" + #include #include #include "libbb.h" @@ -68,8 +75,7 @@ struct globals { #define logpipe (G.logpipe ) #define pfd (G.pfd ) #define stamplog (G.stamplog ) -#define INIT_G() do { \ -} while (0) +#define INIT_G() do { } while (0) static void fatal2_cannot(const char *m1, const char *m2) { diff --git a/release/src/router/busybox/runit/sv.c b/release/src/router/busybox/runit/sv.c index c420a91a6d..5b01c875c1 100644 --- a/release/src/router/busybox/runit/sv.c +++ b/release/src/router/busybox/runit/sv.c @@ -153,6 +153,22 @@ Exit Codes /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ +//usage:#define sv_trivial_usage +//usage: "[-v] [-w SEC] CMD SERVICE_DIR..." +//usage:#define sv_full_usage "\n\n" +//usage: "Control services monitored by runsv supervisor.\n" +//usage: "Commands (only first character is enough):\n" +//usage: "\n" +//usage: "status: query service status\n" +//usage: "up: if service isn't running, start it. If service stops, restart it\n" +//usage: "once: like 'up', but if service stops, don't restart it\n" +//usage: "down: send TERM and CONT signals. If ./run exits, start ./finish\n" +//usage: " if it exists. After it stops, don't restart service\n" +//usage: "exit: send TERM and CONT signals to service and log service. If they exit,\n" +//usage: " runsv exits too\n" +//usage: "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n" +//usage: "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service" + #include #include #include "libbb.h" @@ -421,7 +437,6 @@ static int control(const char *a) int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sv_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; char *x; char *action; const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR; @@ -442,7 +457,7 @@ int sv_main(int argc UNUSED_PARAM, char **argv) if (x) waitsec = xatou(x); opt_complementary = "w+:vv"; /* -w N, -v is a counter */ - opt = getopt32(argv, "w:v", &waitsec, &verbose); + getopt32(argv, "w:v", &waitsec, &verbose); argv += optind; action = *argv++; if (!action || !*argv) bb_show_usage(); diff --git a/release/src/router/busybox/runit/svlogd.c b/release/src/router/busybox/runit/svlogd.c index c3ff4e9c18..b0ba21bb63 100644 --- a/release/src/router/busybox/runit/svlogd.c +++ b/release/src/router/busybox/runit/svlogd.c @@ -125,6 +125,23 @@ log message, you can use a pattern like this instead -*: *: pid * */ +//usage:#define svlogd_trivial_usage +//usage: "[-ttv] [-r C] [-R CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..." +//usage:#define svlogd_full_usage "\n\n" +//usage: "Continuously read log data from stdin and write to rotated log files in DIRs" +//usage: "\n" +//usage: "\n""DIR/config file modifies behavior:" +//usage: "\n""sSIZE - when to rotate logs" +//usage: "\n""nNUM - number of files to retain" +/*usage: "\n""NNUM - min number files to retain" - confusing */ +/*usage: "\n""tSEC - rotate file if it get SEC seconds old" - confusing */ +//usage: "\n""!PROG - process rotated log with PROG" +/*usage: "\n""uIPADDR - send log over UDP" - unsupported */ +/*usage: "\n""UIPADDR - send log over UDP and DONT log" - unsupported */ +/*usage: "\n""pPFX - prefix each line with PFX" - unsupported */ +//usage: "\n""+,-PATTERN - (de)select line for logging" +//usage: "\n""E,ePATTERN - (de)select line for stderr" + #include #include #include "libbb.h" @@ -170,6 +187,7 @@ struct globals { unsigned nearest_rotate; void* (*memRchr)(const void *, int, size_t); + char *shell; smallint exitasap; smallint rotateasap; @@ -365,6 +383,9 @@ static void processorstart(struct logdir *ld) /* vfork'ed child trashes this byte, save... */ sv_ch = ld->fnsave[26]; + if (!G.shell) + G.shell = xstrdup(get_shell_name()); + while ((pid = vfork()) == -1) pause2cannot("vfork for processor", ld->name); if (!pid) { @@ -399,8 +420,7 @@ static void processorstart(struct logdir *ld) fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); xmove_fd(fd, 5); -// getenv("SHELL")? - execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", ld->processor, (char*) NULL); + execl(G.shell, G.shell, "-c", ld->processor, (char*) NULL); bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name); } ld->fnsave[26] = sv_ch; /* ...restore */ diff --git a/release/src/router/busybox/scripts/Makefile.IMA b/release/src/router/busybox/scripts/Makefile.IMA index a62618ae02..0eced29823 100644 --- a/release/src/router/busybox/scripts/Makefile.IMA +++ b/release/src/router/busybox/scripts/Makefile.IMA @@ -9,7 +9,10 @@ objtree := $(CURDIR) src := $(srctree) obj := $(objtree) -# Look for make include files relative to root of kernel src +# Make generated files +DUMMY := $(shell $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) >&2) + +# Look for make include files relative to root of src MAKEFLAGS += --include-dir=$(srctree) default: busybox @@ -121,6 +124,9 @@ lib-y:= include miscutils/Kbuild lib-all-y += $(patsubst %,miscutils/%,$(sort $(lib-y))) lib-y:= +include mailutils/Kbuild +lib-all-y += $(patsubst %,mailutils/%,$(sort $(lib-y))) +lib-y:= include coreutils/libcoreutils/Kbuild lib-all-y += $(patsubst %,coreutils/libcoreutils/%,$(sort $(lib-y))) lib-y:= @@ -168,7 +174,7 @@ lib-all-y += $(patsubst %,libbb/%,$(sort $(lib-y))) lib-y:= comma:=, -busybox_unstripped.o: $(usage_stuff) include/applet_tables.h include/autoconf.h +busybox_unstripped.o: $(usage_stuff) include/applet_tables.h include/NUM_APPLETS.h include/autoconf.h $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) \ $(patsubst %,-Wl$(comma)%,$(LDFLAGS) $(EXTRA_LDFLAGS)) \ -DGCC_COMBINE=1 \ @@ -194,14 +200,9 @@ busybox: busybox_unstripped.o include/autoconf.h: .config $(MAKE) -f $(srctree)/Makefile silentoldconfig +# Override rules for host compile applets/usage: include/autoconf.h - $(HOSTCC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I$(srctree)/include -o applets/usage applets/usage.c + $(HOSTCC) -Wall -O2 -I$(srctree)/include -o applets/usage applets/usage.c applets/applet_tables: include/autoconf.h - $(HOSTCC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I$(srctree)/include -o applets/applet_tables applets/applet_tables.c - -include/usage_compressed.h: include/usage.h applets/usage - $(srctree)/applets/usage_compressed include/usage_compressed.h applets - -include/applet_tables.h: include/applets.h - applets/applet_tables include/applet_tables.h + $(HOSTCC) -Wall -O2 -I$(srctree)/include -o applets/applet_tables applets/applet_tables.c diff --git a/release/src/router/busybox/scripts/basic/docproc.c b/release/src/router/busybox/scripts/basic/docproc.c index db30019d89..b125698321 100644 --- a/release/src/router/busybox/scripts/basic/docproc.c +++ b/release/src/router/busybox/scripts/basic/docproc.c @@ -39,6 +39,7 @@ #include #include #include +#include /* exitstatus is used to keep track of any failing calls to kernel-doc, * but execution continues. */ @@ -212,7 +213,7 @@ void find_export_symbols(char * filename) * Document all external or internal functions in a file. * Call kernel-doc with following parameters: * kernel-doc -docbook -nofunction function_name1 filename - * function names are obtained from all the the src files + * function names are obtained from all the src files * by find_export_symbols. * intfunc uses -nofunction * extfunc uses -function diff --git a/release/src/router/busybox/scripts/basic/fixdep.c b/release/src/router/busybox/scripts/basic/fixdep.c index 1a5b10f848..165a8c39dc 100644 --- a/release/src/router/busybox/scripts/basic/fixdep.c +++ b/release/src/router/busybox/scripts/basic/fixdep.c @@ -113,6 +113,7 @@ #include #include #include +#include /* bbox: not needed #define INT_CONF ntohl(0x434f4e46) @@ -329,7 +330,7 @@ void parse_dep_file(void *map, size_t len) clear_config(); while (m < end) { - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) m++; p = m; while (p < end && *p != ' ') p++; diff --git a/release/src/router/busybox/scripts/bloat-o-meter b/release/src/router/busybox/scripts/bloat-o-meter index 91374c1ca9..6db2a5e58c 100755 --- a/release/src/router/busybox/scripts/bloat-o-meter +++ b/release/src/router/busybox/scripts/bloat-o-meter @@ -1,8 +1,8 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Copyright 2004 Matt Mackall # -# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen +# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -39,25 +39,16 @@ if f1 is None or f2 is None: sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) def getsizes(file): sym, alias, lut = {}, {}, {} - #dynsym_filter = re.compile("^\d+:\s+[\dA-Fa-f]+\s+\d+\s+\w+\s+\w+\s+\w+\s+\w+\s+\w+$") for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines(): - if True: - l = l.strip() - if not (len(l) and l[0].isdigit() and len(l.split()) == 8): - continue - num, value, size, typ, bind, vis, ndx, name = l.split() - if ndx == "UND": continue # skip undefined - if typ in ["SECTION", "FILES"]: continue # skip sections and files - #else: - # l = l.strip() - # match = dynsym_filter.match(l) - # if not match: continue - # x, value, size, typ, bind, x, ndx, name = l.split() - # if ndx == "UND": continue # skip undefined - # if typ in ["SECTION", "FILES"]: continue # skip sections and files + l = l.strip() + if not (len(l) and l[0].isdigit() and len(l.split()) == 8): + continue + num, value, size, typ, bind, vis, ndx, name = l.split() + if ndx == "UND": continue # skip undefined + if typ in ["SECTION", "FILES"]: continue # skip sections and files if "." in name: name = "static." + name.split(".")[0] value = int(value, 16) - size = int(size) + size = int(size, 16) if size.startswith('0x') else int(size) if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias alias[(value, size)] = {"name" : name} else: diff --git a/release/src/router/busybox/scripts/gen_build_files.sh b/release/src/router/busybox/scripts/gen_build_files.sh index 620f495488..0989b2fe5e 100755 --- a/release/src/router/busybox/scripts/gen_build_files.sh +++ b/release/src/router/busybox/scripts/gen_build_files.sh @@ -1,5 +1,9 @@ #!/bin/sh +# Note: was using sed OPTS CMD -- FILES +# but users complain that many sed implementations +# are misinterpreting --. + test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } # cd to objtree @@ -15,21 +19,20 @@ chk() { status "CHK" "$@"; } generate() { - local src="$1" dst="$2" header="$3" insert="$4" + # NB: data to be inserted at INSERT line is coming on stdin + local src="$1" dst="$2" header="$3" #chk "${dst}" - ( + { + # Need to use printf: different shells have inconsistent + # rules re handling of "\n" in echo params. printf "%s\n" "${header}" - if grep -qs '^INSERT$' "${src}"; then - sed -n '1,/^INSERT$/p' "${src}" - printf "%s\n" "${insert}" - sed -n '/^INSERT$/,$p' "${src}" - else - if [ -n "${insert}" ]; then - printf "%s\n" "ERROR: INSERT line missing in: ${src}" 1>&2 - fi - cat "${src}" - fi - ) | sed '/^INSERT$/d' > "${dst}.tmp" + # print everything up to INSERT line + sed -n '/^INSERT$/ q; p' "${src}" + # copy stdin to stdout + cat + # print everything after INSERT line + sed -n '/^INSERT$/ { :l; n; p; bl }' "${src}" + } >"${dst}.tmp" if ! cmp -s "${dst}" "${dst}.tmp"; then gen "${dst}" mv "${dst}.tmp" "${dst}" @@ -39,27 +42,27 @@ generate() } # (Re)generate include/applets.h -s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -generate \ +sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ +| generate \ "$srctree/include/applets.src.h" \ "include/applets.h" \ - "/* DO NOT EDIT. This file is generated from applets.src.h */" \ - "${s}" + "/* DO NOT EDIT. This file is generated from applets.src.h */" # (Re)generate include/usage.h # We add line continuation backslash after each line, # and insert empty line before each line which doesn't start # with space or tab -# (note: we need to use \\\\ because of ``) -s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -generate \ +sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' \ + "$srctree"/*/*.c "$srctree"/*/*/*.c \ +| generate \ "$srctree/include/usage.src.h" \ "include/usage.h" \ - "/* DO NOT EDIT. This file is generated from usage.src.h */" \ - "${s}" + "/* DO NOT EDIT. This file is generated from usage.src.h */" # (Re)generate */Kbuild and */Config.in -{ cd -- "$srctree" && find . -type d; } | while read -r d; do +# We skip .dotdirs - makes git/svn/etc users happier +{ cd -- "$srctree" && find . -type d -not '(' -name '.?*' -prune ')'; } \ +| while read -r d; do d="${d#./}" src="$srctree/$d/Kbuild.src" @@ -67,11 +70,10 @@ generate \ if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` - generate \ + sed -n 's@^//kbuild:@@p' "$srctree/$d"/*.c \ + | generate \ "${src}" "${dst}" \ - "# DO NOT EDIT. This file is generated from Kbuild.src" \ - "${s}" + "# DO NOT EDIT. This file is generated from Kbuild.src" fi src="$srctree/$d/Config.src" @@ -79,11 +81,10 @@ generate \ if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` - generate \ + sed -n 's@^//config:@@p' "$srctree/$d"/*.c \ + | generate \ "${src}" "${dst}" \ - "# DO NOT EDIT. This file is generated from Config.src" \ - "${s}" + "# DO NOT EDIT. This file is generated from Config.src" fi done diff --git a/release/src/router/busybox/scripts/kconfig/Makefile b/release/src/router/busybox/scripts/kconfig/Makefile index b5708e2e4b..1651390a68 100644 --- a/release/src/router/busybox/scripts/kconfig/Makefile +++ b/release/src/router/busybox/scripts/kconfig/Makefile @@ -87,7 +87,7 @@ endif $(MTIME_IS_COARSE) && sleep 1 %_defconfig: $(obj)/conf - $(Q)$< -D $@ Config.in + $(Q)$< -D configs/$@ Config.in $(MTIME_IS_COARSE) && sleep 1 # Help text used by make help diff --git a/release/src/router/busybox/scripts/kconfig/conf.c b/release/src/router/busybox/scripts/kconfig/conf.c index 9befa2b54d..ea2446a898 100644 --- a/release/src/router/busybox/scripts/kconfig/conf.c +++ b/release/src/router/busybox/scripts/kconfig/conf.c @@ -3,6 +3,8 @@ * Released under the terms of the GNU GPL v2.0. */ +#define _XOPEN_SOURCE 700 + #include #include #include @@ -171,7 +173,7 @@ static void conf_askvalue(struct symbol *sym, const char *def) int conf_string(struct menu *menu) { struct symbol *sym = menu->sym; - const char *def, *help; + const char *def; while (1) { printf("%*s%s ", indent - 1, "", menu->prompt->text); @@ -186,10 +188,7 @@ int conf_string(struct menu *menu) case '?': /* print help */ if (line[1] == '\n') { - help = nohelp_text; - if (menu->sym->help) - help = menu->sym->help; - printf("\n%s\n", menu->sym->help); + printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text); def = NULL; break; } @@ -205,7 +204,6 @@ int conf_string(struct menu *menu) static int conf_sym(struct menu *menu) { struct symbol *sym = menu->sym; - int type; tristate oldval, newval; const char *help; @@ -213,7 +211,6 @@ static int conf_sym(struct menu *menu) printf("%*s%s ", indent - 1, "", menu->prompt->text); if (sym->name) printf("(%s) ", sym->name); - type = sym_get_type(sym); putchar('['); oldval = sym_get_tristate_value(sym); switch (oldval) { @@ -280,11 +277,9 @@ static int conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; struct menu *child; - int type; bool is_new; sym = menu->sym; - type = sym_get_type(sym); is_new = !sym_has_value(sym); if (sym_is_changable(sym)) { conf_sym(menu); diff --git a/release/src/router/busybox/scripts/kconfig/lxdialog/textbox.c b/release/src/router/busybox/scripts/kconfig/lxdialog/textbox.c index 77848bb8e0..de4ae41d7b 100644 --- a/release/src/router/busybox/scripts/kconfig/lxdialog/textbox.c +++ b/release/src/router/busybox/scripts/kconfig/lxdialog/textbox.c @@ -38,11 +38,8 @@ int dialog_textbox(const char *title, const char *file, int height, int width) { int i, x, y, cur_x, cur_y, fpos, key = 0; int passed_end; - char search_term[MAX_LEN + 1]; WINDOW *dialog, *text; - search_term[0] = '\0'; /* no search term entered yet */ - /* Open input file for reading */ if ((fd = open(file, O_RDONLY)) == -1) { endwin(); @@ -437,7 +434,6 @@ static void print_page(WINDOW * win, int height, int width) */ static void print_line(WINDOW * win, int row, int width) { - int y, x; char *line; line = get_line(); @@ -446,11 +442,13 @@ static void print_line(WINDOW * win, int row, int width) waddch(win, ' '); waddnstr(win, line, MIN(strlen(line), width - 2)); - getyx(win, y, x); /* Clear 'residue' of previous line */ #if OLD_NCURSES { int i; + int y, x; + + getyx(win, y, x); for (i = 0; i < width - x; i++) waddch(win, ' '); } diff --git a/release/src/router/busybox/scripts/kconfig/mconf.c b/release/src/router/busybox/scripts/kconfig/mconf.c index d292b46cc1..d3f69f8f5a 100644 --- a/release/src/router/busybox/scripts/kconfig/mconf.c +++ b/release/src/router/busybox/scripts/kconfig/mconf.c @@ -8,6 +8,8 @@ * i18n, 2005, Arnaldo Carvalho de Melo */ +#define _XOPEN_SOURCE 700 + #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include /* for strcasecmp */ #include #include #include diff --git a/release/src/router/busybox/scripts/randomtest.loop b/release/src/router/busybox/scripts/randomtest.loop index 2c8a9bd35b..758a8e8629 100755 --- a/release/src/router/busybox/scripts/randomtest.loop +++ b/release/src/router/busybox/scripts/randomtest.loop @@ -1,5 +1,7 @@ #!/bin/sh +run_testsuite=true + test -d "$1" || { echo "'$1' is not a directory"; exit 1; } test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; } @@ -21,7 +23,9 @@ while sleep 1; do echo "Failed build in: failed.$dir" exit 1 # you may comment this out... let fail++ - else + continue + fi + if $run_testsuite; then ( cd -- "$dir/testsuite" || exit 1 echo "Running testsuite in $dir..." @@ -29,10 +33,12 @@ while sleep 1; do ) if test $? != 0; then echo "Failed runtest in $dir" - exit 1 + exit 1 # you may comment this out... + let fail++ + continue fi tail -n10 -- "$dir/testsuite/runtest.log" - rm -rf -- "$dir" fi + rm -rf -- "$dir" let cnt++ done diff --git a/release/src/router/busybox/scripts/trylink b/release/src/router/busybox/scripts/trylink index 5994a757bc..a8b0b2e034 100755 --- a/release/src/router/busybox/scripts/trylink +++ b/release/src/router/busybox/scripts/trylink @@ -255,6 +255,7 @@ if test "$CONFIG_FEATURE_SHARED_BUSYBOX" = y; then $GC_SECTIONS \ $START_GROUP $O_FILES $END_GROUP \ -L"$sharedlib_dir" -lbusybox \ + $l_list \ $INFO_OPTS \ || { echo "Linking $EXE failed" diff --git a/release/src/router/busybox/selinux/chcon.c b/release/src/router/busybox/selinux/chcon.c index e00cdda1bb..88d0cfec61 100644 --- a/release/src/router/busybox/selinux/chcon.c +++ b/release/src/router/busybox/selinux/chcon.c @@ -7,7 +7,39 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include + +//usage:#define chcon_trivial_usage +//usage: "[OPTIONS] CONTEXT FILE..." +//usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." +//usage: IF_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." +//usage: ) +//usage:#define chcon_full_usage "\n\n" +//usage: "Change the security context of each FILE to CONTEXT\n" +//usage: IF_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n -v,--verbose Verbose" +//usage: "\n -c,--changes Report changes made" +//usage: "\n -h,--no-dereference Affect symlinks instead of their targets" +//usage: "\n -f,--silent,--quiet Suppress most error messages" +//usage: "\n --reference=RFILE Use RFILE's group instead of using a CONTEXT value" +//usage: "\n -u,--user=USER Set user/role/type/range in the target" +//usage: "\n -r,--role=ROLE security context" +//usage: "\n -t,--type=TYPE" +//usage: "\n -l,--range=RANGE" +//usage: "\n -R,--recursive Recurse" +//usage: ) +//usage: IF_NOT_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n -v Verbose" +//usage: "\n -c Report changes made" +//usage: "\n -h Affect symlinks instead of their targets" +//usage: "\n -f Suppress most error messages" +//usage: "\n -u USER Set user/role/type/range in the target security context" +//usage: "\n -r ROLE" +//usage: "\n -t TYPE" +//usage: "\n -l RNG" +//usage: "\n -R Recurse" +//usage: ) + #include #include "libbb.h" diff --git a/release/src/router/busybox/selinux/getenforce.c b/release/src/router/busybox/selinux/getenforce.c index d9d9d0f658..56611d6936 100644 --- a/release/src/router/busybox/selinux/getenforce.c +++ b/release/src/router/busybox/selinux/getenforce.c @@ -7,6 +7,9 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define getenforce_trivial_usage NOUSAGE_STR +//usage:#define getenforce_full_usage "" + #include "libbb.h" int getenforce_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/selinux/getsebool.c b/release/src/router/busybox/selinux/getsebool.c index 924356caec..e8f0fefb05 100644 --- a/release/src/router/busybox/selinux/getsebool.c +++ b/release/src/router/busybox/selinux/getsebool.c @@ -7,6 +7,11 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define getsebool_trivial_usage +//usage: "-a or getsebool boolean..." +//usage:#define getsebool_full_usage "\n\n" +//usage: " -a Show all selinux booleans" + #include "libbb.h" int getsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/selinux/load_policy.c b/release/src/router/busybox/selinux/load_policy.c index 8fc92dbf3b..ce139dbf2f 100644 --- a/release/src/router/busybox/selinux/load_policy.c +++ b/release/src/router/busybox/selinux/load_policy.c @@ -4,6 +4,10 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define load_policy_trivial_usage NOUSAGE_STR +//usage:#define load_policy_full_usage "" + #include "libbb.h" int load_policy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/selinux/matchpathcon.c b/release/src/router/busybox/selinux/matchpathcon.c index ec49077c8e..9e5728eb3b 100644 --- a/release/src/router/busybox/selinux/matchpathcon.c +++ b/release/src/router/busybox/selinux/matchpathcon.c @@ -5,6 +5,16 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define matchpathcon_trivial_usage +//usage: "[-n] [-N] [-f file_contexts_file] [-p prefix] [-V]" +//usage:#define matchpathcon_full_usage "\n\n" +//usage: " -n Don't display path" +//usage: "\n -N Don't use translations" +//usage: "\n -f Use alternate file_context file" +//usage: "\n -p Use prefix to speed translations" +//usage: "\n -V Verify file context on disk matches defaults" + #include "libbb.h" static int print_matchpathcon(char *path, int noprint) diff --git a/release/src/router/busybox/selinux/runcon.c b/release/src/router/busybox/selinux/runcon.c index b70a5e396b..3183a2274e 100644 --- a/release/src/router/busybox/selinux/runcon.c +++ b/release/src/router/busybox/selinux/runcon.c @@ -28,7 +28,28 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include + +//usage:#define runcon_trivial_usage +//usage: "[-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] PROG ARGS\n" +//usage: "runcon CONTEXT PROG ARGS" +//usage:#define runcon_full_usage "\n\n" +//usage: "Run PROG in a different security context\n" +//usage: "\n CONTEXT Complete security context\n" +//usage: IF_FEATURE_RUNCON_LONG_OPTIONS( +//usage: "\n -c,--compute Compute process transition context before modifying" +//usage: "\n -t,--type=TYPE Type (for same role as parent)" +//usage: "\n -u,--user=USER User identity" +//usage: "\n -r,--role=ROLE Role" +//usage: "\n -l,--range=RNG Levelrange" +//usage: ) +//usage: IF_NOT_FEATURE_RUNCON_LONG_OPTIONS( +//usage: "\n -c Compute process transition context before modifying" +//usage: "\n -t TYPE Type (for same role as parent)" +//usage: "\n -u USER User identity" +//usage: "\n -r ROLE Role" +//usage: "\n -l RNG Levelrange" +//usage: ) + #include #include @@ -132,6 +153,5 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("can't set up security context '%s'", context_str(con)); - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/release/src/router/busybox/selinux/selinuxenabled.c b/release/src/router/busybox/selinux/selinuxenabled.c index aa4e63f741..ce830dc220 100644 --- a/release/src/router/busybox/selinux/selinuxenabled.c +++ b/release/src/router/busybox/selinux/selinuxenabled.c @@ -6,6 +6,10 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define selinuxenabled_trivial_usage NOUSAGE_STR +//usage:#define selinuxenabled_full_usage "" + #include "libbb.h" int selinuxenabled_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/selinux/sestatus.c b/release/src/router/busybox/selinux/sestatus.c index aa12e806c9..0bd1a0dda3 100644 --- a/release/src/router/busybox/selinux/sestatus.c +++ b/release/src/router/busybox/selinux/sestatus.c @@ -8,6 +8,12 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define sestatus_trivial_usage +//usage: "[-vb]" +//usage:#define sestatus_full_usage "\n\n" +//usage: " -v Verbose" +//usage: "\n -b Display current state of booleans" + #include "libbb.h" extern char *selinux_mnt; diff --git a/release/src/router/busybox/selinux/setenforce.c b/release/src/router/busybox/selinux/setenforce.c index be5432147d..c5bc0a5a69 100644 --- a/release/src/router/busybox/selinux/setenforce.c +++ b/release/src/router/busybox/selinux/setenforce.c @@ -7,6 +7,10 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define setenforce_trivial_usage +//usage: "[Enforcing | Permissive | 1 | 0]" +//usage:#define setenforce_full_usage "" + #include "libbb.h" /* These strings are arranged so that odd ones diff --git a/release/src/router/busybox/selinux/setfiles.c b/release/src/router/busybox/selinux/setfiles.c index 989510e3d9..ca3fd93618 100644 --- a/release/src/router/busybox/selinux/setfiles.c +++ b/release/src/router/busybox/selinux/setfiles.c @@ -4,6 +4,46 @@ Port to BusyBox (c) 2007 by Yuichi Nakamura */ +//usage:#define setfiles_trivial_usage +//usage: "[-dnpqsvW] [-e DIR]... [-o FILE] [-r alt_root_path]" +//usage: IF_FEATURE_SETFILES_CHECK_OPTION( +//usage: " [-c policyfile] spec_file" +//usage: ) +//usage: " pathname" +//usage:#define setfiles_full_usage "\n\n" +//usage: "Reset file contexts under pathname according to spec_file\n" +//usage: IF_FEATURE_SETFILES_CHECK_OPTION( +//usage: "\n -c FILE Check the validity of the contexts against the specified binary policy" +//usage: ) +//usage: "\n -d Show which specification matched each file" +//usage: "\n -l Log changes in file labels to syslog" +//usage: "\n -n Don't change any file labels" +//usage: "\n -q Suppress warnings" +//usage: "\n -r DIR Use an alternate root path" +//usage: "\n -e DIR Exclude DIR" +//usage: "\n -F Force reset of context to match file_context for customizable files" +//usage: "\n -o FILE Save list of files with incorrect context" +//usage: "\n -s Take a list of files from stdin (instead of command line)" +//usage: "\n -v Show changes in file labels, if type or role are changing" +//usage: "\n -vv Show changes in file labels, if type, role, or user are changing" +//usage: "\n -W Display warnings about entries that had no matching files" +//usage: +//usage:#define restorecon_trivial_usage +//usage: "[-iFnRv] [-e EXCLUDEDIR]... [-o FILE] [-f FILE]" +//usage:#define restorecon_full_usage "\n\n" +//usage: "Reset security contexts of files in pathname\n" +//usage: "\n -i Ignore files that don't exist" +//usage: "\n -f FILE File with list of files to process" +//usage: "\n -e DIR Directory to exclude" +//usage: "\n -R,-r Recurse" +//usage: "\n -n Don't change any file labels" +//usage: "\n -o FILE Save list of files with incorrect context" +//usage: "\n -v Verbose" +//usage: "\n -vv Show changed labels" +//usage: "\n -F Force reset of context to match file_context" +//usage: "\n for customizable files, or the user section," +//usage: "\n if it has changed" + #include "libbb.h" #if ENABLE_FEATURE_SETFILES_CHECK_OPTION #include diff --git a/release/src/router/busybox/selinux/setsebool.c b/release/src/router/busybox/selinux/setsebool.c index a8cc004070..ec682e5c55 100644 --- a/release/src/router/busybox/selinux/setsebool.c +++ b/release/src/router/busybox/selinux/setsebool.c @@ -8,6 +8,11 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define setsebool_trivial_usage +//usage: "boolean value" +//usage:#define setsebool_full_usage "\n\n" +//usage: "Change boolean setting" + #include "libbb.h" int setsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/release/src/router/busybox/shell/Config.src b/release/src/router/busybox/shell/Config.src index c9c2439e72..b31e62ddac 100644 --- a/release/src/router/busybox/shell/Config.src +++ b/release/src/router/busybox/shell/Config.src @@ -123,9 +123,9 @@ config FEATURE_SH_NOFORK default n depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS help - This option causes busybox shells [currently only ash] - to not execute typical fork/exec/wait sequence, but call _main - directly, if possible. (Sometimes it is not possible: for example, + This option causes busybox shells to not execute typical + fork/exec/wait sequence, but call _main directly, + if possible. (Sometimes it is not possible: for example, this is not possible in pipes). This will be done only for some applets (those which are marked @@ -133,6 +133,17 @@ config FEATURE_SH_NOFORK This may significantly speed up some shell scripts. - This feature is relatively new. Use with care. + This feature is relatively new. Use with care. Report bugs + to project mailing list. + +config FEATURE_SH_HISTFILESIZE + bool "Use $HISTFILESIZE" + default y + depends on HUSH || ASH + help + This option makes busybox shells to use $HISTFILESIZE variable + to set shell history size. Note that its max value is capped + by "History size" setting in library tuning section. + endmenu diff --git a/release/src/router/busybox/shell/ash.c b/release/src/router/busybox/shell/ash.c index bf4193916f..5115025d80 100644 --- a/release/src/router/busybox/shell/ash.c +++ b/release/src/router/busybox/shell/ash.c @@ -36,12 +36,14 @@ #define JOBS ENABLE_ASH_JOB_CONTROL -#include "busybox.h" /* for applet_names */ #include #include #include #include +#include "busybox.h" /* for applet_names */ +#include "unicode.h" + #include "shell_common.h" #if ENABLE_SH_MATH_SUPPORT # include "math.h" @@ -72,13 +74,6 @@ # error "Do not even bother, ash will not run on NOMMU machine" #endif -//applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) -//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) - -//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o -//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o - //config:config ASH //config: bool "ash" //config: default y @@ -97,6 +92,13 @@ //config: help //config: Enable bash-compatible extensions. //config: +//config:config ASH_IDLE_TIMEOUT +//config: bool "Idle timeout variable" +//config: default n +//config: depends on ASH +//config: help +//config: Enables bash-like auto-logout after $TMOUT seconds of idle time. +//config: //config:config ASH_JOB_CONTROL //config: bool "Job control" //config: default y @@ -105,7 +107,7 @@ //config: Enable job control in the ash shell. //config: //config:config ASH_ALIAS -//config: bool "alias support" +//config: bool "Alias support" //config: default y //config: depends on ASH //config: help @@ -116,28 +118,28 @@ //config: default y //config: depends on ASH //config: help -//config: Enable getopts builtin in the ash shell. +//config: Enable support for getopts builtin in ash. //config: //config:config ASH_BUILTIN_ECHO //config: bool "Builtin version of 'echo'" //config: default y //config: depends on ASH //config: help -//config: Enable support for echo, builtin to ash. +//config: Enable support for echo builtin in ash. //config: //config:config ASH_BUILTIN_PRINTF //config: bool "Builtin version of 'printf'" //config: default y //config: depends on ASH //config: help -//config: Enable support for printf, builtin to ash. +//config: Enable support for printf builtin in ash. //config: //config:config ASH_BUILTIN_TEST //config: bool "Builtin version of 'test'" //config: default y //config: depends on ASH //config: help -//config: Enable support for test, builtin to ash. +//config: Enable support for test builtin in ash. //config: //config:config ASH_CMDCMD //config: bool "'command' command to override shell builtins" @@ -153,7 +155,7 @@ //config: default n //config: depends on ASH //config: help -//config: Enable "check for new mail" in the ash shell. +//config: Enable "check for new mail" function in the ash shell. //config: //config:config ASH_OPTIMIZE_FOR_SIZE //config: bool "Optimize for size instead of speed" @@ -183,12 +185,12 @@ //config: variable each time it is displayed. //config: -//usage:#define ash_trivial_usage NOUSAGE_STR -//usage:#define ash_full_usage "" -//usage:#define sh_trivial_usage NOUSAGE_STR -//usage:#define sh_full_usage "" -//usage:#define bash_trivial_usage NOUSAGE_STR -//usage:#define bash_full_usage "" +//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o +//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o /* ============ Hash table sizes. Configurable. */ @@ -400,6 +402,9 @@ static const char *var_end(const char *var) /* ============ Interrupts / exceptions */ + +static void exitshell(void) NORETURN; + /* * These macros allow the user to suspend the handling of interrupt signals * over a period of time. This is similar to SIGHOLD or to sigblock, but @@ -1880,7 +1885,9 @@ change_lc_ctype(const char *value) #endif #if ENABLE_ASH_MAIL static void chkmail(void); -static void changemail(const char *) FAST_FUNC; +static void changemail(const char *var_value) FAST_FUNC; +#else +# define chkmail() ((void)0) #endif static void changepath(const char *) FAST_FUNC; #if ENABLE_ASH_RANDOM_SUPPORT @@ -3484,13 +3491,18 @@ setsignal(int signo) switch (new_act) { case S_CATCH: act.sa_handler = signal_handler; - act.sa_flags = 0; /* matters only if !DFL and !IGN */ - sigfillset(&act.sa_mask); /* ditto */ break; case S_IGN: act.sa_handler = SIG_IGN; break; } + + /* flags and mask matter only if !DFL and !IGN, but we do it + * for all cases for more deterministic behavior: + */ + act.sa_flags = 0; + sigfillset(&act.sa_mask); + sigaction_set(signo, &act); *t = new_act; @@ -3527,12 +3539,12 @@ set_curjob(struct job *jp, unsigned mode) /* first remove from list */ jpp = curp = &curjob; - do { + while (1) { jp1 = *jpp; if (jp1 == jp) break; jpp = &jp1->prev_job; - } while (1); + } *jpp = jp1->prev_job; /* Then re-insert in correct position */ @@ -3548,14 +3560,14 @@ set_curjob(struct job *jp, unsigned mode) case CUR_RUNNING: /* newly created job or backgrounded job, put after all stopped jobs. */ - do { + while (1) { jp1 = *jpp; #if JOBS if (!jp1 || jp1->state != JOBSTOPPED) #endif break; jpp = &jp1->prev_job; - } while (1); + } /* FALLTHROUGH */ #if JOBS case CUR_STOPPED: @@ -3728,7 +3740,7 @@ setjobctl(int on) goto out; /* fd is a tty at this point */ close_on_exec_on(fd); - do { /* while we are in the background */ + while (1) { /* while we are in the background */ pgrp = tcgetpgrp(fd); if (pgrp < 0) { out: @@ -3739,7 +3751,7 @@ setjobctl(int on) if (pgrp == getpgrp()) break; killpg(0, SIGTTIN); - } while (1); + } initialpgrp = pgrp; setsignal(SIGTSTP); @@ -3771,18 +3783,51 @@ setjobctl(int on) static int FAST_FUNC killcmd(int argc, char **argv) { - int i = 1; if (argv[1] && strcmp(argv[1], "-l") != 0) { + int i = 1; do { if (argv[i][0] == '%') { - struct job *jp = getjob(argv[i], 0); - unsigned pid = jp->ps[0].ps_pid; - /* Enough space for ' -NNN' */ - argv[i] = alloca(sizeof(int)*3 + 3); - /* kill_main has matching code to expect - * leading space. Needed to not confuse - * negative pids with "kill -SIGNAL_NO" syntax */ - sprintf(argv[i], " -%u", pid); + /* + * "kill %N" - job kill + * Converting to pgrp / pid kill + */ + struct job *jp; + char *dst; + int j, n; + + jp = getjob(argv[i], 0); + /* + * In jobs started under job control, we signal + * entire process group by kill -PGRP_ID. + * This happens, f.e., in interactive shell. + * + * Otherwise, we signal each child via + * kill PID1 PID2 PID3. + * Testcases: + * sh -c 'sleep 1|sleep 1 & kill %1' + * sh -c 'true|sleep 2 & sleep 1; kill %1' + * sh -c 'true|sleep 1 & sleep 2; kill %1' + */ + n = jp->nprocs; /* can't be 0 (I hope) */ + if (jp->jobctl) + n = 1; + dst = alloca(n * sizeof(int)*4); + argv[i] = dst; + for (j = 0; j < n; j++) { + struct procstat *ps = &jp->ps[j]; + /* Skip non-running and not-stopped members + * (i.e. dead members) of the job + */ + if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) + continue; + /* + * kill_main has matching code to expect + * leading space. Needed to not confuse + * negative pids with "kill -SIGNAL_NO" syntax + */ + dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); + } + *dst = '\0'; } } while (argv[++i]); } @@ -3880,6 +3925,7 @@ sprint_status(char *s, int status, int sigonly) #endif } st &= 0x7f; +//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata col = fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { col += fmtstr(s + col, 16, " (core dumped)"); @@ -4214,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) break; job = job->prev_job; } - } else + } else { job = getjob(*argv, 0); + } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) blocking_wait_with_raise_on_sig(); @@ -4711,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode) #if JOBS /* do job control only in root shell */ doing_jobctl = 0; - if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { + if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { pid_t pgrp; if (jp->nprocs == 0) @@ -4737,7 +4784,7 @@ forkchild(struct job *jp, union node *n, int mode) ash_msg_and_raise_error("can't open '%s'", bb_dev_null); } } - if (!oldlvl) { + if (oldlvl == 0) { if (iflag) { /* why if iflag only? */ setsignal(SIGINT); setsignal(SIGTERM); @@ -4944,6 +4991,8 @@ stoppedjobs(void) * Code for dealing with input/output redirection. */ +#undef EMPTY +#undef CLOSED #define EMPTY -2 /* marks an unused slot in redirtab */ #define CLOSED -3 /* marks a slot of previously-closed fd */ @@ -5869,7 +5918,7 @@ expbackq(union node *cmd, int quoted, int quotes) read: if (in.fd < 0) break; - i = nonblock_safe_read(in.fd, buf, sizeof(buf)); + i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); TRACE(("expbackq: read returns %d\n", i)); if (i <= 0) break; @@ -5921,7 +5970,7 @@ expari(int quotes) p = expdest - 1; *p = '\0'; p--; - do { + while (1) { int esc; while ((unsigned char)*p != CTLARI) { @@ -5939,7 +5988,7 @@ expari(int quotes) } p -= esc + 1; - } while (1); + } begoff = p - start; @@ -6797,8 +6846,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) patloc = expdest - (char *)stackblock(); if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, startloc, varflags, -//TODO: | EXP_REDIR too? All other such places do it too - /* quotes: */ flags & (EXP_FULL | EXP_CASE), + /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), var_str_list) ) { int amount = expdest - ( @@ -7347,8 +7395,6 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ static void tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) { - int repeated = 0; - #if ENABLE_FEATURE_SH_STANDALONE if (applet_no >= 0) { if (APPLET_IS_NOEXEC(applet_no)) { @@ -7372,7 +7418,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** #else execve(cmd, argv, envp); #endif - if (repeated) { + if (cmd == (char*) bb_busybox_exec_path) { free(argv); return; } @@ -7382,15 +7428,14 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** for (ap = argv; *ap; ap++) continue; - ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); - ap[1] = cmd; - ap[0] = cmd = (char *)DEFAULT_SHELL; - ap += 2; - argv++; - while ((*ap++ = *argv++) != NULL) + new = ckmalloc((ap - argv + 2) * sizeof(new[0])); + new[0] = (char*) "ash"; + new[1] = cmd; + ap = new + 2; + while ((*ap++ = *++argv) != NULL) continue; + cmd = (char*) bb_busybox_exec_path; argv = new; - repeated++; goto repeat; } } @@ -7407,9 +7452,7 @@ shellexec(char **argv, const char *path, int idx) int e; char **envp; int exerrno; -#if ENABLE_FEATURE_SH_STANDALONE - int applet_no = -1; -#endif + int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ clearredir(/*drop:*/ 1); envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); @@ -7419,8 +7462,16 @@ shellexec(char **argv, const char *path, int idx) #endif ) { tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); + if (applet_no >= 0) { + /* We tried execing ourself, but it didn't work. + * Maybe /proc/self/exe doesn't exist? + * Try $PATH search. + */ + goto try_PATH; + } e = errno; } else { + try_PATH: e = ENOENT; while ((cmdname = path_advance(&path, argv[0])) != NULL) { if (--idx < 0 && pathopt == NULL) { @@ -9559,12 +9610,28 @@ preadfd(void) #if ENABLE_FEATURE_EDITING retry: if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) - nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); else { -#if ENABLE_FEATURE_TAB_COMPLETION + int timeout = -1; +# if ENABLE_ASH_IDLE_TIMEOUT + if (iflag) { + const char *tmout_var = lookupvar("TMOUT"); + if (tmout_var) { + timeout = atoi(tmout_var) * 1000; + if (timeout <= 0) + timeout = -1; + } + } +# endif +# if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); -#endif - nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); +# endif + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + reinit_unicode(lookupvar("LANG")); + nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); if (nr == 0) { /* Ctrl+C pressed */ if (trap[SIGINT]) { @@ -9575,17 +9642,24 @@ preadfd(void) } goto retry; } - if (nr < 0 && errno == 0) { - /* Ctrl+D pressed */ - nr = 0; + if (nr < 0) { + if (errno == 0) { + /* Ctrl+D pressed */ + nr = 0; + } +# if ENABLE_ASH_IDLE_TIMEOUT + else if (errno == EAGAIN && timeout > 0) { + printf("\007timed out waiting for input: auto-logout\n"); + exitshell(); + } +# endif } } #else - nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); #endif -#if 0 -/* nonblock_safe_read() handles this problem */ +#if 0 /* disabled: nonblock_immune_read() handles this problem */ if (nr < 0) { if (parsefile->fd == 0 && errno == EWOULDBLOCK) { int flags = fcntl(0, F_GETFL); @@ -10104,7 +10178,7 @@ options(int cmdline) else if (*argptr == NULL) setparam(argptr); } - break; /* "-" or "--" terminates options */ + break; /* "-" or "--" terminates options */ } } /* first char was + or - */ @@ -10206,10 +10280,10 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!argv[1]) return showvars(nullstr, 0, VUNSET); + INT_OFF; - retval = 1; - if (!options(0)) { /* if no parse error... */ - retval = 0; + retval = options(/*cmdline:*/ 0); + if (retval == 0) { /* if no parse error... */ optschanged(); if (*argptr != NULL) { setparam(argptr); @@ -12070,9 +12144,7 @@ cmdloop(int top) inter = 0; if (iflag && top) { inter++; -#if ENABLE_ASH_MAIL chkmail(); -#endif } n = parsecmd(inter); #if DEBUG @@ -12813,7 +12885,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv) /* * Called to exit the shell. */ -static void exitshell(void) NORETURN; static void exitshell(void) { @@ -12821,6 +12892,10 @@ exitshell(void) char *p; int status; +#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(line_input_state); +#endif + status = exitstatus; TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); if (setjmp(loc.loc)) { @@ -12876,14 +12951,32 @@ init(void) setvar("PPID", utoa(getppid()), 0); p = lookupvar("PWD"); - if (p) + if (p) { if (*p != '/' || stat(p, &st1) || stat(".", &st2) - || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino + ) { p = '\0'; + } + } setpwd(p, 0); } } + +//usage:#define ash_trivial_usage +//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" +//usage:#define ash_full_usage "\n\n" +//usage: "Unix shell interpreter" + +//usage:#if ENABLE_FEATURE_SH_IS_ASH +//usage:# define sh_trivial_usage ash_trivial_usage +//usage:# define sh_full_usage ash_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_ASH +//usage:# define bash_trivial_usage ash_trivial_usage +//usage:# define bash_full_usage ash_full_usage +//usage:#endif + /* * Process the shell command line arguments. */ @@ -12901,7 +12994,7 @@ procargs(char **argv) for (i = 0; i < NOPTS; i++) optlist[i] = 2; argptr = xargv; - if (options(1)) { + if (options(/*cmdline:*/ 1)) { /* it already printed err message */ raise_exception(EXERROR); } @@ -13063,10 +13156,9 @@ int ash_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_EDITING_SAVEHISTORY if (iflag) { const char *hp = lookupvar("HISTFILE"); - - if (hp == NULL) { + if (!hp) { hp = lookupvar("HOME"); - if (hp != NULL) { + if (hp) { char *defhp = concat_path_file(hp, ".ash_history"); setvar("HISTFILE", defhp, 0); free(defhp); @@ -13074,7 +13166,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } } #endif - if (/* argv[0] && */ argv[0][0] == '-') + if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { state = 1; @@ -13110,11 +13202,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } if (sflag || minusc == NULL) { -#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY +#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY if (iflag) { const char *hp = lookupvar("HISTFILE"); if (hp) line_input_state->hist_file = hp; +# if ENABLE_FEATURE_SH_HISTFILESIZE + hp = lookupvar("HISTFILESIZE"); + line_input_state->max_history = size_from_HISTFILESIZE(hp); +# endif } #endif state4: /* XXX ??? - why isn't this before the "if" statement */ diff --git a/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.right b/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.right new file mode 100644 index 0000000000..3e91a13d34 --- /dev/null +++ b/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.right @@ -0,0 +1,2 @@ +ash: write error: Broken pipe +Ok: 1 diff --git a/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.tests b/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.tests new file mode 100644 index 0000000000..0a40c9ff73 --- /dev/null +++ b/release/src/router/busybox/shell/ash_test/ash-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } diff --git a/release/src/router/busybox/shell/ash_test/ash-redir/redir.right b/release/src/router/busybox/shell/ash_test/ash-redir/redir.right index 2a02d41ce2..c1a6e729a6 100644 --- a/release/src/router/busybox/shell/ash_test/ash-redir/redir.right +++ b/release/src/router/busybox/shell/ash_test/ash-redir/redir.right @@ -1 +1,2 @@ +ash: write error: Bad file descriptor TEST diff --git a/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.right b/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.right new file mode 100644 index 0000000000..a9094b056f --- /dev/null +++ b/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.tests b/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.tests new file mode 100644 index 0000000000..3d483d32a4 --- /dev/null +++ b/release/src/router/busybox/shell/ash_test/ash-signals/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (The complex command is necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# in the testcase we don't send SIGINT *to the child*...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed diff --git a/release/src/router/busybox/shell/cttyhack.c b/release/src/router/busybox/shell/cttyhack.c index d1cb7fcc3d..f9b59c2632 100644 --- a/release/src/router/busybox/shell/cttyhack.c +++ b/release/src/router/busybox/shell/cttyhack.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -//applet:IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o @@ -14,18 +14,22 @@ //config: bool "cttyhack" //config: default y //config: help -//config: One common problem reported on the mailing list is "can't access tty; -//config: job control turned off" error message which typically appears when -//config: one tries to use shell with stdin/stdout opened to /dev/console. +//config: One common problem reported on the mailing list is the "can't +//config: access tty; job control turned off" error message, which typically +//config: appears when one tries to use a shell with stdin/stdout on +//config: /dev/console. //config: This device is special - it cannot be a controlling tty. //config: -//config: Proper solution is to use correct device instead of /dev/console. +//config: The proper solution is to use the correct device instead of +//config: /dev/console. //config: -//config: cttyhack provides "quick and dirty" solution to this problem. +//config: cttyhack provides a "quick and dirty" solution to this problem. //config: It analyzes stdin with various ioctls, trying to determine whether //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). -//config: If it detects one, it closes stdin/out/err and reopens that device. -//config: Then it executes given program. Opening the device will make +//config: On Linux it also checks sysfs for a pointer to the active console. +//config: If cttyhack is able to find the real console device, it closes +//config: stdin/out/err and reopens that device. +//config: Then it executes the given program. Opening the device will make //config: that device a controlling tty. This may require cttyhack //config: to be a session leader. //config: @@ -46,9 +50,12 @@ //config: //config: # exec setsid sh -c 'exec sh /dev/tty1 2>&1' //config: +//config: Starting getty on a controlling tty from a shell script: +//config: +//config: # getty 115200 $(cttyhack) //usage:#define cttyhack_trivial_usage -//usage: "PROG ARGS" +//usage: "[PROG ARGS]" //usage:#define cttyhack_full_usage "\n\n" //usage: "Give PROG a controlling tty if possible." //usage: "\nExample for /etc/inittab (for busybox init):" @@ -104,44 +111,78 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) char paranoia[sizeof(struct serial_struct) * 3]; } u; - if (!*++argv) { - bb_show_usage(); - } - strcpy(console, "/dev/tty"); fd = open(console, O_RDWR); - if (fd >= 0) { - /* We already have ctty, nothing to do */ - close(fd); - } else { + if (fd < 0) { /* We don't have ctty (or don't have "/dev/tty" node...) */ - if (0) {} -#ifdef TIOCGSERIAL - else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { - /* this is a serial console */ - sprintf(console + 8, "S%d", u.sr.line); - } -#endif + do { #ifdef __linux__ - else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { - /* this is linux virtual tty */ - sprintf(console + 8, "S%d" + 1, u.vt.v_active); - } -#endif - if (console[8]) { - fd = xopen(console, O_RDWR); - //bb_error_msg("switching to '%s'", console); - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - while (fd > 2) - close(fd--); - /* Some other session may have it as ctty, - * steal it from them: + /* Note that this method does not use _stdin_. + * Thus, "cttyhack 0) { + char *last; + /* Found active console via sysfs (Linux 2.6.38+). + * It looks like "[tty0 ]ttyS0\n" so zap the newline: + */ + console[4 + s] = '\0'; + /* If there are multiple consoles, + * take the last one: + */ + last = strrchr(console + 5, ' '); + if (last) + overlapping_strcpy(console + 5, last + 1); + break; + } + + if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { + /* this is linux virtual tty */ + sprintf(console + 8, "S%u" + 1, (int)u.vt.v_active); + break; + } +#endif +#ifdef TIOCGSERIAL + if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { + /* this is a serial console; assuming it is named /dev/ttySn */ + sprintf(console + 8, "S%u", (int)u.sr.line); + break; + } +#endif + /* nope, could not find it */ + console[0] = '\0'; + } while (0); } + argv++; + if (!argv[0]) { + if (!console[0]) + return EXIT_FAILURE; + puts(console); + return EXIT_SUCCESS; + } + + if (fd < 0) { + fd = open_or_warn(console, O_RDWR); + if (fd < 0) + goto ret; + } + //bb_error_msg("switching to '%s'", console); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + while (fd > 2) + close(fd--); + /* Some other session may have it as ctty, + * try to steal it from them: + */ + ioctl(0, TIOCSCTTY, 1); + ret: BB_EXECVP_or_die(argv); } diff --git a/release/src/router/busybox/shell/hush.c b/release/src/router/busybox/shell/hush.c index f0a0d85a3b..51d38d3aef 100644 --- a/release/src/router/busybox/shell/hush.c +++ b/release/src/router/busybox/shell/hush.c @@ -81,14 +81,19 @@ * $ "export" i=`echo 'aaa bbb'`; echo "$i" * aaa */ -#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ -#include /* for malloc_trim */ +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for malloc_trim */ +#endif #include /* #include */ #if ENABLE_HUSH_CASE # include #endif +#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ +#include "unicode.h" #include "shell_common.h" #include "math.h" #include "match.h" @@ -101,13 +106,9 @@ # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif -//applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) -//applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) -//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) - -//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o -//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o +/* Not every libc has sighandler_t. Fix it */ +typedef void (*hush_sighandler_t)(int); +#define sighandler_t hush_sighandler_t //config:config HUSH //config: bool "hush" @@ -245,14 +246,35 @@ //config: msh is deprecated and will be removed, please migrate to hush. //config: -//usage:#define hush_trivial_usage NOUSAGE_STR -//usage:#define hush_full_usage "" -//usage:#define msh_trivial_usage NOUSAGE_STR -//usage:#define msh_full_usage "" -//usage:#define sh_trivial_usage NOUSAGE_STR -//usage:#define sh_full_usage "" -//usage:#define bash_trivial_usage NOUSAGE_STR -//usage:#define bash_full_usage "" +//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o +//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o + +/* -i (interactive) and -s (read stdin) are also accepted, + * but currently do nothing, therefore aren't shown in help. + * NOMMU-specific options are not meant to be used by users, + * therefore we don't show them either. + */ +//usage:#define hush_trivial_usage +//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" +//usage:#define hush_full_usage "\n\n" +//usage: "Unix shell interpreter" + +//usage:#define msh_trivial_usage hush_trivial_usage +//usage:#define msh_full_usage hush_full_usage + +//usage:#if ENABLE_FEATURE_SH_IS_HUSH +//usage:# define sh_trivial_usage hush_trivial_usage +//usage:# define sh_full_usage hush_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_HUSH +//usage:# define bash_trivial_usage hush_trivial_usage +//usage:# define bash_full_usage hush_full_usage +//usage:#endif /* Build knobs */ @@ -302,6 +324,8 @@ # define ENABLE_FEATURE_EDITING 0 # undef ENABLE_FEATURE_EDITING_FANCY_PROMPT # define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 +# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0 #endif /* Do we support ANY keywords? */ @@ -436,17 +460,15 @@ static const char *const assignment_flag[] = { }; #endif -/* I can almost use ordinary FILE*. Is open_memstream() universally - * available? Where is it documented? */ typedef struct in_str { const char *p; /* eof_flag=1: last char in ->p is really an EOF */ char eof_flag; /* meaningless if ->p == NULL */ char peek_buf[2]; #if ENABLE_HUSH_INTERACTIVE - smallint promptme; smallint promptmode; /* 0: PS1, 1: PS2 */ #endif + int last_char; FILE *file; int (*get) (struct in_str *) FAST_FUNC; int (*peek) (struct in_str *) FAST_FUNC; @@ -504,7 +526,6 @@ typedef enum redir_type { struct command { pid_t pid; /* 0 if exited */ int assignment_cnt; /* how many argv[i] are assignments? */ - smallint is_stopped; /* is the command currently running? */ smallint cmd_type; /* CMD_xxx */ #define CMD_NORMAL 0 #define CMD_SUBSHELL 1 @@ -676,9 +697,19 @@ struct function { * vi off * xtrace off */ -static const char o_opt_strings[] ALIGN1 = "pipefail\0"; +static const char o_opt_strings[] ALIGN1 = + "pipefail\0" + "noexec\0" +#if ENABLE_HUSH_MODE_X + "xtrace\0" +#endif + ; enum { OPT_O_PIPEFAIL, + OPT_O_NOEXEC, +#if ENABLE_HUSH_MODE_X + OPT_O_XTRACE, +#endif NUM_OPT_O }; @@ -726,6 +757,11 @@ struct globals { # define G_saved_tty_pgrp 0 #endif char o_opt[NUM_OPT_O]; +#if ENABLE_HUSH_MODE_X +# define G_x_mode (G.o_opt[OPT_O_XTRACE]) +#else +# define G_x_mode 0 +#endif smallint flag_SIGINT; #if ENABLE_HUSH_LOOPS smallint flag_break_continue; @@ -737,19 +773,11 @@ struct globals { */ smallint flag_return_in_progress; #endif - smallint n_mode; -#if ENABLE_HUSH_MODE_X - smallint x_mode; -# define G_x_mode (G.x_mode) -#else -# define G_x_mode 0 -#endif smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ smalluint global_args_malloced; - smalluint inherited_set_is_saved; /* how many non-NULL argv's we have. NB: $# + 1 */ int global_argc; char **global_argv; @@ -777,15 +805,27 @@ struct globals { unsigned handled_SIGCHLD; smallint we_have_children; #endif - /* which signals have non-DFL handler (even with no traps set)? */ - unsigned non_DFL_mask; + /* Which signals have non-DFL handler (even with no traps set)? + * Set at the start to: + * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) + * SPECIAL_INTERACTIVE_SIGS are cleared after fork. + * The rest is cleared right before execv syscalls. + * Other than these two times, never modified. + */ + unsigned special_sig_mask; +#if ENABLE_HUSH_JOB + unsigned fatal_sig_mask; +# define G_fatal_sig_mask G.fatal_sig_mask +#else +# define G_fatal_sig_mask 0 +#endif char **traps; /* char *traps[NSIG] */ - sigset_t blocked_set; - sigset_t inherited_set; + sigset_t pending_set; #if HUSH_DEBUG unsigned long memleak_value; int debug_indent; #endif + struct sigaction sa; char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; }; #define G (*ptr_to_globals) @@ -794,6 +834,9 @@ struct globals { * is global, thus "G." prefix is a useful hint */ #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + /* memset(&G.sa, 0, sizeof(G.sa)); */ \ + sigfillset(&G.sa.sa_mask); \ + G.sa.sa_flags = SA_RESTART; \ } while (0) @@ -1061,43 +1104,36 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) xfunc_die(); } -static void syntax_error(unsigned lineno, const char *msg) +static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) { if (msg) - die_if_script(lineno, "syntax error: %s", msg); + bb_error_msg("syntax error: %s", msg); else - die_if_script(lineno, "syntax error", NULL); + bb_error_msg("syntax error"); } -static void syntax_error_at(unsigned lineno, const char *msg) +static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) { - die_if_script(lineno, "syntax error at '%s'", msg); + bb_error_msg("syntax error at '%s'", msg); } -static void syntax_error_unterm_str(unsigned lineno, const char *s) +static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) { - die_if_script(lineno, "syntax error: unterminated %s", s); + bb_error_msg("syntax error: unterminated %s", s); } -/* It so happens that all such cases are totally fatal - * even if shell is interactive: EOF while looking for closing - * delimiter. There is nowhere to read stuff from after that, - * it's EOF! The only choice is to terminate. - */ -static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; static void syntax_error_unterm_ch(unsigned lineno, char ch) { char msg[2] = { ch, '\0' }; syntax_error_unterm_str(lineno, msg); - xfunc_die(); } -static void syntax_error_unexpected_ch(unsigned lineno, int ch) +static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) { char msg[2]; msg[0] = ch; msg[1] = '\0'; - die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg); + bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); } #if HUSH_DEBUG < 2 @@ -1311,12 +1347,14 @@ static void restore_G_args(save_arg_t *sv, char **argv) * "echo $$; sleep 5 & wait; ls -l" + "kill -INT " * Example 3: this does not wait 5 sec, but executes ls: * "sleep 5; ls -l" + press ^C + * Example 4: this does not wait and does not execute ls: + * "sleep 5 & wait; ls -l" + press ^C * * (What happens to signals which are IGN on shell start?) * (What happens with signal mask on shell start?) * - * Implementation in hush - * ====================== + * Old implementation + * ================== * We use in-kernel pending signal mask to determine which signals were sent. * We block all signals which we don't want to take action immediately, * i.e. we block all signals which need to have special handling as described @@ -1324,11 +1362,11 @@ static void restore_G_args(save_arg_t *sv, char **argv) * After each pipe execution, we extract any pending signals via sigtimedwait() * and act on them. * - * unsigned non_DFL_mask: a mask of such "special" signals + * unsigned special_sig_mask: a mask of such "special" signals * sigset_t blocked_set: current blocked signal set * * "trap - SIGxxx": - * clear bit in blocked_set unless it is also in non_DFL_mask + * clear bit in blocked_set unless it is also in special_sig_mask * "trap 'cmd' SIGxxx": * set bit in blocked_set (even if 'cmd' is '') * after [v]fork, if we plan to be a shell: @@ -1347,6 +1385,49 @@ static void restore_G_args(save_arg_t *sv, char **argv) * Standard says "When a subshell is entered, traps that are not being ignored * are set to the default actions". bash interprets it so that traps which * are set to '' (ignore) are NOT reset to defaults. We do the same. + * + * Problem: the above approach makes it unwieldy to catch signals while + * we are in read builtin, of while we read commands from stdin: + * masked signals are not visible! + * + * New implementation + * ================== + * We record each signal we are interested in by installing signal handler + * for them - a bit like emulating kernel pending signal mask in userspace. + * We are interested in: signals which need to have special handling + * as described above, and all signals which have traps set. + * Signals are rocorded in pending_set. + * After each pipe execution, we extract any pending signals + * and act on them. + * + * unsigned special_sig_mask: a mask of shell-special signals. + * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp. + * char *traps[sig] if trap for sig is set (even if it's ''). + * sigset_t pending_set: set of sigs we received. + * + * "trap - SIGxxx": + * if sig is in special_sig_mask, set handler back to: + * record_pending_signo, or to IGN if it's a tty stop signal + * if sig is in fatal_sig_mask, set handler back to sigexit. + * else: set handler back to SIG_DFL + * "trap 'cmd' SIGxxx": + * set handler to record_pending_signo. + * "trap '' SIGxxx": + * set handler to SIG_IGN. + * after [v]fork, if we plan to be a shell: + * set signals with special interactive handling to SIG_DFL + * (because child shell is not interactive), + * unset all traps except '' (note: regardless of child shell's type - {}, (), etc) + * after [v]fork, if we plan to exec: + * POSIX says fork clears pending signal mask in child - no need to clear it. + * + * To make wait builtin interruptible, we handle SIGCHLD as special signal, + * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it. + * + * Note (compat): + * Standard says "When a subshell is entered, traps that are not being ignored + * are set to the default actions". bash interprets it so that traps which + * are set to '' (ignore) are NOT reset to defaults. We do the same. */ enum { SPECIAL_INTERACTIVE_SIGS = 0 @@ -1354,21 +1435,43 @@ enum { | (1 << SIGINT) | (1 << SIGHUP) , - SPECIAL_JOB_SIGS = 0 + SPECIAL_JOBSTOP_SIGS = 0 #if ENABLE_HUSH_JOB | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP) #endif + , }; -#if ENABLE_HUSH_FAST -static void SIGCHLD_handler(int sig UNUSED_PARAM) +static void record_pending_signo(int sig) { - G.count_SIGCHLD++; + sigaddset(&G.pending_set, sig); +#if ENABLE_HUSH_FAST + if (sig == SIGCHLD) { + G.count_SIGCHLD++; //bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); -} + } #endif +} + +static sighandler_t install_sighandler(int sig, sighandler_t handler) +{ + struct sigaction old_sa; + + /* We could use signal() to install handlers... almost: + * except that we need to mask ALL signals while handlers run. + * I saw signal nesting in strace, race window isn't small. + * SA_RESTART is also needed, but in Linux, signal() + * sets SA_RESTART too. + */ + /* memset(&G.sa, 0, sizeof(G.sa)); - already done */ + /* sigfillset(&G.sa.sa_mask); - already done */ + /* G.sa.sa_flags = SA_RESTART; - already done */ + G.sa.sa_handler = handler; + sigaction(sig, &G.sa, &old_sa); + return old_sa.sa_handler; +} #if ENABLE_HUSH_JOB @@ -1385,13 +1488,15 @@ static void SIGCHLD_handler(int sig UNUSED_PARAM) static void sigexit(int sig) NORETURN; static void sigexit(int sig) { - /* Disable all signals: job control, SIGPIPE, etc. */ - sigprocmask_allsigs(SIG_BLOCK); - /* Careful: we can end up here after [v]fork. Do not restore * tty pgrp then, only top-level shell process does that */ - if (G_saved_tty_pgrp && getpid() == G.root_pid) + if (G_saved_tty_pgrp && getpid() == G.root_pid) { + /* Disable all signals: job control, SIGPIPE, etc. + * Mostly paranoid measure, to prevent infinite SIGTTOU. + */ + sigprocmask_allsigs(SIG_BLOCK); tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); + } /* Not a signal, just exit */ if (sig <= 0) @@ -1406,14 +1511,43 @@ static void sigexit(int sig) #endif +static sighandler_t pick_sighandler(unsigned sig) +{ + sighandler_t handler = SIG_DFL; + if (sig < sizeof(unsigned)*8) { + unsigned sigmask = (1 << sig); + +#if ENABLE_HUSH_JOB + /* is sig fatal? */ + if (G_fatal_sig_mask & sigmask) + handler = sigexit; + else +#endif + /* sig has special handling? */ + if (G.special_sig_mask & sigmask) { + handler = record_pending_signo; + /* TTIN/TTOU/TSTP can't be set to record_pending_signo + * in order to ignore them: they will be raised + * in an endless loop when we try to do some + * terminal ioctls! We do have to _ignore_ these. + */ + if (SPECIAL_JOBSTOP_SIGS & sigmask) + handler = SIG_IGN; + } + } + return handler; +} + /* Restores tty foreground process group, and exits. */ static void hush_exit(int exitcode) NORETURN; static void hush_exit(int exitcode) { +#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(G.line_input_state); +#endif + + fflush_all(); if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { - /* Prevent recursion: - * trap "echo Hi; exit" EXIT; exit - */ char *argv[3]; /* argv[0] is unused */ argv[1] = G.traps[0]; @@ -1450,28 +1584,30 @@ static void hush_exit(int exitcode) } -static int check_and_run_traps(int sig) +//TODO: return a mask of ALL handled sigs? +static int check_and_run_traps(void) { - /* I want it in rodata, not in bss. - * gcc 4.2.1 puts it in rodata only if it has { 0, 0 } - * initializer. But other compilers may still use bss. - * TODO: find more portable solution. - */ - static const struct timespec zero_timespec = { 0, 0 }; - smalluint save_rcode; int last_sig = 0; - if (sig) - goto jump_in; while (1) { - sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); - if (sig <= 0) + int sig; + + if (sigisemptyset(&G.pending_set)) break; - jump_in: - last_sig = sig; + sig = 0; + do { + sig++; + if (sigismember(&G.pending_set, sig)) { + sigdelset(&G.pending_set, sig); + goto got_sig; + } + } while (sig < NSIG); + break; + got_sig: if (G.traps && G.traps[sig]) { if (G.traps[sig][0]) { /* We have user-defined handler */ + smalluint save_rcode; char *argv[3]; /* argv[0] is unused */ argv[1] = G.traps[sig]; @@ -1479,21 +1615,17 @@ static int check_and_run_traps(int sig) save_rcode = G.last_exitcode; builtin_eval(argv); G.last_exitcode = save_rcode; + last_sig = sig; } /* else: "" trap, ignoring signal */ continue; } /* not a trap: special action */ switch (sig) { -#if ENABLE_HUSH_FAST - case SIGCHLD: - G.count_SIGCHLD++; -//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); - break; -#endif case SIGINT: /* Builtin was ^C'ed, make it look prettier: */ bb_putchar('\n'); G.flag_SIGINT = 1; + last_sig = sig; break; #if ENABLE_HUSH_JOB case SIGHUP: { @@ -1510,8 +1642,23 @@ static int check_and_run_traps(int sig) sigexit(SIGHUP); } #endif +#if ENABLE_HUSH_FAST + case SIGCHLD: + G.count_SIGCHLD++; +//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + /* Note: + * We dont do 'last_sig = sig' here -> NOT returning this sig. + * This simplifies wait builtin a bit. + */ + break; +#endif default: /* ignored: */ /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ + /* Note: + * We dont do 'last_sig = sig' here -> NOT returning this sig. + * Example: wait is not interrupted by TERM + * in interactive shell, because TERM is ignored. + */ break; } } @@ -1833,6 +1980,7 @@ static int FAST_FUNC static_get(struct in_str *i) int ch = *i->p; if (ch != '\0') { i->p++; + i->last_char = ch; return ch; } return EOF; @@ -1890,12 +2038,18 @@ static void get_user_input(struct in_str *i) /* Enable command line editing only while a command line * is actually being read */ do { + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + reinit_unicode(get_local_var_value("LANG")); + G.flag_SIGINT = 0; /* buglet: SIGINT will not make new prompt to appear _at once_, * only after . (^C will work) */ - r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state); + r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); /* catch *SIGINT* etc (^C is handled by read_line_input) */ - check_and_run_traps(0); + check_and_run_traps(); } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ i->eof_flag = (r < 0); if (i->eof_flag) { /* EOF/error detected */ @@ -1905,11 +2059,18 @@ static void get_user_input(struct in_str *i) # else do { G.flag_SIGINT = 0; - fputs(prompt_str, stdout); + if (i->last_char == '\0' || i->last_char == '\n') { + /* Why check_and_run_traps here? Try this interactively: + * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & + * $ <[enter], repeatedly...> + * Without check_and_run_traps, handler never runs. + */ + check_and_run_traps(); + fputs(prompt_str, stdout); + } fflush_all(); G.user_input_buf[0] = r = fgetc(i->file); /*G.user_input_buf[1] = '\0'; - already is and never changed */ -//do we need check_and_run_traps(0)? (maybe only if stdin) } while (G.flag_SIGINT); i->eof_flag = (r == EOF); # endif @@ -1937,22 +2098,18 @@ static int FAST_FUNC file_get(struct in_str *i) /* need to double check i->file because we might be doing something * more complicated by now, like sourcing or substituting. */ #if ENABLE_HUSH_INTERACTIVE - if (G_interactive_fd && i->promptme && i->file == stdin) { + if (G_interactive_fd && i->file == stdin) { do { get_user_input(i); } while (!*i->p); /* need non-empty line */ i->promptmode = 1; /* PS2 */ - i->promptme = 0; goto take_cached; } #endif do ch = fgetc(i->file); while (ch == '\0'); } debug_printf("file_get: got '%c' %d\n", ch, ch); -#if ENABLE_HUSH_INTERACTIVE - if (ch == '\n') - i->promptme = 1; -#endif + i->last_char = ch; return ch; } @@ -1979,26 +2136,22 @@ static int FAST_FUNC file_peek(struct in_str *i) static void setup_file_in_str(struct in_str *i, FILE *f) { + memset(i, 0, sizeof(*i)); i->peek = file_peek; i->get = file_get; -#if ENABLE_HUSH_INTERACTIVE - i->promptme = 1; - i->promptmode = 0; /* PS1 */ -#endif + /* i->promptmode = 0; - PS1 (memset did it) */ i->file = f; - i->p = NULL; + /* i->p = NULL; */ } static void setup_string_in_str(struct in_str *i, const char *s) { + memset(i, 0, sizeof(*i)); i->peek = static_peek; i->get = static_get; -#if ENABLE_HUSH_INTERACTIVE - i->promptme = 1; - i->promptmode = 0; /* PS1 */ -#endif + /* i->promptmode = 0; - PS1 (memset did it) */ i->p = s; - i->eof_flag = 0; + /* i->eof_flag = 0; */ } @@ -2133,7 +2286,7 @@ static void o_addqblock(o_string *o, const char *str, int len) ordinary_cnt = len; o_addblock(o, str, ordinary_cnt); if (ordinary_cnt == len) - return; + return; /* NUL is already added by o_addblock */ str += ordinary_cnt; len -= ordinary_cnt + 1; /* we are processing + 1 char below */ @@ -2147,8 +2300,8 @@ static void o_addqblock(o_string *o, const char *str, int len) o_grow_by(o, sz); o->data[o->length] = ch; o->length++; - o->data[o->length] = '\0'; } + o->data[o->length] = '\0'; } static void o_addQblock(o_string *o, const char *str, int len) @@ -2237,6 +2390,7 @@ static int o_save_ptr_helper(o_string *o, int n) n, string_len, string_start); o->has_empty_slot = 0; } + o->has_quoted_part = 0; list[n] = (char*)(uintptr_t)string_len; return n + 1; } @@ -3116,14 +3270,6 @@ static int done_word(o_string *word, struct parse_context *ctx) ) { p += 3; } - if (p == word->data || p[0] != '\0') { - /* saw no "$@", or not only "$@" but some - * real text is there too */ - /* insert "empty variable" reference, this makes - * e.g. "", $empty"" etc to not disappear */ - o_addchr(word, SPECIAL_VAR_SYMBOL); - o_addchr(word, SPECIAL_VAR_SYMBOL); - } } command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); debug_print_strings("word appended to argv", command->argv); @@ -3321,6 +3467,7 @@ static char *fetch_till_str(o_string *as_string, int ch; goto jump_in; + while (1) { ch = i_getch(input); if (ch != EOF) @@ -3532,39 +3679,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx, #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS /* Subroutines for copying $(...) and `...` things */ -static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); /* '...' */ -static void add_till_single_quote(o_string *dest, struct in_str *input) +static int add_till_single_quote(o_string *dest, struct in_str *input) { while (1) { int ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch('\''); - /*xfunc_die(); - redundant */ + return 0; } if (ch == '\'') - return; + return 1; o_addchr(dest, ch); } } /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ -static void add_till_double_quote(o_string *dest, struct in_str *input) +static int add_till_double_quote(o_string *dest, struct in_str *input) { while (1) { int ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch('"'); - /*xfunc_die(); - redundant */ + return 0; } if (ch == '"') - return; + return 1; if (ch == '\\') { /* \x. Copy both chars. */ o_addchr(dest, ch); ch = i_getch(input); } o_addchr(dest, ch); if (ch == '`') { - add_till_backquote(dest, input, /*in_dquote:*/ 1); + if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) + return 0; o_addchr(dest, ch); continue; } @@ -3585,12 +3733,12 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) * Example Output * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST */ -static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) { while (1) { int ch = i_getch(input); if (ch == '`') - return; + return 1; if (ch == '\\') { /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ ch = i_getch(input); @@ -3604,7 +3752,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquo } if (ch == EOF) { syntax_error_unterm_ch('`'); - /*xfunc_die(); - redundant */ + return 0; } o_addchr(dest, ch); } @@ -3640,7 +3788,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch(end_ch); - /*xfunc_die(); - redundant */ + return 0; } if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { if (!dbl) @@ -3654,22 +3802,26 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign o_addchr(dest, ch); if (ch == '(' || ch == '{') { ch = (ch == '(' ? ')' : '}'); - add_till_closing_bracket(dest, input, ch); + if (!add_till_closing_bracket(dest, input, ch)) + return 0; o_addchr(dest, ch); continue; } if (ch == '\'') { - add_till_single_quote(dest, input); + if (!add_till_single_quote(dest, input)) + return 0; o_addchr(dest, ch); continue; } if (ch == '"') { - add_till_double_quote(dest, input); + if (!add_till_double_quote(dest, input)) + return 0; o_addchr(dest, ch); continue; } if (ch == '`') { - add_till_backquote(dest, input, /*in_dquote:*/ 0); + if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) + return 0; o_addchr(dest, ch); continue; } @@ -3678,7 +3830,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch(')'); - /*xfunc_die(); - redundant */ + return 0; } o_addchr(dest, ch); continue; @@ -3749,8 +3901,8 @@ static int parse_dollar(o_string *as_string, ) { bad_dollar_syntax: syntax_error_unterm_str("${name}"); - debug_printf_parse("parse_dollar return 1: unterminated ${name}\n"); - return 1; + debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); + return 0; } nommu_addchr(as_string, ch); ch |= quote_mask; @@ -3806,6 +3958,8 @@ static int parse_dollar(o_string *as_string, pos = dest->length; #if ENABLE_HUSH_DOLLAR_OPS last_ch = add_till_closing_bracket(dest, input, end_ch); + if (last_ch == 0) /* error? */ + return 0; #else #error Simple code to only allow ${var} is not implemented #endif @@ -3850,7 +4004,8 @@ static int parse_dollar(o_string *as_string, o_addchr(dest, /*quote_mask |*/ '+'); if (!BB_MMU) pos = dest->length; - add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); + if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) + return 0; /* error */ if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, ')'); @@ -3865,7 +4020,8 @@ static int parse_dollar(o_string *as_string, o_addchr(dest, quote_mask | '`'); if (!BB_MMU) pos = dest->length; - add_till_closing_bracket(dest, input, ')'); + if (!add_till_closing_bracket(dest, input, ')')) + return 0; /* error */ if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, ')'); @@ -3892,8 +4048,8 @@ static int parse_dollar(o_string *as_string, default: o_addQchr(dest, '$'); } - debug_printf_parse("parse_dollar return 0\n"); - return 0; + debug_printf_parse("parse_dollar return 1 (ok)\n"); + return 1; #undef as_string } @@ -3934,13 +4090,13 @@ static int encode_string(o_string *as_string, if (ch != EOF) nommu_addchr(as_string, ch); if (ch == dquote_end) { /* may be only '"' or EOF */ - debug_printf_parse("encode_string return 0\n"); - return 0; + debug_printf_parse("encode_string return 1 (ok)\n"); + return 1; } /* note: can't move it above ch == dquote_end check! */ if (ch == EOF) { syntax_error_unterm_ch('"'); - /*xfunc_die(); - redundant */ + return 0; /* error */ } next = '\0'; if (ch != '\n') { @@ -3971,10 +4127,10 @@ static int encode_string(o_string *as_string, goto again; } if (ch == '$') { - if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) { - debug_printf_parse("encode_string return 1: " - "parse_dollar returned non-0\n"); - return 1; + if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { + debug_printf_parse("encode_string return 0: " + "parse_dollar returned 0 (error)\n"); + return 0; } goto again; } @@ -3983,7 +4139,8 @@ static int encode_string(o_string *as_string, //unsigned pos = dest->length; o_addchr(dest, SPECIAL_VAR_SYMBOL); o_addchr(dest, 0x80 | '`'); - add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); + if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) + return 0; /* error */ o_addchr(dest, SPECIAL_VAR_SYMBOL); //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); goto again; @@ -3998,7 +4155,7 @@ static int encode_string(o_string *as_string, * Scan input until EOF or end_trigger char. * Return a list of pipes to execute, or NULL on EOF * or if end_trigger character is met. - * On syntax error, exit is shell is not interactive, + * On syntax error, exit if shell is not interactive, * reset parsing machinery and start parsing anew, * or return ERR_PTR. */ @@ -4027,11 +4184,6 @@ static struct pipe *parse_stream(char **pstring, * here we should use blank chars as separators, not $IFS */ - reset: /* we come back here only on syntax errors in interactive shell */ - -#if ENABLE_HUSH_INTERACTIVE - input->promptmode = 0; /* PS1 */ -#endif if (MAYBE_ASSIGNMENT != 0) dest.o_assignment = MAYBE_ASSIGNMENT; initialize_context(&ctx); @@ -4057,8 +4209,8 @@ static struct pipe *parse_stream(char **pstring, /* end_trigger == '}' case errors out earlier, * checking only ')' */ if (end_trigger == ')') { - syntax_error_unterm_ch('('); /* exits */ - /* goto parse_error; */ + syntax_error_unterm_ch('('); + goto parse_error; } if (done_word(&dest, &ctx)) { @@ -4353,42 +4505,53 @@ static struct pipe *parse_stream(char **pstring, dest.has_quoted_part = 1; break; case '$': - if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { + if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { debug_printf_parse("parse_stream parse error: " - "parse_dollar returned non-0\n"); + "parse_dollar returned 0 (error)\n"); goto parse_error; } break; case '\'': dest.has_quoted_part = 1; - while (1) { - ch = i_getch(input); - if (ch == EOF) { - syntax_error_unterm_ch('\''); - /*xfunc_die(); - redundant */ + if (next == '\'' && !ctx.pending_redirect) { + insert_empty_quoted_str_marker: + nommu_addchr(&ctx.as_string, next); + i_getch(input); /* eat second ' */ + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + } else { + while (1) { + ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch('\''); + goto parse_error; + } + nommu_addchr(&ctx.as_string, ch); + if (ch == '\'') + break; + o_addqchr(&dest, ch); } - nommu_addchr(&ctx.as_string, ch); - if (ch == '\'') - break; - o_addqchr(&dest, ch); } break; case '"': dest.has_quoted_part = 1; + if (next == '"' && !ctx.pending_redirect) + goto insert_empty_quoted_str_marker; if (dest.o_assignment == NOT_ASSIGNMENT) dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; - if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) + if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) goto parse_error; dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; break; #if ENABLE_HUSH_TICK case '`': { - unsigned pos; + USE_FOR_NOMMU(unsigned pos;) o_addchr(&dest, SPECIAL_VAR_SYMBOL); o_addchr(&dest, '`'); - pos = dest.length; - add_till_backquote(&dest, input, /*in_dquote:*/ 0); + USE_FOR_NOMMU(pos = dest.length;) + if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) + goto parse_error; # if !BB_MMU o_addstr(&ctx.as_string, dest.data + pos); o_addchr(&ctx.as_string, '`'); @@ -4527,23 +4690,15 @@ static struct pipe *parse_stream(char **pstring, } IF_HAS_KEYWORDS(pctx = p2;) } while (HAS_KEYWORDS && pctx); - /* Free text, clear all dest fields */ + o_free(&dest); - /* If we are not in top-level parse, we return, - * our caller will propagate error. - */ - if (end_trigger != ';') { + G.last_exitcode = 1; #if !BB_MMU - if (pstring) - *pstring = NULL; + if (pstring) + *pstring = NULL; #endif - debug_leave(); - return ERR_PTR; - } - /* Discard cached input, force prompt */ - input->p = NULL; - IF_HUSH_INTERACTIVE(input->promptme = 1;) - goto reset; + debug_leave(); + return ERR_PTR; } } @@ -4603,12 +4758,22 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len /* Store given string, finalizing the word and starting new one whenever * we encounter IFS char(s). This is used for expanding variable values. - * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ -static int expand_on_ifs(o_string *output, int n, const char *str) + * End-of-string does NOT finalize word: think about 'echo -$VAR-'. + * Return in *ended_with_ifs: + * 1 - ended with IFS char, else 0 (this includes case of empty str). + */ +static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) { + int last_is_ifs = 0; + while (1) { - int word_len = strcspn(str, G.ifs); + int word_len; + + if (!*str) /* EOL - do not finalize word */ + break; + word_len = strcspn(str, G.ifs); if (word_len) { + /* We have WORD_LEN leading non-IFS chars */ if (!(output->o_expflags & EXP_FLAG_GLOB)) { o_addblock(output, str, word_len); } else { @@ -4621,15 +4786,36 @@ static int expand_on_ifs(o_string *output, int n, const char *str) /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ } + last_is_ifs = 0; str += word_len; + if (!*str) /* EOL - do not finalize word */ + break; } + + /* We know str here points to at least one IFS char */ + last_is_ifs = 1; + str += strspn(str, G.ifs); /* skip IFS chars */ if (!*str) /* EOL - do not finalize word */ break; - o_addchr(output, '\0'); - debug_print_list("expand_on_ifs", output, n); - n = o_save_ptr(output, n); - str += strspn(str, G.ifs); /* skip ifs chars */ + + /* Start new word... but not always! */ + /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ + if (output->has_quoted_part + /* Case "v=' a'; echo $v": + * here nothing precedes the space in $v expansion, + * therefore we should not finish the word + * (IOW: if there *is* word to finalize, only then do it): + */ + || (n > 0 && output->data[output->length - 1]) + ) { + o_addchr(output, '\0'); + debug_print_list("expand_on_ifs", output, n); + n = o_save_ptr(output, n); + } } + + if (ended_with_ifs) + *ended_with_ifs = last_is_ifs; debug_print_list("expand_on_ifs[1]", output, n); return n; } @@ -4666,6 +4852,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int */ setup_string_in_str(&input, str); encode_string(NULL, &dest, &input, EOF, process_bkslash); +//TODO: error check (encode_string returns 0 on error)? //bb_error_msg("'%s' -> '%s'", str, dest.data); exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); @@ -5043,6 +5230,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) * expansion of right-hand side of assignment == 1-element expand. */ char cant_be_null = 0; /* only bit 0x80 matters */ + int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ char *p; debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, @@ -5061,6 +5249,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) #if ENABLE_SH_MATH_SUPPORT char arith_buf[sizeof(arith_t)*3 + 2]; #endif + + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + ended_in_ifs = 0; + } + o_addblock(output, arg, p - arg); debug_print_list("expand_vars_to_list[1]", output, n); arg = ++p; @@ -5089,7 +5284,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ while (G.global_argv[i]) { - n = expand_on_ifs(output, n, G.global_argv[i]); + n = expand_on_ifs(NULL, output, n, G.global_argv[i]); debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); if (G.global_argv[i++][0] && G.global_argv[i]) { /* this argv[] is not empty and not last: @@ -5122,11 +5317,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) if (G.ifs[0]) o_addchr(output, G.ifs[0]); } + output->has_quoted_part = 1; } break; } case SPECIAL_VAR_SYMBOL: /* */ /* "Empty variable", used to make "" etc to not disappear */ + output->has_quoted_part = 1; arg++; cant_be_null = 0x80; break; @@ -5164,10 +5361,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); if (val && val[0]) { - n = expand_on_ifs(output, n, val); + n = expand_on_ifs(&ended_in_ifs, output, n, val); val = NULL; } } else { /* quoted $VAR, val will be appended below */ + output->has_quoted_part = 1; debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); } @@ -5192,6 +5390,10 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ if (arg[0]) { + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + } debug_print_list("expand_vars_to_list[a]", output, n); /* this part is literal, and it was already pre-quoted * if needed (much earlier), do not use o_addQstr here! */ @@ -5322,6 +5524,25 @@ static char **expand_assignments(char **argv, int count) } +static void switch_off_special_sigs(unsigned mask) +{ + unsigned sig = 0; + while ((mask >>= 1) != 0) { + sig++; + if (!(mask & 1)) + continue; + if (G.traps) { + if (G.traps[sig] && !G.traps[sig][0]) + /* trap is '', has to remain SIG_IGN */ + continue; + free(G.traps[sig]); + G.traps[sig] = NULL; + } + /* We are here only if no trap or trap was not '' */ + install_sighandler(sig, SIG_DFL); + } +} + #if BB_MMU /* never called */ void re_execute_shell(char ***to_free, const char *s, @@ -5341,47 +5562,36 @@ static void reset_traps_to_defaults(void) * Testcase: (while :; do :; done) + ^Z should background. * Same goes for SIGTERM, SIGHUP, SIGINT. */ - if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) - return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ - - /* Switching off SPECIAL_INTERACTIVE_SIGS. - * Stupid. It can be done with *single* &= op, but we can't use - * the fact that G.blocked_set is implemented as a bitmask - * in libc... */ - mask = (SPECIAL_INTERACTIVE_SIGS >> 1); - sig = 1; - while (1) { - if (mask & 1) { - /* Careful. Only if no trap or trap is not "" */ - if (!G.traps || !G.traps[sig] || G.traps[sig][0]) - sigdelset(&G.blocked_set, sig); - } - mask >>= 1; - if (!mask) - break; - sig++; - } - /* Our homegrown sig mask is saner to work with :) */ - G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; + mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask; + if (!G.traps && !mask) + return; /* already no traps and no special sigs */ - /* Resetting all traps to default except empty ones */ - mask = G.non_DFL_mask; - if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { - if (!G.traps[sig] || !G.traps[sig][0]) - continue; + /* Switch off special sigs */ + switch_off_special_sigs(mask); +#if ENABLE_HUSH_JOB + G_fatal_sig_mask = 0; +#endif + G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; + /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS + * remain set in G.special_sig_mask */ + + if (!G.traps) + return; + + /* Reset all sigs to default except ones with empty traps */ + for (sig = 0; sig < NSIG; sig++) { + if (!G.traps[sig]) + continue; /* no trap: nothing to do */ + if (!G.traps[sig][0]) + continue; /* empty trap: has to remain SIG_IGN */ + /* sig has non-empty trap, reset it: */ free(G.traps[sig]); G.traps[sig] = NULL; - /* There is no signal for 0 (EXIT) */ + /* There is no signal for trap 0 (EXIT) */ if (sig == 0) continue; - /* There was a trap handler, we just removed it. - * But if sig still has non-DFL handling, - * we should not unblock the sig. */ - if (mask & 1) - continue; - sigdelset(&G.blocked_set, sig); + install_sighandler(sig, pick_sighandler(sig)); } - sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); } #else /* !BB_MMU */ @@ -5492,9 +5702,6 @@ static void re_execute_shell(char ***to_free, const char *s, * _inside_ group (just before echo 1), it works. * * I conclude it means we don't need to pass active traps here. - * Even if we would use signal handlers instead of signal masking - * in order to implement trap handling, - * exec syscall below resets signals to SIG_DFL for us. */ *pp++ = (char *) "-c"; *pp++ = (char *) s; @@ -5511,7 +5718,9 @@ static void re_execute_shell(char ***to_free, const char *s, do_exec: debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execve(bb_busybox_exec_path, argv, pp); /* Fallback. Useful for init=/bin/hush usage etc */ if (argv[0][0] == '/') @@ -5542,9 +5751,29 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) while (1) { struct pipe *pipe_list; +#if ENABLE_HUSH_INTERACTIVE + if (end_trigger == ';') + inp->promptmode = 0; /* PS1 */ +#endif pipe_list = parse_stream(NULL, inp, end_trigger); - if (!pipe_list) { /* EOF */ - if (empty) + if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ + /* If we are in "big" script + * (not in `cmd` or something similar)... + */ + if (pipe_list == ERR_PTR && end_trigger == ';') { + /* Discard cached input (rest of line) */ + int ch = inp->last_char; + while (ch != EOF && ch != '\n') { + //bb_error_msg("Discarded:'%c'", ch); + ch = i_getch(inp); + } + /* Force prompt */ + inp->p = NULL; + /* This stream isn't empty */ + empty = 0; + continue; + } + if (!pipe_list && empty) G.last_exitcode = 0; break; } @@ -5552,6 +5781,10 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); run_and_free_list(pipe_list); empty = 0; +#if ENABLE_HUSH_FUNCTIONS + if (G.flag_return_in_progress == 1) + break; +#endif } } @@ -6118,10 +6351,13 @@ static void exec_builtin(char ***to_free, char **argv) { #if BB_MMU - int rcode = x->b_function(argv); + int rcode; + fflush_all(); + rcode = x->b_function(argv); fflush_all(); _exit(rcode); #else + fflush_all(); /* On NOMMU, we must never block! * Example: { sleep 99 | read line; } & echo Ok */ @@ -6138,7 +6374,9 @@ static void execvp_or_die(char **argv) NORETURN; static void execvp_or_die(char **argv) { debug_printf_exec("execing '%s'\n", argv[0]); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execvp(argv[0], argv); bb_perror_msg("can't execute '%s'", argv[0]); _exit(127); /* bash compat */ @@ -6270,7 +6508,9 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, # endif /* Re-exec ourselves */ debug_printf_exec("re-execing applet '%s'\n", argv[0]); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execv(bb_busybox_exec_path, argv); /* If they called chroot or otherwise made the binary no longer * executable, fall through */ @@ -6513,20 +6753,21 @@ static int checkjobs(struct pipe *fg_pipe) fg_pipe->alive_cmds--; ex = WEXITSTATUS(status); /* bash prints killer signal's name for *last* - * process in pipe (prints just newline for SIGINT). + * process in pipe (prints just newline for SIGINT/SIGPIPE). * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) */ if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); if (i == fg_pipe->num_cmds-1) - printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); + /* TODO: use strsignal() instead for bash compat? but that's bloat... */ + printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); + /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? * Maybe we need to use sig | 128? */ ex = sig + 128; } fg_pipe->cmds[i].cmd_exitcode = ex; } else { - fg_pipe->cmds[i].is_stopped = 1; fg_pipe->stopped_cmds++; } debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", @@ -6587,7 +6828,6 @@ static int checkjobs(struct pipe *fg_pipe) } } else { /* child stopped */ - pi->cmds[i].is_stopped = 1; pi->stopped_cmds++; } #endif @@ -6628,7 +6868,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) * cmd ; ... { list } ; ... * cmd && ... { list } && ... * cmd || ... { list } || ... - * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], + * If it is, then we can run cmd as a builtin, NOFORK, * or (if SH_STANDALONE) an applet, and we can run the { list } * with run_list. If it isn't one of these, we fork and exec cmd. * @@ -6810,13 +7050,12 @@ static NOINLINE int run_pipe(struct pipe *pi) } /* Expand the rest into (possibly) many strings each */ - if (0) {} #if ENABLE_HUSH_BASH_COMPAT - else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { + if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); - } + } else #endif - else { + { argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); } @@ -6846,6 +7085,7 @@ static NOINLINE int run_pipe(struct pipe *pi) if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", x->b_cmd, argv_expanded[1]); + fflush_all(); rcode = x->b_function(argv_expanded) & 0xff; fflush_all(); } @@ -6878,7 +7118,7 @@ static NOINLINE int run_pipe(struct pipe *pi) return rcode; } - if (ENABLE_FEATURE_SH_STANDALONE) { + if (ENABLE_FEATURE_SH_NOFORK) { int n = find_applet_by_name(argv_expanded[0]); if (n >= 0 && APPLET_IS_NOFORK(n)) { rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); @@ -6967,9 +7207,6 @@ static NOINLINE int run_pipe(struct pipe *pi) if (setup_redirects(command, NULL)) _exit(1); - /* Restore default handlers just prior to exec */ - /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */ - /* Stores to nommu_save list of env vars putenv'ed * (NOMMU, on MMU we don't need that) */ /* cast away volatility... */ @@ -7247,7 +7484,7 @@ static int run_list(struct pipe *pi) * and we don't need to wait for anything. */ G.last_exitcode = rcode; debug_printf_exec(": builtin/func exitcode %d\n", rcode); - check_and_run_traps(0); + check_and_run_traps(); #if ENABLE_HUSH_LOOPS /* Was it "break" or "continue"? */ if (G.flag_break_continue) { @@ -7279,7 +7516,7 @@ static int run_list(struct pipe *pi) /* even bash 3.2 doesn't do that well with nested bg: * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". * I'm NOT treating inner &'s as jobs */ - check_and_run_traps(0); + check_and_run_traps(); #if ENABLE_HUSH_JOB if (G.run_list_level == 1) insert_bg_job(pi); @@ -7294,13 +7531,13 @@ static int run_list(struct pipe *pi) /* Waits for completion, then fg's main shell */ rcode = checkjobs_and_fg_shell(pi); debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); - check_and_run_traps(0); + check_and_run_traps(); } else #endif { /* This one just waits for completion */ rcode = checkjobs(pi); debug_printf_exec(": checkjobs exitcode %d\n", rcode); - check_and_run_traps(0); + check_and_run_traps(); } G.last_exitcode = rcode; } @@ -7315,7 +7552,7 @@ static int run_list(struct pipe *pi) /* Beware of "while false; true; do ..."! */ if (pi->next && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE) - /* (the second check above is needed for "while ...; do \n done" case) */ + /* check for RES_DONE is needed for "while ...; do \n done" case */ ) { if (rword == RES_WHILE) { if (rcode) { @@ -7361,7 +7598,7 @@ static int run_and_free_list(struct pipe *pi) { int rcode = 0; debug_printf_exec("run_and_free_list entered\n"); - if (!G.n_mode) { + if (!G.o_opt[OPT_O_NOEXEC]) { debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); rcode = run_list(pi); } @@ -7374,88 +7611,81 @@ static int run_and_free_list(struct pipe *pi) } +static void install_sighandlers(unsigned mask) +{ + sighandler_t old_handler; + unsigned sig = 0; + while ((mask >>= 1) != 0) { + sig++; + if (!(mask & 1)) + continue; + old_handler = install_sighandler(sig, pick_sighandler(sig)); + /* POSIX allows shell to re-enable SIGCHLD + * even if it was SIG_IGN on entry. + * Therefore we skip IGN check for it: + */ + if (sig == SIGCHLD) + continue; + if (old_handler == SIG_IGN) { + /* oops... restore back to IGN, and record this fact */ + install_sighandler(sig, old_handler); + if (!G.traps) + G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); + free(G.traps[sig]); + G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ + } + } +} + /* Called a few times only (or even once if "sh -c") */ -static void init_sigmasks(void) +static void install_special_sighandlers(void) { - unsigned sig; unsigned mask; - sigset_t old_blocked_set; - if (!G.inherited_set_is_saved) { - sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); - G.inherited_set = G.blocked_set; - } - old_blocked_set = G.blocked_set; - - mask = (1 << SIGQUIT); + /* Which signals are shell-special? */ + mask = (1 << SIGQUIT) | (1 << SIGCHLD); if (G_interactive_fd) { - mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS; + mask |= SPECIAL_INTERACTIVE_SIGS; if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ - mask |= SPECIAL_JOB_SIGS; + mask |= SPECIAL_JOBSTOP_SIGS; } - G.non_DFL_mask = mask; - - sig = 0; - while (mask) { - if (mask & 1) - sigaddset(&G.blocked_set, sig); - mask >>= 1; - sig++; + /* Careful, do not re-install handlers we already installed */ + if (G.special_sig_mask != mask) { + unsigned diff = mask & ~G.special_sig_mask; + G.special_sig_mask = mask; + install_sighandlers(diff); } - sigdelset(&G.blocked_set, SIGCHLD); - - if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0) - sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); - - /* POSIX allows shell to re-enable SIGCHLD - * even if it was SIG_IGN on entry */ -#if ENABLE_HUSH_FAST - G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ - if (!G.inherited_set_is_saved) - signal(SIGCHLD, SIGCHLD_handler); -#else - if (!G.inherited_set_is_saved) - signal(SIGCHLD, SIG_DFL); -#endif - - G.inherited_set_is_saved = 1; } #if ENABLE_HUSH_JOB /* helper */ -static void maybe_set_to_sigexit(int sig) -{ - void (*handler)(int); - /* non_DFL_mask'ed signals are, well, masked, - * no need to set handler for them. - */ - if (!((G.non_DFL_mask >> sig) & 1)) { - handler = signal(sig, sigexit); - if (handler == SIG_IGN) /* oops... restore back to IGN! */ - signal(sig, handler); - } -} /* Set handlers to restore tty pgrp and exit */ -static void set_fatal_handlers(void) -{ - /* We _must_ restore tty pgrp on fatal signals */ - if (HUSH_DEBUG) { - maybe_set_to_sigexit(SIGILL ); - maybe_set_to_sigexit(SIGFPE ); - maybe_set_to_sigexit(SIGBUS ); - maybe_set_to_sigexit(SIGSEGV); - maybe_set_to_sigexit(SIGTRAP); - } /* else: hush is perfect. what SEGV? */ - maybe_set_to_sigexit(SIGABRT); +static void install_fatal_sighandlers(void) +{ + unsigned mask; + + /* We will restore tty pgrp on these signals */ + mask = 0 + + (1 << SIGILL ) * HUSH_DEBUG + + (1 << SIGFPE ) * HUSH_DEBUG + + (1 << SIGBUS ) * HUSH_DEBUG + + (1 << SIGSEGV) * HUSH_DEBUG + + (1 << SIGTRAP) * HUSH_DEBUG + + (1 << SIGABRT) /* bash 3.2 seems to handle these just like 'fatal' ones */ - maybe_set_to_sigexit(SIGPIPE); - maybe_set_to_sigexit(SIGALRM); - /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. + + (1 << SIGPIPE) + + (1 << SIGALRM) + /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs. * if we aren't interactive... but in this case - * we never want to restore pgrp on exit, and this fn is not called */ - /*maybe_set_to_sigexit(SIGHUP );*/ - /*maybe_set_to_sigexit(SIGTERM);*/ - /*maybe_set_to_sigexit(SIGINT );*/ + * we never want to restore pgrp on exit, and this fn is not called + */ + /*+ (1 << SIGHUP )*/ + /*+ (1 << SIGTERM)*/ + /*+ (1 << SIGINT )*/ + ; + G_fatal_sig_mask = mask; + + install_sighandlers(mask); } #endif @@ -7464,7 +7694,7 @@ static int set_mode(int state, char mode, const char *o_opt) int idx; switch (mode) { case 'n': - G.n_mode = state; + G.o_opt[OPT_O_NOEXEC] = state; break; case 'x': IF_HUSH_MODE_X(G_x_mode = state;) @@ -7501,6 +7731,10 @@ static int set_mode(int state, char mode, const char *o_opt) int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int hush_main(int argc, char **argv) { + enum { + OPT_login = (1 << 0), + }; + unsigned flags; int opt; unsigned builtin_argc; char **e; @@ -7508,8 +7742,11 @@ int hush_main(int argc, char **argv) struct variable *shell_ver; INIT_G(); - if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ + if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ G.last_exitcode = EXIT_SUCCESS; +#if ENABLE_HUSH_FAST + G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ +#endif #if !BB_MMU G.argv0_for_re_execing = argv[0]; #endif @@ -7583,22 +7820,8 @@ int hush_main(int argc, char **argv) #if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); -# if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY - { - const char *hp = get_local_var_value("HISTFILE"); - if (!hp) { - hp = get_local_var_value("HOME"); - if (hp) { - G.line_input_state->hist_file = concat_path_file(hp, ".hush_history"); - //set_local_var(xasprintf("HISTFILE=%s", ...)); - } - } - } -# endif #endif - G.global_argc = argc; - G.global_argv = argv; /* Initialize some more globals to non-zero values */ cmdedit_update_prompt(); @@ -7610,17 +7833,18 @@ int hush_main(int argc, char **argv) } /* Shell is non-interactive at first. We need to call - * init_sigmasks() if we are going to execute "sh