From f49df5de66d4ac16eec6eca19e68f06018348a34 Mon Sep 17 00:00:00 2001 From: Keith Moyer Date: Sat, 23 May 2009 16:40:45 -0500 Subject: [PATCH] Tomato 1.24 --- release/src/Makefile | 40 +- release/src/linux/linux/.config | 6 +- .../src/linux/linux/Documentation/Configure.help | 34 + .../arch/mips/brcm-boards/bcm947xx/prom-orig.c | 41 + .../linux/arch/mips/brcm-boards/bcm947xx/prom.c | 43 +- release/src/linux/linux/arch/mips/kernel/branch.c | 2 +- .../src/linux/linux/arch/mips/math-emu/cp1emu.c | 5 +- .../src/linux/linux/drivers/mtd/chips/gen_probe.c | 1 + .../linux/include/linux/netfilter_ipv4/ipt_ROUTE.h | 23 + .../linux/include/linux/netfilter_ipv4/ipt_ipp2p.h | 31 + .../include/linux/netfilter_ipv6/ip6t_ROUTE.h | 23 + release/src/linux/linux/net/ipv4/arp.c | 24 +- release/src/linux/linux/net/ipv4/igmp.c | 5 +- .../src/linux/linux/net/ipv4/netfilter/Config.in | 4 +- .../src/linux/linux/net/ipv4/netfilter/Makefile | 2 + .../src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c | 422 + .../linux/linux/net/ipv4/netfilter/ipt_connlimit.c | 1 + .../src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c | 868 ++ release/src/linux/linux/net/ipv4/route.c | 10 - release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c | 12 - release/src/linux/linux/net/ipv4/tcp_input.c | 311 +- release/src/linux/linux/net/ipv4/tcp_minisocks.c | 3 +- release/src/linux/linux/net/ipv4/tcp_output.c | 20 +- .../src/linux/linux/net/ipv6/netfilter/Config.in | 2 + .../src/linux/linux/net/ipv6/netfilter/Makefile | 1 + .../linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c | 308 + release/src/router/Makefile | 73 +- release/src/router/busybox/.config | 883 +++ release/src/router/busybox/AUTHORS | 2 +- release/src/router/busybox/Config.in | 52 +- release/src/router/busybox/Makefile | 14 +- release/src/router/busybox/Makefile.custom | 6 + release/src/router/busybox/Makefile.flags | 12 +- release/src/router/busybox/Makefile.help | 1 + release/src/router/busybox/README | 2 +- release/src/router/busybox/TODO | 23 +- release/src/router/busybox/TODO_config_nommu | 167 +- release/src/router/busybox/applets/usage.c | 5 + .../src/router/busybox/applets/usage_compressed | 2 +- release/src/router/busybox/archival/Config.in | 12 +- release/src/router/busybox/archival/bbunzip.c | 32 +- release/src/router/busybox/archival/bzip2.c | 3 +- release/src/router/busybox/archival/cpio.c | 251 +- release/src/router/busybox/archival/dpkg.c | 135 +- release/src/router/busybox/archival/gzip.c | 3 +- .../archival/libunarchive/data_extract_all.c | 4 +- .../archival/libunarchive/decompress_unzip.c | 31 +- .../archival/libunarchive/get_header_cpio.c | 3 +- .../busybox/archival/libunarchive/get_header_tar.c | 77 +- .../archival/libunarchive/header_verbose_list.c | 4 +- release/src/router/busybox/archival/rpm.c | 30 +- release/src/router/busybox/archival/tar.c | 9 +- release/src/router/busybox/archival/unzip.c | 243 +- release/src/router/busybox/config_g | 853 -- release/src/router/busybox/console-tools/Config.in | 15 + .../src/router/busybox/console-tools/kbd_mode.c | 21 +- .../src/router/busybox/console-tools/loadfont.c | 196 +- .../src/router/busybox/console-tools/loadkmap.c | 10 +- release/src/router/busybox/console-tools/resize.c | 2 +- .../src/router/busybox/console-tools/setconsole.c | 2 +- release/src/router/busybox/console-tools/showkey.c | 6 +- release/src/router/busybox/coreutils/Config.in | 24 +- release/src/router/busybox/coreutils/Kbuild | 3 + release/src/router/busybox/coreutils/basename.c | 1 + release/src/router/busybox/coreutils/cksum.c | 25 +- release/src/router/busybox/coreutils/cp.c | 50 +- release/src/router/busybox/coreutils/cut.c | 2 +- release/src/router/busybox/coreutils/date.c | 2 +- release/src/router/busybox/coreutils/dd.c | 1 - release/src/router/busybox/coreutils/df.c | 98 +- release/src/router/busybox/coreutils/du.c | 82 +- release/src/router/busybox/coreutils/env.c | 18 +- release/src/router/busybox/coreutils/expand.c | 120 +- release/src/router/busybox/coreutils/expr.c | 23 +- release/src/router/busybox/coreutils/head.c | 8 +- release/src/router/busybox/coreutils/id.c | 340 +- release/src/router/busybox/coreutils/id_test.sh | 244 + release/src/router/busybox/coreutils/install.c | 61 +- release/src/router/busybox/coreutils/length.c | 3 + .../busybox/coreutils/libcoreutils/coreutils.h | 10 +- release/src/router/busybox/coreutils/ls.c | 490 +- .../src/router/busybox/coreutils/md5_sha1_sum.c | 35 +- release/src/router/busybox/coreutils/nohup.c | 2 +- release/src/router/busybox/coreutils/printenv.c | 6 +- release/src/router/busybox/coreutils/printf.c | 133 +- release/src/router/busybox/coreutils/rm.c | 5 +- release/src/router/busybox/coreutils/seq.c | 23 +- release/src/router/busybox/coreutils/split.c | 2 +- release/src/router/busybox/coreutils/stat.c | 27 +- release/src/router/busybox/coreutils/tail.c | 2 +- release/src/router/busybox/coreutils/tee.c | 1 - release/src/router/busybox/coreutils/test.c | 2 +- release/src/router/busybox/coreutils/touch.c | 20 +- release/src/router/busybox/coreutils/tr.c | 297 +- release/src/router/busybox/coreutils/tty.c | 2 +- release/src/router/busybox/coreutils/uname.c | 123 +- release/src/router/busybox/coreutils/uniq.c | 2 +- release/src/router/busybox/coreutils/who.c | 1 - release/src/router/busybox/coreutils/whoami.c | 2 +- release/src/router/busybox/debianutils/Config.in | 1 + release/src/router/busybox/debianutils/run_parts.c | 2 +- .../router/busybox/debianutils/start_stop_daemon.c | 8 +- .../busybox/docs/Serial-Programming-HOWTO.txt | 424 + release/src/router/busybox/docs/autodocifier.pl | 4 + .../src/router/busybox/docs/busybox.net/FAQ.html | 89 +- .../src/router/busybox/docs/busybox.net/about.html | 2 +- .../router/busybox/docs/busybox.net/download.html | 34 +- .../src/router/busybox/docs/busybox.net/fix.html | 2 +- .../router/busybox/docs/busybox.net/footer.html | 20 +- .../router/busybox/docs/busybox.net/header.html | 45 +- .../router/busybox/docs/busybox.net/license.html | 30 +- .../src/router/busybox/docs/busybox.net/links.html | 4 +- .../src/router/busybox/docs/busybox.net/lists.html | 4 +- .../src/router/busybox/docs/busybox.net/news.html | 820 +- .../router/busybox/docs/busybox.net/oldnews.html | 449 +- .../router/busybox/docs/busybox.net/products.html | 335 +- .../router/busybox/docs/busybox.net/sponsors.html | 18 +- .../busybox/docs/busybox.net/subversion.html | 6 +- .../router/busybox/docs/busybox.net/svnindex.css | 92 + .../router/busybox/docs/busybox.net/svnindex.xsl | 108 + .../router/busybox/docs/busybox.net/tinyutils.html | 22 +- release/src/router/busybox/docs/busybox_header.pod | 11 +- .../busybox/docs/logging_and_backgrounding.txt | 96 + release/src/router/busybox/docs/mdev.txt | 6 +- release/src/router/busybox/e2fsprogs/e2fs_defs.h | 6 +- release/src/router/busybox/e2fsprogs/e2fs_lib.c | 3 +- release/src/router/busybox/e2fsprogs/e2fs_lib.h | 8 +- release/src/router/busybox/e2fsprogs/fsck.c | 9 +- .../busybox/e2fsprogs/old_e2fsprogs/blkid/blkid.h | 7 +- .../busybox/e2fsprogs/old_e2fsprogs/blkid/blkidP.h | 7 +- .../e2fsprogs/old_e2fsprogs/blkid/devname.c | 4 +- .../busybox/e2fsprogs/old_e2fsprogs/blkid/list.h | 4 +- .../busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c | 4 +- .../busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h | 17 +- .../busybox/e2fsprogs/old_e2fsprogs/e2fsbb.h | 6 +- .../busybox/e2fsprogs/old_e2fsprogs/e2fsck.c | 56 +- .../e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c | 4 +- .../e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c | 2 +- .../e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h | 7 +- .../e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h | 8 +- .../e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h | 7 +- .../e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h | 7 +- .../e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h | 4 +- .../e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c | 2 +- .../e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c | 6 +- .../router/busybox/e2fsprogs/old_e2fsprogs/fsck.c | 35 +- .../busybox/e2fsprogs/old_e2fsprogs/mke2fs.c | 7 +- .../busybox/e2fsprogs/old_e2fsprogs/tune2fs.c | 5 +- .../router/busybox/e2fsprogs/old_e2fsprogs/util.c | 21 +- .../e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c | 2 +- .../busybox/e2fsprogs/old_e2fsprogs/uuid/uuid.h | 5 +- release/src/router/busybox/editors/Config.in | 4 +- release/src/router/busybox/editors/awk.c | 117 +- release/src/router/busybox/editors/diff.c | 18 +- release/src/router/busybox/editors/vi.c | 500 +- release/src/router/busybox/examples/depmod-t.pl | 293 + release/src/router/busybox/findutils/Config.in | 2 +- release/src/router/busybox/findutils/find.c | 22 +- release/src/router/busybox/findutils/grep.c | 21 +- release/src/router/busybox/include/applets.h | 23 +- release/src/router/busybox/include/busybox.h | 14 +- release/src/router/busybox/include/dump.h | 8 +- release/src/router/busybox/include/grp_.h | 43 +- release/src/router/busybox/include/libbb.h | 225 +- release/src/router/busybox/include/platform.h | 77 +- release/src/router/busybox/include/pwd_.h | 41 +- release/src/router/busybox/include/rtc_.h | 49 +- release/src/router/busybox/include/shadow_.h | 45 +- release/src/router/busybox/include/unarchive.h | 23 +- release/src/router/busybox/include/usage.h | 733 +- release/src/router/busybox/include/volume_id.h | 1 + release/src/router/busybox/include/xatonum.h | 8 +- release/src/router/busybox/include/xregex.h | 12 +- release/src/router/busybox/init/Config.in | 15 +- release/src/router/busybox/init/halt.c | 79 +- release/src/router/busybox/init/init.c | 926 ++- release/src/router/busybox/init/mesg.c | 2 +- release/src/router/busybox/libbb/Kbuild | 13 +- release/src/router/busybox/libbb/appletlib.c | 6 +- release/src/router/busybox/libbb/bb_askpass.c | 18 +- release/src/router/busybox/libbb/bb_pwd.c | 211 +- release/src/router/busybox/libbb/bb_strtod.c | 3 +- .../src/router/busybox/libbb/correct_password.c | 2 +- release/src/router/busybox/libbb/crc32.c | 2 + .../src/router/busybox/libbb/create_icmp6_socket.c | 2 + .../src/router/busybox/libbb/create_icmp_socket.c | 2 + release/src/router/busybox/libbb/crypt_make_salt.c | 45 - .../src/router/busybox/libbb/die_if_bad_username.c | 2 +- release/src/router/busybox/libbb/dump.c | 17 +- release/src/router/busybox/libbb/fgets_str.c | 26 +- .../src/router/busybox/libbb/find_pid_by_name.c | 15 +- release/src/router/busybox/libbb/get_console.c | 2 - release/src/router/busybox/libbb/getopt32.c | 14 +- release/src/router/busybox/libbb/human_readable.c | 35 +- release/src/router/busybox/libbb/inet_common.c | 5 +- release/src/router/busybox/libbb/info_msg.c | 26 + release/src/router/busybox/libbb/inode_hash.c | 2 +- release/src/router/busybox/libbb/lineedit.c | 154 +- release/src/router/busybox/libbb/llist.c | 68 +- release/src/router/busybox/libbb/make_directory.c | 2 +- release/src/router/busybox/libbb/match_fstype.c | 36 +- release/src/router/busybox/libbb/md5.c | 875 +-- release/src/router/busybox/libbb/md5prime.c | 460 ++ release/src/router/busybox/libbb/parse_config.c | 3 +- .../router/busybox/libbb/process_escape_sequence.c | 17 +- release/src/router/busybox/libbb/procps.c | 45 +- release/src/router/busybox/libbb/pw_encrypt.c | 93 +- release/src/router/busybox/libbb/pw_encrypt_des.c | 70 +- release/src/router/busybox/libbb/pw_encrypt_md5.c | 809 +- release/src/router/busybox/libbb/pw_encrypt_sha.c | 286 + release/src/router/busybox/libbb/read.c | 6 +- release/src/router/busybox/libbb/read_key.c | 157 + release/src/router/busybox/libbb/rtc.c | 2 + release/src/router/busybox/libbb/selinux_common.c | 2 + release/src/router/busybox/libbb/sha1.c | 635 +- release/src/router/busybox/libbb/signals.c | 10 +- release/src/router/busybox/libbb/speed_table.c | 1 - release/src/router/busybox/libbb/strrstr.c | 2 +- release/src/router/busybox/libbb/update_passwd.c | 167 +- .../src/router/busybox/libbb/vfork_daemon_rexec.c | 27 +- release/src/router/busybox/libbb/wfopen.c | 2 +- release/src/router/busybox/libbb/write.c | 7 +- .../src/router/busybox/libbb/xatonum_template.c | 4 + release/src/router/busybox/libbb/xconnect.c | 45 +- release/src/router/busybox/libbb/xfuncs.c | 24 + release/src/router/busybox/libbb/xfuncs_printf.c | 29 +- release/src/router/busybox/libbb/xgetcwd.c | 4 +- release/src/router/busybox/libbb/xreadlink.c | 12 +- release/src/router/busybox/libpwdgrp/pwd_grp.c | 68 +- release/src/router/busybox/libpwdgrp/uidgid_get.c | 5 +- release/src/router/busybox/loginutils/Config.in | 29 +- release/src/router/busybox/loginutils/addgroup.c | 78 +- release/src/router/busybox/loginutils/adduser.c | 52 +- release/src/router/busybox/loginutils/chpasswd.c | 5 +- release/src/router/busybox/loginutils/cryptpw.c | 175 +- release/src/router/busybox/loginutils/deluser.c | 181 +- release/src/router/busybox/loginutils/getty.c | 45 +- release/src/router/busybox/loginutils/login.c | 227 +- release/src/router/busybox/loginutils/passwd.c | 23 +- release/src/router/busybox/loginutils/su.c | 6 +- release/src/router/busybox/loginutils/sulogin.c | 9 +- release/src/router/busybox/loginutils/vlock.c | 11 +- release/src/router/busybox/mailutils/Config.in | 53 + release/src/router/busybox/mailutils/Kbuild | 11 + release/src/router/busybox/mailutils/mail.c | 248 + release/src/router/busybox/mailutils/mail.h | 35 + release/src/router/busybox/mailutils/mime.c | 354 + release/src/router/busybox/mailutils/popmaildir.c | 235 + release/src/router/busybox/mailutils/sendmail.c | 259 + release/src/router/busybox/miscutils/Config.in | 91 +- release/src/router/busybox/miscutils/Kbuild | 4 + release/src/router/busybox/miscutils/chat.c | 97 +- release/src/router/busybox/miscutils/chrt.c | 2 +- release/src/router/busybox/miscutils/crond.c | 48 +- release/src/router/busybox/miscutils/crontab.c | 20 +- release/src/router/busybox/miscutils/dc.c | 46 +- release/src/router/busybox/miscutils/devmem.c | 128 + release/src/router/busybox/miscutils/fbsplash.c | 62 +- .../src/router/busybox/miscutils/flash_eraseall.c | 194 + release/src/router/busybox/miscutils/hdparm.c | 16 +- release/src/router/busybox/miscutils/inotifyd.c | 132 +- release/src/router/busybox/miscutils/ionice.c | 99 + release/src/router/busybox/miscutils/less.c | 681 +- release/src/router/busybox/miscutils/man.c | 107 +- release/src/router/busybox/miscutils/microcom.c | 20 +- release/src/router/busybox/miscutils/mountpoint.c | 138 +- release/src/router/busybox/miscutils/raidautorun.c | 2 +- release/src/router/busybox/miscutils/runlevel.c | 2 +- release/src/router/busybox/miscutils/setsid.c | 3 +- release/src/router/busybox/miscutils/strings.c | 9 +- release/src/router/busybox/miscutils/taskset.c | 2 +- release/src/router/busybox/miscutils/time.c | 4 +- release/src/router/busybox/miscutils/timeout.c | 115 + release/src/router/busybox/miscutils/watchdog.c | 72 +- release/src/router/busybox/modutils/Config.in | 215 +- release/src/router/busybox/modutils/Kbuild | 27 +- release/src/router/busybox/modutils/depmod.c | 520 +- release/src/router/busybox/modutils/insmod.c | 4328 +--------- release/src/router/busybox/modutils/lsmod.c | 273 +- .../src/router/busybox/modutils/modprobe-small.c | 49 +- release/src/router/busybox/modutils/modprobe.c | 1350 +--- release/src/router/busybox/modutils/modutils-24.c | 3905 +++++++++ release/src/router/busybox/modutils/modutils.c | 129 + release/src/router/busybox/modutils/modutils.h | 64 + release/src/router/busybox/modutils/rmmod.c | 153 +- release/src/router/busybox/networking/Config.in | 84 +- release/src/router/busybox/networking/Kbuild | 5 +- release/src/router/busybox/networking/arp.c | 72 +- release/src/router/busybox/networking/arping.c | 28 +- release/src/router/busybox/networking/brctl.c | 20 +- release/src/router/busybox/networking/dnsd.c | 898 ++- release/src/router/busybox/networking/ether-wake.c | 4 +- release/src/router/busybox/networking/ftpd.c | 1346 ++++ release/src/router/busybox/networking/httpd.c | 191 +- release/src/router/busybox/networking/ifconfig.c | 2 +- release/src/router/busybox/networking/ifenslave.c | 18 +- release/src/router/busybox/networking/ifupdown.c | 32 +- release/src/router/busybox/networking/inetd.c | 146 +- release/src/router/busybox/networking/interface.c | 182 +- release/src/router/busybox/networking/ip.c | 4 +- release/src/router/busybox/networking/isrv.h | 8 +- .../src/router/busybox/networking/isrv_identd.c | 2 +- .../busybox/networking/libiproute/ip_common.h | 14 +- .../busybox/networking/libiproute/ipaddress.c | 11 +- .../router/busybox/networking/libiproute/iplink.c | 28 +- .../router/busybox/networking/libiproute/iproute.c | 16 +- .../router/busybox/networking/libiproute/iprule.c | 10 +- .../busybox/networking/libiproute/iptunnel.c | 91 +- .../busybox/networking/libiproute/libnetlink.c | 4 +- .../busybox/networking/libiproute/libnetlink.h | 15 +- .../router/busybox/networking/libiproute/ll_addr.c | 38 +- .../router/busybox/networking/libiproute/ll_map.c | 4 +- .../router/busybox/networking/libiproute/ll_map.h | 14 +- .../busybox/networking/libiproute/ll_proto.c | 15 +- .../busybox/networking/libiproute/rt_names.h | 15 +- .../router/busybox/networking/libiproute/rtm_map.h | 14 +- .../router/busybox/networking/libiproute/utils.c | 205 +- .../router/busybox/networking/libiproute/utils.h | 38 +- release/src/router/busybox/networking/nameif.c | 6 +- release/src/router/busybox/networking/nc.c | 3 +- release/src/router/busybox/networking/nslookup.c | 59 +- release/src/router/busybox/networking/ping.c | 67 +- release/src/router/busybox/networking/route.c | 6 +- release/src/router/busybox/networking/sendmail.c | 675 -- release/src/router/busybox/networking/slattach.c | 2 + release/src/router/busybox/networking/tc.c | 543 ++ release/src/router/busybox/networking/tcpudp.c | 11 +- .../src/router/busybox/networking/tcpudp_perhost.h | 8 +- release/src/router/busybox/networking/telnet.c | 252 +- release/src/router/busybox/networking/telnetd.c | 159 +- .../router/busybox/networking/telnetd.ctrlSQ.patch | 175 + release/src/router/busybox/networking/tftp.c | 49 +- release/src/router/busybox/networking/traceroute.c | 897 +-- release/src/router/busybox/networking/tunctl.c | 139 + .../src/router/busybox/networking/udhcp/Config.in | 6 +- release/src/router/busybox/networking/udhcp/Kbuild | 2 +- .../src/router/busybox/networking/udhcp/arpping.c | 4 +- .../router/busybox/networking/udhcp/clientpacket.c | 61 +- .../router/busybox/networking/udhcp/clientsocket.c | 2 +- .../src/router/busybox/networking/udhcp/common.h | 83 +- .../src/router/busybox/networking/udhcp/dhcpc.c | 71 +- .../src/router/busybox/networking/udhcp/dhcpc.h | 29 +- .../src/router/busybox/networking/udhcp/dhcpd.c | 54 +- .../src/router/busybox/networking/udhcp/dhcpd.h | 83 +- .../router/busybox/networking/udhcp/dhcprelay.c | 135 +- .../router/busybox/networking/udhcp/domain_codec.c | 8 +- .../router/busybox/networking/udhcp/dumpleases.c | 67 +- .../src/router/busybox/networking/udhcp/files.c | 158 +- .../src/router/busybox/networking/udhcp/leases.c | 105 +- .../src/router/busybox/networking/udhcp/options.c | 117 +- .../src/router/busybox/networking/udhcp/options.h | 237 +- .../src/router/busybox/networking/udhcp/packet.c | 27 +- .../src/router/busybox/networking/udhcp/script.c | 86 +- .../router/busybox/networking/udhcp/serverpacket.c | 91 +- .../router/busybox/networking/udhcp/signalpipe.c | 6 +- .../src/router/busybox/networking/udhcp/socket.c | 15 +- .../busybox/networking/udhcp/static_leases.c | 72 +- release/src/router/busybox/networking/vconfig.c | 13 +- release/src/router/busybox/networking/wget.c | 115 +- release/src/router/busybox/networking/zcip.c | 142 +- release/src/router/busybox/printutils/Config.in | 5 + release/src/router/busybox/printutils/lpr.c | 2 +- release/src/router/busybox/procps/Config.in | 31 +- release/src/router/busybox/procps/fuser.c | 5 +- release/src/router/busybox/procps/kill.c | 67 +- release/src/router/busybox/procps/nmeter.c | 46 +- release/src/router/busybox/procps/pidof.c | 10 +- release/src/router/busybox/procps/sysctl.c | 526 +- release/src/router/busybox/procps/top.c | 378 +- release/src/router/busybox/runit/Config.in | 17 + release/src/router/busybox/runit/runit_lib.h | 8 +- release/src/router/busybox/runit/runsv.c | 34 +- release/src/router/busybox/runit/runsvdir.c | 294 +- release/src/router/busybox/runit/sv.c | 6 +- release/src/router/busybox/runit/svlogd.c | 16 +- release/src/router/busybox/scripts/Makefile.lib | 8 +- release/src/router/busybox/scripts/checkhelp.awk | 2 +- release/src/router/busybox/scripts/defconfig | 276 +- .../src/router/busybox/scripts/kconfig/confdata.c | 2 + .../busybox/scripts/kconfig/lxdialog/Makefile | 2 +- .../scripts/kconfig/lxdialog/check-lxdialog.sh | 48 +- release/src/router/busybox/scripts/kconfig/util.c | 8 +- release/src/router/busybox/scripts/objsizes | 2 +- release/src/router/busybox/scripts/randomtest | 92 + release/src/router/busybox/scripts/randomtest.loop | 10 + release/src/router/busybox/scripts/trylink | 9 +- release/src/router/busybox/selinux/Config.in | 2 +- release/src/router/busybox/selinux/chcon.c | 2 + release/src/router/busybox/selinux/getenforce.c | 1 + release/src/router/busybox/selinux/getsebool.c | 1 + release/src/router/busybox/selinux/load_policy.c | 2 + release/src/router/busybox/selinux/matchpathcon.c | 1 + release/src/router/busybox/selinux/runcon.c | 2 + .../src/router/busybox/selinux/selinuxenabled.c | 1 + release/src/router/busybox/selinux/sestatus.c | 7 +- release/src/router/busybox/selinux/setenforce.c | 1 + release/src/router/busybox/selinux/setsebool.c | 2 + release/src/router/busybox/shell/Config.in | 81 +- release/src/router/busybox/shell/Kbuild | 3 +- release/src/router/busybox/shell/ash.c | 2179 +++--- release/src/router/busybox/shell/ash_doc.txt | 91 + .../busybox/shell/ash_test/ash-misc/last_amp.right | 2 + .../busybox/shell/ash_test/ash-misc/last_amp.tests | 8 + .../busybox/shell/ash_test/ash-read/read_ifs.right | 7 + .../busybox/shell/ash_test/ash-read/read_ifs.tests | 7 + .../busybox/shell/ash_test/ash-signals/reap1.right | 1 + .../busybox/shell/ash_test/ash-signals/reap1.tests | 14 + .../ash-standalone/noexec_gets_no_env.right | 4 + .../ash-standalone/noexec_gets_no_env.tests | 5 + .../ash-standalone/nofork_trashes_getopt.right | 1 + .../ash-standalone/nofork_trashes_getopt.tests | 6 + release/src/router/busybox/shell/hush.c | 8280 +++++++++++++------- release/src/router/busybox/shell/hush_leaktool.sh | 6 +- .../busybox/shell/hush_test/hush-arith/arith.right | 138 + .../busybox/shell/hush_test/hush-arith/arith.tests | 302 + .../busybox/shell/hush_test/hush-arith/arith1.sub | 40 + .../busybox/shell/hush_test/hush-arith/arith2.sub | 57 + .../hush-bugs/and_or_and_backgrounding.right | 4 + .../hush-bugs/and_or_and_backgrounding.tests | 31 + .../leak_var.right => hush-leak/leak_argv1.right} | 0 .../shell/hush_test/hush-leak/leak_argv1.tests | 117 + .../busybox/shell/hush_test/hush-misc/and-or.right | 18 + .../busybox/shell/hush_test/hush-misc/and-or.tests | 34 + .../shell/hush_test/hush-misc/continue2.right | 1 + .../shell/hush_test/hush-misc/continue2.tests | 3 + .../shell/hush_test/hush-misc/continue3.right | 2 + .../shell/hush_test/hush-misc/continue3.tests | 3 + .../busybox/shell/hush_test/hush-misc/exec.right | 6 + .../busybox/shell/hush_test/hush-misc/exec.tests | 30 + .../busybox/shell/hush_test/hush-misc/exit1.right | 1 + .../busybox/shell/hush_test/hush-misc/exit1.tests | 4 + .../busybox/shell/hush_test/hush-misc/export.right | 6 + .../busybox/shell/hush_test/hush-misc/export.tests | 7 + .../hush_test/hush-misc/for_with_bslashes.right | 8 + .../hush_test/hush-misc/for_with_bslashes.tests | 10 + .../busybox/shell/hush_test/hush-misc/func1.right | 6 + .../busybox/shell/hush_test/hush-misc/func1.tests | 16 + .../busybox/shell/hush_test/hush-misc/func2.right | 5 + .../busybox/shell/hush_test/hush-misc/func2.tests | 9 + .../shell/hush_test/hush-misc/heredoc1.right | 5 + .../shell/hush_test/hush-misc/heredoc1.tests | 9 + .../shell/hush_test/hush-misc/heredoc2.right | 9 + .../shell/hush_test/hush-misc/heredoc2.tests | 12 + .../shell/hush_test/hush-misc/heredoc3.right | 9 + .../shell/hush_test/hush-misc/heredoc3.tests | 12 + .../shell/hush_test/hush-misc/heredoc_huge.right | 3 + .../shell/hush_test/hush-misc/heredoc_huge.tests | 9 + .../hush_test/hush-misc/if_false_exitcode.right | 1 + .../hush_test/hush-misc/if_false_exitcode.tests | 2 + .../busybox/shell/hush_test/hush-misc/redir1.right | 12 + .../busybox/shell/hush_test/hush-misc/redir1.tests | 40 + .../busybox/shell/hush_test/hush-misc/redir2.right | 1 + .../busybox/shell/hush_test/hush-misc/redir2.tests | 2 + .../busybox/shell/hush_test/hush-misc/redir3.right | 14 + .../busybox/shell/hush_test/hush-misc/redir3.tests | 9 + .../busybox/shell/hush_test/hush-misc/redir4.right | 18 + .../busybox/shell/hush_test/hush-misc/redir4.tests | 85 + .../shell/hush_test/hush-misc/syntax_err.right | 2 + .../hush_test/hush-misc/syntax_err_negate.right | 2 +- .../busybox/shell/hush_test/hush-misc/until1.right | 3 + .../busybox/shell/hush_test/hush-misc/until1.tests | 11 + .../busybox/shell/hush_test/hush-misc/while2.right | 2 + .../busybox/shell/hush_test/hush-misc/while2.tests | 2 + .../shell/hush_test/hush-parsing/escape1.tests | 2 + .../shell/hush_test/hush-parsing/escape3.tests | 2 + .../shell/hush_test/hush-parsing/negate.tests | 32 +- .../shell/hush_test/hush-parsing/starquoted2.right | 3 + .../shell/hush_test/hush-parsing/starquoted2.tests | 5 + .../shell/hush_test/hush-psubst/tick3.tests | 2 + .../shell/hush_test/hush-psubst/tick_huge.right | 3 + .../shell/hush_test/hush-psubst/tick_huge.tests | 7 + .../busybox/shell/hush_test/hush-trap/catch.right | 4 + .../busybox/shell/hush_test/hush-trap/catch.tests | 20 + .../busybox/shell/hush_test/hush-trap/exit.right | 2 + .../busybox/shell/hush_test/hush-trap/exit.tests | 3 + .../shell/hush_test/hush-trap/save-ret.right | 2 + .../shell/hush_test/hush-trap/save-ret.tests | 4 + .../busybox/shell/hush_test/hush-trap/usage.right | 14 + .../busybox/shell/hush_test/hush-trap/usage.tests | 23 + .../hush_test/hush-vars/param_expand_alt.right | 8 + .../hush_test/hush-vars/param_expand_alt.tests | 22 + .../hush_test/hush-vars/param_expand_assign.right | 27 + .../hush_test/hush-vars/param_expand_assign.tests | 38 + .../hush_test/hush-vars/param_expand_default.right | 8 + .../hush_test/hush-vars/param_expand_default.tests | 22 + .../hush-vars/param_expand_indicate_error.right | 29 + .../hush-vars/param_expand_indicate_error.tests | 40 + .../hush_test/hush-vars/param_expand_len.right | 4 + .../hush_test/hush-vars/param_expand_len.tests | 12 + .../shell/hush_test/hush-vars/param_subshell.right | 7 + .../shell/hush_test/hush-vars/param_subshell.tests | 15 + .../busybox/shell/hush_test/hush-vars/unset.right | 19 + .../busybox/shell/hush_test/hush-vars/unset.tests | 36 + .../busybox/shell/hush_test/hush-vars/var3.right | 3 + .../busybox/shell/hush_test/hush-vars/var3.tests | 4 + .../shell/hush_test/hush-vars/var_in_pipes.right | 6 + .../shell/hush_test/hush-vars/var_in_pipes.tests | 7 + .../shell/hush_test/hush-vars/var_leaks.right | 1 + .../shell/hush_test/hush-vars/var_leaks.tests | 14 + .../shell/hush_test/hush-vars/var_posix1.right | 33 + .../shell/hush_test/hush-vars/var_posix1.tests | 43 + .../shell/hush_test/hush-vars/var_preserved.right | 4 + .../shell/hush_test/hush-vars/var_preserved.tests | 16 + .../shell/hush_test/hush-z_slow/leak_all1.right | 3 + .../shell/hush_test/hush-z_slow/leak_all1.tests | 145 + .../shell/hush_test/hush-z_slow/leak_all2.right | 3 + .../shell/hush_test/hush-z_slow/leak_all2.tests | 93 + .../hush_test/hush-z_slow/leak_heredoc1.right | 3 + .../hush_test/hush-z_slow/leak_heredoc1.tests | 34 + .../shell/hush_test/hush-z_slow/leak_var.right | 2 +- .../shell/hush_test/hush-z_slow/leak_var.tests | 56 +- .../shell/hush_test/hush-z_slow/leak_var2.right | 3 + .../shell/hush_test/hush-z_slow/leak_var2.tests | 40 + .../shell/hush_test/hush-z_slow/leak_var3.right | 3 + .../shell/hush_test/hush-z_slow/leak_var3.tests | 41 + release/src/router/busybox/shell/hush_test/run-all | 26 +- release/src/router/busybox/shell/lash_unused.c | 5 +- release/src/router/busybox/shell/match.c | 140 + release/src/router/busybox/shell/match.h | 26 + release/src/router/busybox/shell/math.c | 700 ++ release/src/router/busybox/shell/math.h | 103 + release/src/router/busybox/shell/msh.c | 15 +- .../msh_test/msh-execution/exitcode_EACCES.right | 2 +- release/src/router/busybox/shell/msh_test/run-all | 4 +- release/src/router/busybox/sysklogd/klogd.c | 83 +- release/src/router/busybox/sysklogd/logger.c | 13 +- release/src/router/busybox/sysklogd/syslogd.c | 93 +- release/src/router/busybox/testsuite/awk.tests | 24 + release/src/router/busybox/testsuite/expand.tests | 15 + .../busybox/testsuite/makedevs.device_table.txt | 8 +- release/src/router/busybox/testsuite/mdev.tests | 29 +- release/src/router/busybox/testsuite/pidof.tests | 2 +- release/src/router/busybox/testsuite/seq.tests | 7 +- release/src/router/busybox/testsuite/sum.tests | 2 +- release/src/router/busybox/testsuite/taskset.tests | 2 +- release/src/router/busybox/testsuite/tr.tests | 31 + .../src/router/busybox/testsuite/unexpand.tests | 30 + release/src/router/busybox/util-linux/Config.in | 47 +- release/src/router/busybox/util-linux/Kbuild | 3 + release/src/router/busybox/util-linux/acpid.c | 167 + release/src/router/busybox/util-linux/blkid.c | 18 + release/src/router/busybox/util-linux/dmesg.c | 2 +- release/src/router/busybox/util-linux/fbset.c | 281 +- release/src/router/busybox/util-linux/fdformat.c | 7 +- release/src/router/busybox/util-linux/fdisk.c | 2 +- release/src/router/busybox/util-linux/fdisk_aix.c | 4 +- release/src/router/busybox/util-linux/fdisk_osf.c | 2 +- release/src/router/busybox/util-linux/fdisk_sgi.c | 12 +- release/src/router/busybox/util-linux/fdisk_sun.c | 27 +- release/src/router/busybox/util-linux/fsck_minix.c | 6 +- release/src/router/busybox/util-linux/getopt.c | 9 + release/src/router/busybox/util-linux/mdev.c | 344 +- release/src/router/busybox/util-linux/mkfs_minix.c | 7 +- release/src/router/busybox/util-linux/mkfs_vfat.c | 614 ++ release/src/router/busybox/util-linux/more.c | 4 - release/src/router/busybox/util-linux/mount.c | 365 +- release/src/router/busybox/util-linux/rtcwake.c | 4 +- release/src/router/busybox/util-linux/script.c | 5 +- release/src/router/busybox/util-linux/setarch.c | 30 +- release/src/router/busybox/util-linux/umount.c | 6 +- .../src/router/busybox/util-linux/volume_id/Kbuild | 1 + .../router/busybox/util-linux/volume_id/cramfs.c | 3 +- .../src/router/busybox/util-linux/volume_id/ext.c | 3 +- .../src/router/busybox/util-linux/volume_id/fat.c | 139 +- .../busybox/util-linux/volume_id/get_devname.c | 281 +- .../src/router/busybox/util-linux/volume_id/hfs.c | 3 +- .../router/busybox/util-linux/volume_id/iso9660.c | 3 +- .../src/router/busybox/util-linux/volume_id/jfs.c | 3 +- .../busybox/util-linux/volume_id/linux_raid.c | 5 +- .../busybox/util-linux/volume_id/linux_swap.c | 3 +- .../src/router/busybox/util-linux/volume_id/luks.c | 53 +- .../src/router/busybox/util-linux/volume_id/ntfs.c | 3 +- .../router/busybox/util-linux/volume_id/ocfs2.c | 3 +- .../router/busybox/util-linux/volume_id/reiserfs.c | 3 +- .../router/busybox/util-linux/volume_id/romfs.c | 3 +- .../src/router/busybox/util-linux/volume_id/sysv.c | 3 +- .../src/router/busybox/util-linux/volume_id/udf.c | 3 +- .../src/router/busybox/util-linux/volume_id/util.c | 101 +- .../busybox/util-linux/volume_id/volume_id.c | 49 +- .../util-linux/volume_id/volume_id_internal.h | 100 +- .../src/router/busybox/util-linux/volume_id/xfs.c | 3 +- release/src/router/common.mak | 20 +- release/src/router/config/config.in | 8 - release/src/router/config_g | 1 - release/src/router/dnsmasq/CHANGELOG | 92 +- release/src/router/dnsmasq/Makefile | 6 +- .../src/router/dnsmasq/contrib/lease-access/README | 20 + .../contrib/lease-access/lease.access.patch | 578 ++ release/src/router/dnsmasq/dbus/dnsmasq.conf | 2 - release/src/router/dnsmasq/dnsmasq.conf.example | 19 +- release/src/router/dnsmasq/doc.html | 6 +- release/src/router/dnsmasq/man/dnsmasq.8 | 64 +- release/src/router/dnsmasq/man/fr/dnsmasq.8 | 149 +- release/src/router/dnsmasq/po/de.po | 282 +- release/src/router/dnsmasq/po/es.po | 284 +- release/src/router/dnsmasq/po/fi.po | 282 +- release/src/router/dnsmasq/po/fr.po | 472 +- release/src/router/dnsmasq/po/id.po | 284 +- release/src/router/dnsmasq/po/it.po | 282 +- release/src/router/dnsmasq/po/no.po | 283 +- release/src/router/dnsmasq/po/pl.po | 291 +- release/src/router/dnsmasq/po/pt_BR.po | 282 +- release/src/router/dnsmasq/po/ro.po | 283 +- release/src/router/dnsmasq/src/bpf.c | 18 +- release/src/router/dnsmasq/src/cache.c | 6 +- release/src/router/dnsmasq/src/config.h | 36 +- release/src/router/dnsmasq/src/dbus.c | 52 +- release/src/router/dnsmasq/src/dhcp.c | 22 +- release/src/router/dnsmasq/src/dnsmasq.c | 9 +- release/src/router/dnsmasq/src/dnsmasq.h | 26 +- release/src/router/dnsmasq/src/forward.c | 6 +- release/src/router/dnsmasq/src/helper.c | 8 +- release/src/router/dnsmasq/src/lease.c | 6 +- release/src/router/dnsmasq/src/log.c | 6 +- release/src/router/dnsmasq/src/netlink.c | 6 +- release/src/router/dnsmasq/src/network.c | 63 +- release/src/router/dnsmasq/src/option.c | 158 +- release/src/router/dnsmasq/src/rfc1035.c | 34 +- release/src/router/dnsmasq/src/rfc2131.c | 280 +- release/src/router/dnsmasq/src/tftp.c | 6 +- release/src/router/dnsmasq/src/util.c | 10 +- release/src/router/httpd/Makefile | 9 - release/src/router/httpd/blackhole.c | 24 +- release/src/router/httpd/bwm.c | 14 +- release/src/router/httpd/config.c | 32 +- release/src/router/httpd/ctnf.c | 32 +- release/src/router/httpd/ddns.c | 8 +- release/src/router/httpd/devlist.c | 6 +- release/src/router/httpd/dhcp.c | 4 +- release/src/router/httpd/httpd.c | 294 +- release/src/router/httpd/httpd.h | 3 +- release/src/router/httpd/log.c | 8 +- release/src/router/httpd/misc.c | 32 +- release/src/router/httpd/nvram.c | 2 +- release/src/router/httpd/parser.c | 56 +- release/src/router/httpd/tomato.c | 139 +- release/src/router/httpd/tomato.h | 7 +- release/src/router/httpd/traceping.c | 4 +- release/src/router/httpd/upgrade.c | 16 +- release/src/router/httpd/upnp.c | 43 +- release/src/router/httpd/version.c | 6 +- release/src/router/httpd/webio.c | 55 +- release/src/router/httpd/webmsg.c | 2 +- release/src/router/httpd/wl.c | 44 +- release/src/router/ipp2p/COPYING | 339 - release/src/router/ipp2p/Makefile | 29 - release/src/router/ipp2p/README | 110 - release/src/router/ipp2p/ipt_ipp2p.c | 895 --- release/src/router/ipp2p/ipt_ipp2p.h | 31 - release/src/router/ipp2p/libipt_ipp2p.c | 401 - release/src/router/iptables/Makefile | 70 +- release/src/router/iptables/Makefile.orig | 278 - .../src/router/iptables/extensions/.connlimit-test | 2 + release/src/router/iptables/extensions/.ipp2p-test | 2 + release/src/router/iptables/extensions/Makefile | 8 +- .../src/router/iptables/extensions/libip6t_ROUTE.c | 51 +- .../src/router/iptables/extensions/libipt_ROUTE.c | 53 +- .../src/router/iptables/extensions/libipt_ipp2p.c | 424 + .../router/iptables/extensions/libipt_ipp2p.man | 43 + release/src/router/iptables/iptables-multi.c | 8 +- release/src/router/iptables/iptables-multi.c.orig | 31 - release/src/router/layer7/protocols/CHANGELOG | 6 + .../src/router/layer7/protocols/extra/gtalk.pat | 11 + .../layer7/protocols/protocols/battlefield2142.pat | 2 +- .../router/layer7/protocols/protocols/dazhihui.pat | 11 + .../layer7/protocols/protocols/replaytv-ivs.pat | 2 +- .../src/router/layer7/protocols/protocols/rtp.pat | 74 +- .../layer7/protocols/protocols/runesofmagic.pat | 63 + .../layer7/protocols/protocols/tonghuashun.pat | 11 + .../router/layer7/protocols/protocols/xboxlive.pat | 2 +- release/src/router/layer7/squish.sh | 14 +- release/src/router/mdu/Makefile | 1 - release/src/router/mdu/mdu.c | 271 +- release/src/router/miniupnpd/Changelog.txt | 482 ++ release/src/router/miniupnpd/INSTALL | 115 + release/src/router/miniupnpd/LICENCE | 26 + release/src/router/miniupnpd/Makefile | 161 + release/src/router/miniupnpd/Makefile.linux | 138 + release/src/router/miniupnpd/Makefile.openwrt | 95 + release/src/router/miniupnpd/Makefile.tomato | 131 + release/src/router/miniupnpd/README | 27 + release/src/router/miniupnpd/README.openwrt | 76 + release/src/router/miniupnpd/bsd/Makefile | 14 + release/src/router/miniupnpd/bsd/getifstats.c | 129 + release/src/router/miniupnpd/bsd/testgetifstats.c | 32 + release/src/router/miniupnpd/bsdqueue.h | 531 ++ release/src/router/miniupnpd/codelength.h | 24 + release/src/router/miniupnpd/commonrdr.h | 36 + release/src/router/miniupnpd/config.h | 58 + release/src/router/miniupnpd/config.h.openwrt | 27 + release/src/router/miniupnpd/daemonize.c | 129 + release/src/router/miniupnpd/daemonize.h | 35 + release/src/router/miniupnpd/genconfig.sh | 222 + release/src/router/miniupnpd/getifaddr.c | 57 + release/src/router/miniupnpd/getifaddr.h | 19 + release/src/router/miniupnpd/getifstats.h | 25 + release/src/router/miniupnpd/ipf/Makefile | 16 + release/src/router/miniupnpd/ipf/ipfrdr.c | 518 ++ release/src/router/miniupnpd/ipf/ipfrdr.h | 55 + release/src/router/miniupnpd/ipf/testipfrdr.c | 25 + release/src/router/miniupnpd/linux/getifstats.c | 94 + .../router/miniupnpd/linux/miniupnpd.init.d.script | 40 + release/src/router/miniupnpd/minissdp.c | 513 ++ release/src/router/miniupnpd/minissdp.h | 47 + release/src/router/miniupnpd/miniupnpd.1 | 73 + release/src/router/miniupnpd/miniupnpd.c | 1343 ++++ release/src/router/miniupnpd/miniupnpd.conf | 99 + release/src/router/miniupnpd/miniupnpdctl.c | 72 + release/src/router/miniupnpd/miniupnpdpath.h | 36 + release/src/router/miniupnpd/miniupnpdtypes.h | 24 + release/src/router/miniupnpd/minixml.c | 191 + release/src/router/miniupnpd/minixml.h | 37 + release/src/router/miniupnpd/natpmp.c | 299 + release/src/router/miniupnpd/natpmp.h | 20 + release/src/router/miniupnpd/netfilter/Makefile | 12 + .../router/miniupnpd/netfilter/iptables_display.sh | 10 + .../router/miniupnpd/netfilter/iptables_flush.sh | 8 + .../router/miniupnpd/netfilter/iptables_init.sh | 20 + .../miniupnpd/netfilter/iptables_removeall.sh | 21 + release/src/router/miniupnpd/netfilter/iptcrdr.c | 698 ++ release/src/router/miniupnpd/netfilter/iptcrdr.h | 38 + .../src/router/miniupnpd/netfilter/testiptcrdr.c | 59 + release/src/router/miniupnpd/options.c | 195 + release/src/router/miniupnpd/options.h | 74 + release/src/router/miniupnpd/pf/Makefile | 16 + release/src/router/miniupnpd/pf/obsdrdr.c | 606 ++ release/src/router/miniupnpd/pf/obsdrdr.h | 63 + release/src/router/miniupnpd/pf/testobsdrdr.c | 87 + release/src/router/miniupnpd/solaris/getifstats.c | 100 + release/src/router/miniupnpd/testgetifaddr.c | 22 + release/src/router/miniupnpd/testgetifstats.c | 36 + release/src/router/miniupnpd/testupnpdescgen.c | 141 + release/src/router/miniupnpd/testupnppermissions.c | 48 + release/src/router/miniupnpd/upnpdescgen.c | 806 ++ release/src/router/miniupnpd/upnpdescgen.h | 79 + release/src/router/miniupnpd/upnpdescstrings.h | 39 + release/src/router/miniupnpd/upnpevents.c | 476 ++ release/src/router/miniupnpd/upnpevents.h | 39 + release/src/router/miniupnpd/upnpglobalvars.c | 88 + release/src/router/miniupnpd/upnpglobalvars.h | 100 + release/src/router/miniupnpd/upnphttp.c | 636 ++ release/src/router/miniupnpd/upnphttp.h | 111 + release/src/router/miniupnpd/upnppermissions.c | 188 + release/src/router/miniupnpd/upnppermissions.h | 55 + release/src/router/miniupnpd/upnpredirect.c | 479 ++ release/src/router/miniupnpd/upnpredirect.h | 92 + release/src/router/miniupnpd/upnpreplyparse.c | 127 + release/src/router/miniupnpd/upnpreplyparse.h | 62 + release/src/router/miniupnpd/upnpsoap.c | 821 ++ release/src/router/miniupnpd/upnpsoap.h | 23 + release/src/router/mssl/mssl.c | 16 +- release/src/router/mssl/mssl.h | 6 +- release/src/router/ntpc/ntpc.c | 47 +- release/src/router/nvram/defaults.c | 32 +- release/src/router/nvram/nvram.c | 218 +- release/src/router/rc/buttons.c | 30 +- release/src/router/rc/cifs.c | 26 +- release/src/router/rc/ddns.c | 60 +- release/src/router/rc/dhcp.c | 89 +- release/src/router/rc/firewall.c | 217 +- release/src/router/rc/firewall_br.c | 206 - release/src/router/rc/forward.c | 16 +- release/src/router/rc/gpio.c | 6 +- release/src/router/rc/heartbeat.c | 2 +- release/src/router/rc/init.c | 127 +- release/src/router/rc/jffs2.c | 20 +- release/src/router/rc/led.c | 10 +- release/src/router/rc/misc.c | 62 +- release/src/router/rc/mtd.c | 22 +- release/src/router/rc/network.c | 54 +- release/src/router/rc/qos.c | 96 +- release/src/router/rc/rc.c | 2 +- release/src/router/rc/rc.h | 8 +- release/src/router/rc/restrict.c | 42 +- release/src/router/rc/sched.c | 24 +- release/src/router/rc/services.c | 221 +- release/src/router/rc/telssh.c | 14 +- release/src/router/rc/wan.c | 28 +- release/src/router/rom/Makefile | 4 +- release/src/router/rstats/rstats.c | 68 +- release/src/router/shared/Makefile | 2 - release/src/router/shared/base64.c | 6 +- release/src/router/shared/files.c | 26 +- release/src/router/shared/id.c | 33 +- release/src/router/shared/led.c | 8 +- release/src/router/shared/misc.c | 65 +- release/src/router/shared/process.c | 8 +- release/src/router/shared/shared.h | 12 +- release/src/router/shared/shutils.c | 2 +- release/src/router/shared/strings.c | 12 +- release/src/router/shared/tomato_config.h | 1 - release/src/router/shared/tomato_version | 2 +- release/src/router/upnp/Makefile | 54 - release/src/router/upnp/igd/cablelink.c | 176 - release/src/router/upnp/igd/etherlink.c | 56 - release/src/router/upnp/igd/igd.c | 177 - release/src/router/upnp/igd/igd.h | 87 - release/src/router/upnp/igd/igd_desc.c | 116 - release/src/router/upnp/igd/ipt.c | 491 -- release/src/router/upnp/igd/lanhostconfig.c | 60 - release/src/router/upnp/igd/lanhostconfig.h | 30 - release/src/router/upnp/igd/layer3.c | 200 - release/src/router/upnp/igd/linux/Makefile | 131 - release/src/router/upnp/igd/linux/linux_igd.c | 409 - release/src/router/upnp/igd/linux/linux_main.c | 146 - release/src/router/upnp/igd/linux/linux_net.c | 120 - release/src/router/upnp/igd/mapmgr.1.c | 621 -- release/src/router/upnp/igd/mapmgr.c | 623 -- release/src/router/upnp/igd/mapmgr.h | 31 - release/src/router/upnp/igd/portmap.c | 570 -- release/src/router/upnp/igd/wancommon.c | 235 - release/src/router/upnp/igd/wanipc.c | 606 -- release/src/router/upnp/igd/wanipc.h | 64 - release/src/router/upnp/igd/wanpotslinkconfig.c | 155 - release/src/router/upnp/igd/wanppp.c | 137 - release/src/router/upnp/igd/wanppp.h | 42 - .../router/upnp/igd/x_lanhostconfigmanagement.c | 271 - .../src/router/upnp/igd/x_wanethernetlinkconfig.c | 80 - release/src/router/upnp/igd/x_wanpppconnection.c | 299 - release/src/router/upnp/include/linux_osl.h | 38 - release/src/router/upnp/include/uio.h | 27 - release/src/router/upnp/include/upnp.h | 375 - release/src/router/upnp/include/upnp_dbg.h | 89 - release/src/router/upnp/include/upnp_osl.h | 44 - release/src/router/upnp/lib/device.c | 290 - release/src/router/upnp/lib/gena.c | 811 -- release/src/router/upnp/lib/http.c | 662 -- release/src/router/upnp/lib/linux/Makefile | 73 - release/src/router/upnp/lib/linux/linux_osl.c | 111 - release/src/router/upnp/lib/service.c | 244 - release/src/router/upnp/lib/soap.c | 530 -- release/src/router/upnp/lib/ssdp.c | 536 -- release/src/router/upnp/lib/uio.c | 241 - release/src/router/upnp/lib/upnp.c | 440 -- release/src/router/www/Makefile | 8 +- release/src/router/www/about.asp | 18 +- release/src/router/www/admin-access.asp | 93 +- release/src/router/www/admin-buttons.asp | 37 +- release/src/router/www/admin-bwm.asp | 6 +- release/src/router/www/admin-cifs.asp | 8 +- release/src/router/www/admin-config.asp | 10 +- release/src/router/www/admin-debug.asp | 10 +- release/src/router/www/admin-jffs2.asp | 6 +- release/src/router/www/admin-log.asp | 30 +- release/src/router/www/admin-sched.asp | 46 +- release/src/router/www/admin-scripts.asp | 4 +- release/src/router/www/admin-upgrade.asp | 2 +- release/src/router/www/advanced-ctnf.asp | 6 +- release/src/router/www/advanced-dhcpdns.asp | 8 +- release/src/router/www/advanced-firewall.asp | 11 +- release/src/router/www/advanced-mac.asp | 2 +- release/src/router/www/advanced-misc.asp | 2 +- release/src/router/www/advanced-routing.asp | 2 +- release/src/router/www/advanced-wireless.asp | 8 +- release/src/router/www/basic-ddns.asp | 66 +- release/src/router/www/basic-ident.asp | 2 +- release/src/router/www/basic-network.asp | 32 +- release/src/router/www/basic-static.asp | 4 +- release/src/router/www/basic-time.asp | 2 +- release/src/router/www/basic-wfilter.asp | 14 +- release/src/router/www/bwm-24.asp | 22 +- release/src/router/www/bwm-common.js | 32 +- release/src/router/www/bwm-daily.asp | 16 +- release/src/router/www/bwm-graph.svg | 2 +- release/src/router/www/bwm-monthly.asp | 10 +- release/src/router/www/bwm-realtime.asp | 14 +- release/src/router/www/bwm-weekly.asp | 16 +- release/src/router/www/clearcookies.asp | 2 +- release/src/router/www/forward-basic.asp | 8 +- release/src/router/www/forward-dmz.asp | 23 +- release/src/router/www/forward-triggered.asp | 4 +- release/src/router/www/forward-upnp.asp | 67 +- release/src/router/www/logout.asp | 28 +- release/src/router/www/mnoise.asp | 2 +- release/src/router/www/qos-classify.asp | 16 +- release/src/router/www/qos-detailed.asp | 22 +- release/src/router/www/qos-graphs.asp | 16 +- release/src/router/www/qos-settings.asp | 6 +- release/src/router/www/reboot-default.asp | 2 +- release/src/router/www/restrict-edit.asp | 20 +- release/src/router/www/restrict.asp | 2 +- release/src/router/www/saved-moved.asp | 2 +- release/src/router/www/saved.asp | 2 +- release/src/router/www/shutdown.asp | 2 +- release/src/router/www/status-data.jsx | 6 +- release/src/router/www/status-devices.asp | 29 +- release/src/router/www/status-log.asp | 2 +- release/src/router/www/status-overview.asp | 2 +- release/src/router/www/tomato.css | 2 +- release/src/router/www/tomato.js | 163 +- release/src/router/www/tools-ping.asp | 2 +- release/src/router/www/tools-survey.asp | 8 +- release/src/router/www/tools-trace.asp | 2 +- release/src/router/www/tools-wol.asp | 10 +- 894 files changed, 56239 insertions(+), 39452 deletions(-) create mode 100644 release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c create mode 100644 release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h create mode 100644 release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h create mode 100644 release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h create mode 100644 release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c create mode 100644 release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c create mode 100644 release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c create mode 100644 release/src/router/busybox/.config delete mode 100644 release/src/router/busybox/config_g rewrite release/src/router/busybox/coreutils/id.c (76%) create mode 100644 release/src/router/busybox/coreutils/id_test.sh create mode 100644 release/src/router/busybox/docs/Serial-Programming-HOWTO.txt rewrite release/src/router/busybox/docs/busybox.net/news.html (93%) rewrite release/src/router/busybox/docs/busybox.net/products.html (72%) create mode 100644 release/src/router/busybox/docs/busybox.net/svnindex.css create mode 100644 release/src/router/busybox/docs/busybox.net/svnindex.xsl create mode 100644 release/src/router/busybox/docs/logging_and_backgrounding.txt create mode 100644 release/src/router/busybox/examples/depmod-t.pl rewrite release/src/router/busybox/libbb/bb_pwd.c (73%) delete mode 100644 release/src/router/busybox/libbb/crypt_make_salt.c rewrite release/src/router/busybox/libbb/md5.c (64%) create mode 100644 release/src/router/busybox/libbb/md5prime.c rewrite release/src/router/busybox/libbb/pw_encrypt_md5.c (79%) create mode 100644 release/src/router/busybox/libbb/pw_encrypt_sha.c create mode 100644 release/src/router/busybox/libbb/read_key.c rewrite release/src/router/busybox/libbb/sha1.c (79%) rewrite release/src/router/busybox/loginutils/cryptpw.c (76%) rewrite release/src/router/busybox/loginutils/deluser.c (85%) create mode 100644 release/src/router/busybox/mailutils/Config.in create mode 100644 release/src/router/busybox/mailutils/Kbuild create mode 100644 release/src/router/busybox/mailutils/mail.c create mode 100644 release/src/router/busybox/mailutils/mail.h create mode 100644 release/src/router/busybox/mailutils/mime.c create mode 100644 release/src/router/busybox/mailutils/popmaildir.c create mode 100644 release/src/router/busybox/mailutils/sendmail.c create mode 100644 release/src/router/busybox/miscutils/devmem.c create mode 100644 release/src/router/busybox/miscutils/flash_eraseall.c create mode 100644 release/src/router/busybox/miscutils/ionice.c rewrite release/src/router/busybox/miscutils/mountpoint.c (71%) create mode 100644 release/src/router/busybox/miscutils/timeout.c rewrite release/src/router/busybox/modutils/Kbuild (61%) rewrite release/src/router/busybox/modutils/depmod.c (87%) rewrite release/src/router/busybox/modutils/insmod.c (99%) rewrite release/src/router/busybox/modutils/lsmod.c (83%) rewrite release/src/router/busybox/modutils/modprobe.c (96%) create mode 100644 release/src/router/busybox/modutils/modutils-24.c create mode 100644 release/src/router/busybox/modutils/modutils.c create mode 100644 release/src/router/busybox/modutils/modutils.h rewrite release/src/router/busybox/modutils/rmmod.c (76%) rewrite release/src/router/busybox/networking/dnsd.c (64%) create mode 100644 release/src/router/busybox/networking/ftpd.c delete mode 100644 release/src/router/busybox/networking/sendmail.c create mode 100644 release/src/router/busybox/networking/tc.c create mode 100644 release/src/router/busybox/networking/telnetd.ctrlSQ.patch create mode 100644 release/src/router/busybox/networking/tunctl.c rewrite release/src/router/busybox/networking/udhcp/options.h (69%) rewrite release/src/router/busybox/procps/sysctl.c (79%) create mode 100644 release/src/router/busybox/scripts/randomtest create mode 100644 release/src/router/busybox/scripts/randomtest.loop create mode 100644 release/src/router/busybox/shell/ash_test/ash-misc/last_amp.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-misc/last_amp.tests create mode 100644 release/src/router/busybox/shell/ash_test/ash-read/read_ifs.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-read/read_ifs.tests create mode 100644 release/src/router/busybox/shell/ash_test/ash-signals/reap1.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-signals/reap1.tests create mode 100644 release/src/router/busybox/shell/ash_test/ash-standalone/noexec_gets_no_env.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-standalone/noexec_gets_no_env.tests create mode 100644 release/src/router/busybox/shell/ash_test/ash-standalone/nofork_trashes_getopt.right create mode 100644 release/src/router/busybox/shell/ash_test/ash-standalone/nofork_trashes_getopt.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-arith/arith.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-arith/arith.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-arith/arith1.sub create mode 100644 release/src/router/busybox/shell/hush_test/hush-arith/arith2.sub create mode 100644 release/src/router/busybox/shell/hush_test/hush-bugs/and_or_and_backgrounding.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-bugs/and_or_and_backgrounding.tests copy release/src/router/busybox/shell/hush_test/{hush-z_slow/leak_var.right => hush-leak/leak_argv1.right} (100%) create mode 100644 release/src/router/busybox/shell/hush_test/hush-leak/leak_argv1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/and-or.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/and-or.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/continue2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/continue2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/continue3.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/continue3.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/exec.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/exec.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/exit1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/exit1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/export.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/export.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/for_with_bslashes.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/for_with_bslashes.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/func1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/func1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/func2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/func2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc3.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc3.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc_huge.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/heredoc_huge.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/if_false_exitcode.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/if_false_exitcode.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir3.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir3.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir4.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/redir4.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/until1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/until1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/while2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-misc/while2.tests rewrite release/src/router/busybox/shell/hush_test/hush-parsing/negate.tests (67%) create mode 100644 release/src/router/busybox/shell/hush_test/hush-psubst/tick_huge.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-psubst/tick_huge.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/catch.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/catch.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/exit.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/exit.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/save-ret.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/save-ret.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/usage.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-trap/usage.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_alt.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_alt.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_assign.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_assign.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_default.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_default.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_indicate_error.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_indicate_error.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_len.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_expand_len.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_subshell.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/param_subshell.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/unset.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/unset.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var3.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var3.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_in_pipes.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_in_pipes.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_leaks.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_leaks.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_posix1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_posix1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_preserved.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-vars/var_preserved.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_all1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_all1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_all2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_all2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_heredoc1.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_heredoc1.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_var2.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_var2.tests create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_var3.right create mode 100644 release/src/router/busybox/shell/hush_test/hush-z_slow/leak_var3.tests create mode 100644 release/src/router/busybox/shell/match.c create mode 100644 release/src/router/busybox/shell/match.h create mode 100644 release/src/router/busybox/shell/math.c create mode 100644 release/src/router/busybox/shell/math.h create mode 100644 release/src/router/busybox/testsuite/expand.tests create mode 100644 release/src/router/busybox/testsuite/tr.tests create mode 100644 release/src/router/busybox/testsuite/unexpand.tests create mode 100644 release/src/router/busybox/util-linux/acpid.c create mode 100644 release/src/router/busybox/util-linux/blkid.c create mode 100644 release/src/router/busybox/util-linux/mkfs_vfat.c create mode 100644 release/src/router/dnsmasq/contrib/lease-access/README create mode 100644 release/src/router/dnsmasq/contrib/lease-access/lease.access.patch delete mode 100644 release/src/router/ipp2p/COPYING delete mode 100644 release/src/router/ipp2p/Makefile delete mode 100644 release/src/router/ipp2p/README delete mode 100644 release/src/router/ipp2p/ipt_ipp2p.c delete mode 100644 release/src/router/ipp2p/ipt_ipp2p.h delete mode 100644 release/src/router/ipp2p/libipt_ipp2p.c delete mode 100644 release/src/router/iptables/Makefile.orig create mode 100644 release/src/router/iptables/extensions/.connlimit-test create mode 100644 release/src/router/iptables/extensions/.ipp2p-test create mode 100644 release/src/router/iptables/extensions/libipt_ipp2p.c create mode 100644 release/src/router/iptables/extensions/libipt_ipp2p.man delete mode 100644 release/src/router/iptables/iptables-multi.c.orig create mode 100644 release/src/router/layer7/protocols/extra/gtalk.pat create mode 100644 release/src/router/layer7/protocols/protocols/dazhihui.pat rewrite release/src/router/layer7/protocols/protocols/rtp.pat (61%) create mode 100644 release/src/router/layer7/protocols/protocols/runesofmagic.pat create mode 100644 release/src/router/layer7/protocols/protocols/tonghuashun.pat create mode 100644 release/src/router/miniupnpd/Changelog.txt create mode 100644 release/src/router/miniupnpd/INSTALL create mode 100644 release/src/router/miniupnpd/LICENCE create mode 100644 release/src/router/miniupnpd/Makefile create mode 100644 release/src/router/miniupnpd/Makefile.linux create mode 100644 release/src/router/miniupnpd/Makefile.openwrt create mode 100644 release/src/router/miniupnpd/Makefile.tomato create mode 100644 release/src/router/miniupnpd/README create mode 100644 release/src/router/miniupnpd/README.openwrt create mode 100644 release/src/router/miniupnpd/bsd/Makefile create mode 100644 release/src/router/miniupnpd/bsd/getifstats.c create mode 100644 release/src/router/miniupnpd/bsd/testgetifstats.c create mode 100644 release/src/router/miniupnpd/bsdqueue.h create mode 100644 release/src/router/miniupnpd/codelength.h create mode 100644 release/src/router/miniupnpd/commonrdr.h create mode 100644 release/src/router/miniupnpd/config.h create mode 100644 release/src/router/miniupnpd/config.h.openwrt create mode 100644 release/src/router/miniupnpd/daemonize.c create mode 100644 release/src/router/miniupnpd/daemonize.h create mode 100644 release/src/router/miniupnpd/genconfig.sh create mode 100644 release/src/router/miniupnpd/getifaddr.c create mode 100644 release/src/router/miniupnpd/getifaddr.h create mode 100644 release/src/router/miniupnpd/getifstats.h create mode 100644 release/src/router/miniupnpd/ipf/Makefile create mode 100644 release/src/router/miniupnpd/ipf/ipfrdr.c create mode 100644 release/src/router/miniupnpd/ipf/ipfrdr.h create mode 100644 release/src/router/miniupnpd/ipf/testipfrdr.c create mode 100644 release/src/router/miniupnpd/linux/getifstats.c create mode 100644 release/src/router/miniupnpd/linux/miniupnpd.init.d.script create mode 100644 release/src/router/miniupnpd/minissdp.c create mode 100644 release/src/router/miniupnpd/minissdp.h create mode 100644 release/src/router/miniupnpd/miniupnpd.1 create mode 100644 release/src/router/miniupnpd/miniupnpd.c create mode 100644 release/src/router/miniupnpd/miniupnpd.conf create mode 100644 release/src/router/miniupnpd/miniupnpdctl.c create mode 100644 release/src/router/miniupnpd/miniupnpdpath.h create mode 100644 release/src/router/miniupnpd/miniupnpdtypes.h create mode 100644 release/src/router/miniupnpd/minixml.c create mode 100644 release/src/router/miniupnpd/minixml.h create mode 100644 release/src/router/miniupnpd/natpmp.c create mode 100644 release/src/router/miniupnpd/natpmp.h create mode 100644 release/src/router/miniupnpd/netfilter/Makefile create mode 100644 release/src/router/miniupnpd/netfilter/iptables_display.sh create mode 100644 release/src/router/miniupnpd/netfilter/iptables_flush.sh create mode 100644 release/src/router/miniupnpd/netfilter/iptables_init.sh create mode 100644 release/src/router/miniupnpd/netfilter/iptables_removeall.sh create mode 100644 release/src/router/miniupnpd/netfilter/iptcrdr.c create mode 100644 release/src/router/miniupnpd/netfilter/iptcrdr.h create mode 100644 release/src/router/miniupnpd/netfilter/testiptcrdr.c create mode 100644 release/src/router/miniupnpd/options.c create mode 100644 release/src/router/miniupnpd/options.h create mode 100644 release/src/router/miniupnpd/pf/Makefile create mode 100644 release/src/router/miniupnpd/pf/obsdrdr.c create mode 100644 release/src/router/miniupnpd/pf/obsdrdr.h create mode 100644 release/src/router/miniupnpd/pf/testobsdrdr.c create mode 100644 release/src/router/miniupnpd/solaris/getifstats.c create mode 100644 release/src/router/miniupnpd/testgetifaddr.c create mode 100644 release/src/router/miniupnpd/testgetifstats.c create mode 100644 release/src/router/miniupnpd/testupnpdescgen.c create mode 100644 release/src/router/miniupnpd/testupnppermissions.c create mode 100644 release/src/router/miniupnpd/upnpdescgen.c create mode 100644 release/src/router/miniupnpd/upnpdescgen.h create mode 100644 release/src/router/miniupnpd/upnpdescstrings.h create mode 100644 release/src/router/miniupnpd/upnpevents.c create mode 100644 release/src/router/miniupnpd/upnpevents.h create mode 100644 release/src/router/miniupnpd/upnpglobalvars.c create mode 100644 release/src/router/miniupnpd/upnpglobalvars.h create mode 100644 release/src/router/miniupnpd/upnphttp.c create mode 100644 release/src/router/miniupnpd/upnphttp.h create mode 100644 release/src/router/miniupnpd/upnppermissions.c create mode 100644 release/src/router/miniupnpd/upnppermissions.h create mode 100644 release/src/router/miniupnpd/upnpredirect.c create mode 100644 release/src/router/miniupnpd/upnpredirect.h create mode 100644 release/src/router/miniupnpd/upnpreplyparse.c create mode 100644 release/src/router/miniupnpd/upnpreplyparse.h create mode 100644 release/src/router/miniupnpd/upnpsoap.c create mode 100644 release/src/router/miniupnpd/upnpsoap.h delete mode 100644 release/src/router/rc/firewall_br.c delete mode 100644 release/src/router/upnp/Makefile delete mode 100644 release/src/router/upnp/igd/cablelink.c delete mode 100644 release/src/router/upnp/igd/etherlink.c delete mode 100644 release/src/router/upnp/igd/igd.c delete mode 100644 release/src/router/upnp/igd/igd.h delete mode 100644 release/src/router/upnp/igd/igd_desc.c delete mode 100644 release/src/router/upnp/igd/ipt.c delete mode 100644 release/src/router/upnp/igd/lanhostconfig.c delete mode 100644 release/src/router/upnp/igd/lanhostconfig.h delete mode 100644 release/src/router/upnp/igd/layer3.c delete mode 100644 release/src/router/upnp/igd/linux/Makefile delete mode 100644 release/src/router/upnp/igd/linux/linux_igd.c delete mode 100644 release/src/router/upnp/igd/linux/linux_main.c delete mode 100644 release/src/router/upnp/igd/linux/linux_net.c delete mode 100644 release/src/router/upnp/igd/mapmgr.1.c delete mode 100644 release/src/router/upnp/igd/mapmgr.c delete mode 100644 release/src/router/upnp/igd/mapmgr.h delete mode 100644 release/src/router/upnp/igd/portmap.c delete mode 100644 release/src/router/upnp/igd/wancommon.c delete mode 100644 release/src/router/upnp/igd/wanipc.c delete mode 100644 release/src/router/upnp/igd/wanipc.h delete mode 100644 release/src/router/upnp/igd/wanpotslinkconfig.c delete mode 100644 release/src/router/upnp/igd/wanppp.c delete mode 100644 release/src/router/upnp/igd/wanppp.h delete mode 100644 release/src/router/upnp/igd/x_lanhostconfigmanagement.c delete mode 100644 release/src/router/upnp/igd/x_wanethernetlinkconfig.c delete mode 100644 release/src/router/upnp/igd/x_wanpppconnection.c delete mode 100644 release/src/router/upnp/include/linux_osl.h delete mode 100644 release/src/router/upnp/include/uio.h delete mode 100644 release/src/router/upnp/include/upnp.h delete mode 100644 release/src/router/upnp/include/upnp_dbg.h delete mode 100644 release/src/router/upnp/include/upnp_osl.h delete mode 100644 release/src/router/upnp/lib/device.c delete mode 100644 release/src/router/upnp/lib/gena.c delete mode 100644 release/src/router/upnp/lib/http.c delete mode 100644 release/src/router/upnp/lib/linux/Makefile delete mode 100644 release/src/router/upnp/lib/linux/linux_osl.c delete mode 100644 release/src/router/upnp/lib/service.c delete mode 100644 release/src/router/upnp/lib/soap.c delete mode 100644 release/src/router/upnp/lib/ssdp.c delete mode 100644 release/src/router/upnp/lib/uio.c delete mode 100644 release/src/router/upnp/lib/upnp.c diff --git a/release/src/Makefile b/release/src/Makefile index 6175b61bb9..2629d6f6ce 100644 --- a/release/src/Makefile +++ b/release/src/Makefile @@ -28,9 +28,12 @@ all: else all: - @echo -e "\n\n$(TOMATO_PROFILE_NAME) Profile" + @echo "" + @echo "" + @echo "$(TOMATO_PROFILE_NAME) Profile" @btools/uversion.pl --gen - @echo -e "\n\n" + @echo "" + @echo "" @$(MAKE) -C router all @$(MAKE) -C router install @@ -50,11 +53,13 @@ ifeq ($(wildcard include/bcm20xx.h),) else @btools/fpkg -i linux/linux/arch/mips/brcm-boards/bcm947xx/compressed/vmlinuz -i router/mipsel-uclibc/target.image \ -t image/tomato-ND.trx -# -l WR41,image/WRH54G.bin endif - - @echo -e "\n-----------------\n" `cat router/shared/tomato_version` " ready\n-----------------" + + @echo "" + @echo "-----------------" + @echo `cat router/shared/tomato_version` " ready" + @echo "-----------------" ifneq ($(NOVERSION),1) @cp router/shared/tomato_version router/shared/tomato_version_last @@ -83,8 +88,6 @@ distclean: clean cleankernel cleantools cleanlibc ifneq ($(INSIDE_MAK),1) @$(MAKE) -C router $@ INSIDE_MAK=1 endif - @$(MAKE) -C router/busybox distclean - @rm -f router/busybox/config_current @rm -f router/config_current @rm -f router/.config.cmd router/.config.old @rm -f router/libfoo_xref.txt @@ -94,7 +97,8 @@ prepk: $(MAKE) -C linux/linux oldconfig dep what: - @echo -e "\n$(TOMATO_PROFILE_NAME) Profile\n" + @echo "" + @echo "$(TOMATO_PROFILE_NAME) Profile\n" endif @@ -103,7 +107,7 @@ g: @$(MAKE) setprofile U=G L=g N=G setprofile: - @echo -e "\ + @echo "\ #ifndef TOMATO_PROFILE\n\ #define TOMATO_$(U) 1\n\ #define PROFILE_G 1\n\ @@ -112,7 +116,7 @@ setprofile: #define TOMATO_PROFILE_NAME \"$(N)\"\n\ #endif\n" > router/shared/tomato_profile.h - @echo -e "\ + @echo "\ TOMATO_$(U) = 1\n\ PROFILE_G = 1\n\ PROFILE_N = 2\n\ @@ -128,14 +132,9 @@ TOMATO_PROFILE_U = $(U)\n" > tomato_profile.mak cp config_$(L) .config @$(MAKE) -C router oldconfig - @cd router/busybox && \ - [ -s .config ] && cat .config > config_current; \ - rm -f config_current && \ - ln -s config_$(L) config_current && \ - cp config_$(L) .config - @$(MAKE) -C router/busybox oldconfig - - @echo -e "\nUsing $(N) profile.\n" + @echo "" + @echo "Using $(N) profile." + @echo "" cleanlibc: @@ -144,7 +143,10 @@ cleanlibc: libc: cleanlibc @$(MAKE) -C ../../tools-src/uClibc @$(MAKE) -C ../../tools-src/uClibc install - + +echotest: + @( echo -e foo | grep "\-e foo" ) && echo bar || echo foo + help: @echo "g use G profile" @echo "clean -C router clean" diff --git a/release/src/linux/linux/.config b/release/src/linux/linux/.config index 87abcd7244..b1f69ac915 100644 --- a/release/src/linux/linux/.config +++ b/release/src/linux/linux/.config @@ -311,7 +311,8 @@ CONFIG_IP_NF_PPTP=m # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=y -CONFIG_IP_NF_MATCH_GEOIP=m +CONFIG_IP_NF_MATCH_IPP2P=m +# CONFIG_IP_NF_MATCH_GEOIP is not set # CONFIG_IP_NF_MATCH_QUOTA is not set CONFIG_IP_NF_MATCH_IPRANGE=y # CONFIG_IP_NF_POOL is not set @@ -326,7 +327,7 @@ CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_CONDITION=m CONFIG_IP_NF_MATCH_TIME=m # CONFIG_IP_NF_MATCH_ECN is not set -# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_DSCP=m # CONFIG_IP_NF_MATCH_AH_ESP is not set CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_U32=m @@ -371,6 +372,7 @@ CONFIG_IP_NF_TARGET_TOS=m # CONFIG_IP_NF_TARGET_ECN is not set CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_ROUTE=m CONFIG_IP_NF_TARGET_CLASSIFY=m CONFIG_IP_NF_TARGET_IMQ=m CONFIG_IP_NF_TARGET_LOG=y diff --git a/release/src/linux/linux/Documentation/Configure.help b/release/src/linux/linux/Documentation/Configure.help index 757e7afe4a..1f6261d7c8 100644 --- a/release/src/linux/linux/Documentation/Configure.help +++ b/release/src/linux/linux/Documentation/Configure.help @@ -2834,6 +2834,14 @@ CONFIG_IP_NF_MATCH_TOS If you want to compile it as a module, say M here and read . If unsure, say `N'. +IPP2P match support +CONFIG_IP_NF_MATCH_IPP2P + This option makes possible to match some P2P packets + therefore helps controlling such traffic. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + geoip match support CONFIG_IP_NF_MATCH_GEOIP This option allows you to match a packet by its source or @@ -3075,6 +3083,21 @@ CONFIG_IP_NF_TARGET_MARK If you want to compile it as a module, say M here and read . If unsure, say `N'. +ROUTE target support +CONFIG_IP_NF_TARGET_ROUTE + This option adds a `ROUTE' target, which enables you to setup unusual + routes. For example, the ROUTE lets you route a received packet through + an interface or towards a host, even if the regular destination of the + packet is the router itself. The ROUTE target is also able to change the + incoming interface of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called ipt_ROUTE.o. + If unsure, say `N'. + TCPMSS target support CONFIG_IP_NF_TARGET_TCPMSS This option adds a `TCPMSS' target, which allows you to alter the @@ -3286,6 +3309,17 @@ CONFIG_IP6_NF_TARGET_MARK If you want to compile it as a module, say M here and read . If unsure, say `N'. +ROUTE target support +CONFIG_IP6_NF_TARGET_ROUTE + This option adds a `ROUTE' target, which enables you to setup unusual + routes. The ROUTE target is also able to change the incoming interface + of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + Not working as a module. + TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify diff --git a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c new file mode 100644 index 0000000000..706dfbf1b3 --- /dev/null +++ b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c @@ -0,0 +1,41 @@ +/* + * Early initialization code for BCM94710 boards + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + +void __init +prom_init(int argc, const char **argv) +{ + unsigned long mem; + + mips_machgroup = MACH_GROUP_BRCM; + mips_machtype = MACH_BCM947XX; + + /* Figure out memory size by finding aliases */ + for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { + if (*(unsigned long *)((unsigned long)(prom_init) + mem) == + *(unsigned long *)(prom_init)) + break; + } + add_memory_region(0, mem, BOOT_MEM_RAM); +} + +void __init +prom_free_prom_memory(void) +{ +} diff --git a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c index 242dafb926..cb35926d19 100644 --- a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c +++ b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c @@ -1,7 +1,7 @@ /* * Early initialization code for BCM94710 boards * - * Copyright 2005, Broadcom Corporation + * Copyright 2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY @@ -9,7 +9,7 @@ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * - * $Id: prom.c,v 1.1.1.7 2005/03/07 07:30:37 kanki Exp $ + * $Id$ */ #include @@ -18,24 +18,39 @@ #include #include -void __init -prom_init(int argc, const char **argv) +void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { - unsigned long mem; + unsigned long mem, before, offset; - mips_machgroup = MACH_GROUP_BRCM; - mips_machtype = MACH_BCM947XX; + mips_machgroup = MACH_GROUP_BRCM; + mips_machtype = MACH_BCM947XX; - /* Figure out memory size by finding aliases */ - for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { - if (*(unsigned long *)((unsigned long)(prom_init) + mem) == - *(unsigned long *)(prom_init)) + /* Figure out memory size by finding aliases. + * + * We assume that there will be no more than 128 MB of memory, + * and that the memory size will be a multiple of 1 MB. + * + * We set 'before' to be the amount of memory (in MB) before this + * function, i.e. one MB less than the number of MB of memory that we + * *know* we have. And we set 'offset' to be the address of 'prominit' + * minus 'before', so that KSEG0 or KSEG1 base + offset < 1 MB. + * This prevents us from overrunning 128 MB and causing a bus error. + */ + before = ((unsigned long) &prom_init) & (127 << 20); + offset = ((unsigned long) &prom_init) - before; + for (mem = before + (1 << 20); mem < (128 << 20); mem += (1 << 20)) + if (*(unsigned long *)(offset + mem) == + *(unsigned long *)(prom_init)) { + /* + * We may already be well past the end of memory at + * this point, so we'll have to compensate for it. + */ + mem -= before; break; - } + } add_memory_region(0, mem, BOOT_MEM_RAM); } -void __init -prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { } diff --git a/release/src/linux/linux/arch/mips/kernel/branch.c b/release/src/linux/linux/arch/mips/kernel/branch.c index 8165789cbe..738ae74f12 100644 --- a/release/src/linux/linux/arch/mips/kernel/branch.c +++ b/release/src/linux/linux/arch/mips/kernel/branch.c @@ -170,7 +170,7 @@ int __compute_return_epc(struct pt_regs *regs) bit = (insn.i_format.rt >> 2); bit += (bit != 0); bit += 23; - switch (insn.i_format.rt) { + switch (insn.i_format.rt & 3) { case 0: /* bc1f */ case 2: /* bc1fl */ if (~fcr31 & (1 << bit)) diff --git a/release/src/linux/linux/arch/mips/math-emu/cp1emu.c b/release/src/linux/linux/arch/mips/math-emu/cp1emu.c index be1f732aa0..07f25d7437 100644 --- a/release/src/linux/linux/arch/mips/math-emu/cp1emu.c +++ b/release/src/linux/linux/arch/mips/math-emu/cp1emu.c @@ -528,9 +528,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) if (MIPSInst_FUNC(ir) != movc_op) return SIGILL; cond = fpucondbit[MIPSInst_RT(ir) >> 2]; - if (((ctx->sr & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0)) - return 0; - xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + if (((ctx->sr & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) + xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; break; #endif diff --git a/release/src/linux/linux/drivers/mtd/chips/gen_probe.c b/release/src/linux/linux/drivers/mtd/chips/gen_probe.c index 4bed4f12a1..45ea742b0a 100644 --- a/release/src/linux/linux/drivers/mtd/chips/gen_probe.c +++ b/release/src/linux/linux/drivers/mtd/chips/gen_probe.c @@ -287,6 +287,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) #endif #ifdef CONFIG_MTD_CFI_AMDSTD case 0x0002: + case 0x0006: /* for Winbond W19L320SBT9C */ return cfi_cmdset_0002(map, primary); #endif #ifdef CONFIG_MTD_CFI_SSTSTD diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h new file mode 100644 index 0000000000..41b1a9c867 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h @@ -0,0 +1,23 @@ +/* Header file for iptables ipt_ROUTE target + * + * (C) 2002 by Cédric de Launois + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IPT_ROUTE_IFNAMSIZ 16 + +struct ipt_route_target_info { + char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw; /* IP address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IPT_ROUTE_CONTINUE 0x01 +#define IPT_ROUTE_TEE 0x02 + +#endif /*_IPT_ROUTE_H_target*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h new file mode 100644 index 0000000000..1bd3f649e6 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h @@ -0,0 +1,31 @@ +#ifndef __IPT_IPP2P_H +#define __IPT_IPP2P_H +#define IPP2P_VERSION "0.8.1_rc1" + +struct ipt_p2p_info { + int cmd; + int debug; +}; + +#endif //__IPT_IPP2P_H + +#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/ +//#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/ +#define SHORT_HAND_NONE 5 /* no short hand*/ + +#define IPP2P_EDK (1 << 1) +#define IPP2P_DATA_KAZAA (1 << 2) +#define IPP2P_DATA_EDK (1 << 3) +#define IPP2P_DATA_DC (1 << 4) +#define IPP2P_DC (1 << 5) +#define IPP2P_DATA_GNU (1 << 6) +#define IPP2P_GNU (1 << 7) +#define IPP2P_KAZAA (1 << 8) +#define IPP2P_BIT (1 << 9) +#define IPP2P_APPLE (1 << 10) +#define IPP2P_SOUL (1 << 11) +#define IPP2P_WINMX (1 << 12) +#define IPP2P_ARES (1 << 13) +#define IPP2P_MUTE (1 << 14) +#define IPP2P_WASTE (1 << 15) +#define IPP2P_XDCC (1 << 16) diff --git a/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h new file mode 100644 index 0000000000..c5ec871b50 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h @@ -0,0 +1,23 @@ +/* Header file for iptables ip6t_ROUTE target + * + * (C) 2003 by Cédric de Launois + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IP6T_ROUTE_IFNAMSIZ 16 + +struct ip6t_route_target_info { + char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw[4]; /* IPv6 address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IP6T_ROUTE_CONTINUE 0x01 +#define IP6T_ROUTE_TEE 0x02 + +#endif /*_IP6T_ROUTE_H_target*/ diff --git a/release/src/linux/linux/net/ipv4/arp.c b/release/src/linux/linux/net/ipv4/arp.c index e458f7d5e6..aecd020aaa 100644 --- a/release/src/linux/linux/net/ipv4/arp.c +++ b/release/src/linux/linux/net/ipv4/arp.c @@ -171,8 +171,8 @@ struct neigh_table arp_tbl = { id: "arp_cache", parms: { tbl: &arp_tbl, -/*zhijian 2006-10-23 modify to solve arp entry timeout problem(cdrouter3.3 scaling module)*/ -#if 0 + /*zhijian 2006-10-23 modify to solve arp entry timeout problem(cdrouter3.3 scaling module)*/ + #if 0 base_reachable_time: 30 * HZ, retrans_time: 1 * HZ, gc_staletime: 60 * HZ, @@ -181,16 +181,16 @@ struct neigh_table arp_tbl = { queue_len: 3, ucast_probes: 3, mcast_probes: 3, -#else - base_reachable_time: 60 * HZ, - retrans_time: 5 * HZ, - gc_staletime: 120 * HZ, - reachable_time: 60 * HZ, - delay_probe_time: 10 * HZ, - queue_len: 3, - ucast_probes: 6, - mcast_probes: 6, -#endif + #else + base_reachable_time: 60 * HZ, + retrans_time: 5 * HZ, + gc_staletime: 120 * HZ, + reachable_time: 60 * HZ, + delay_probe_time: 10 * HZ, + queue_len: 3, + ucast_probes: 6, + mcast_probes: 6, + #endif anycast_delay: 1 * HZ, proxy_delay: (8 * HZ) / 10, proxy_qlen: 64, diff --git a/release/src/linux/linux/net/ipv4/igmp.c b/release/src/linux/linux/net/ipv4/igmp.c index c53d8febcd..3f718f2a81 100644 --- a/release/src/linux/linux/net/ipv4/igmp.c +++ b/release/src/linux/linux/net/ipv4/igmp.c @@ -677,9 +677,8 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) count++; } err = -ENOBUFS; - // if (iml == NULL || count >= sysctl_igmp_max_memberships) - // 43011: modify for cdrouter v3.3 item 300(cdrouter_mcast_100) bug - if (iml == NULL || count > sysctl_igmp_max_memberships) + //if (iml == NULL || count >= sysctl_igmp_max_memberships) + if (iml == NULL || count > sysctl_igmp_max_memberships)// modify for cdrouter v3.3 item 300(cdrouter_mcast_100) bug goto done; memcpy(&iml->multi, imr, sizeof(*imr)); iml->next = sk->protinfo.af_inet.mc_list; diff --git a/release/src/linux/linux/net/ipv4/netfilter/Config.in b/release/src/linux/linux/net/ipv4/netfilter/Config.in index 110a3987a9..b1f7f9858c 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv4/netfilter/Config.in @@ -28,6 +28,7 @@ tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTA if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then # The simple matches. dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES + dep_tristate ' IPP2P match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES dep_tristate ' geoip match support' CONFIG_IP_NF_MATCH_GEOIP $CONFIG_IP_NF_IPTABLES dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES dep_tristate ' IP range match support' CONFIG_IP_NF_MATCH_IPRANGE $CONFIG_IP_NF_IPTABLES @@ -205,7 +206,8 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE - dep_tristate ' CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_FILTER + dep_tristate ' ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE + dep_tristate ' CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_FILTER dep_tristate ' IMQ target support' CONFIG_IP_NF_TARGET_IMQ $CONFIG_IP_NF_MANGLE fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES diff --git a/release/src/linux/linux/net/ipv4/netfilter/Makefile b/release/src/linux/linux/net/ipv4/netfilter/Makefile index 8b4bd57e12..80de56f339 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Makefile +++ b/release/src/linux/linux/net/ipv4/netfilter/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o # matches obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o +obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o obj-$(CONFIG_IP_NF_MATCH_GEOIP) += ipt_geoip.o obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o @@ -158,6 +159,7 @@ obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c new file mode 100644 index 0000000000..b97d779260 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c @@ -0,0 +1,422 @@ +/* + * This implements the ROUTE target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2002 Cedric de Launois + * + * v 1.11 2004/11/23 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + + +/* Try to route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: -1 if an error occured + * 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int route(struct sk_buff *skb, + unsigned int ifindex, + const struct ipt_route_target_info *route_info) +{ + int err; + struct rtable *rt; + struct iphdr *iph = skb->nh.iph; + struct rt_key key = { + dst:iph->daddr, + src:0, + oif:ifindex, + tos:RT_TOS(iph->tos) + }; + + /* The destination address may be overloaded by the target */ + if (route_info->gw) + key.dst = route_info->gw; + + /* Trying to route the packet using the standard routing table. */ + if ((err = ip_route_output_key(&rt, &key))) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err); + return -1; + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = NULL; + + /* Success if no oif specified or if the oif correspond to the + * one desired */ + if (!ifindex || rt->u.dst.dev->ifindex == ifindex) { + skb->dst = &rt->u.dst; + skb->dev = skb->dst->dev; + return 1; + } + + /* The interface selected by the routing table is not the one + * specified by the user. This may happen because the dst address + * is one of our own addresses. + */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", + NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex); + + return 0; +} + + +/* Stolen from ip_finish_output2 + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +/* PRE : skb->dev is set to the device we are leaving by + * POST: - the packet is directly sent to the skb->dev device, without + * pushing the link layer header. + * - the packet is destroyed + */ +static inline int dev_direct_send(struct sk_buff *skb) +{ + return dev_queue_xmit(skb); +} + + +static unsigned int route_oif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif); + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + switch (route(skb, ifindex, route_info)) { + case 1: + dev_put(dev_out); + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + + case 0: + /* Failed to send to oif. Trying the hard way */ + if (route_info->flags & IPT_ROUTE_CONTINUE) + return NF_DROP; + + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: forcing the use of %i\n", + ifindex); + + /* We have to force the use of an interface. + * This interface must be a tunnel interface since + * otherwise we can't guess the hw address for + * the packet. For a tunnel interface, no hw address + * is needed. + */ + if ((dev_out->type != ARPHRD_TUNNEL) + && (dev_out->type != ARPHRD_IPGRE)) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: can't guess the hw addr !\n"); + dev_put(dev_out); + return NF_DROP; + } + + /* Send the packet. This will also free skb + * Do not go through the POST_ROUTING hook because + * skb->dst is not set and because it will probably + * get confused by the destination IP address. + */ + skb->dev = dev_out; + dev_direct_send(skb); + dev_put(dev_out); + return NF_STOLEN; + + default: + /* Unexpected error */ + dev_put(dev_out); + return NF_DROP; + } +} + + +static unsigned int route_iif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + struct net_device *dev_in = NULL; + + /* Getting the current interface index. */ + if (!(dev_in = dev_get_by_name(route_info->iif))) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif); + return NF_DROP; + } + + skb->dev = dev_in; + dst_release(skb->dst); + skb->dst = NULL; + + netif_rx(skb); + dev_put(dev_in); + return NF_STOLEN; +} + + +static unsigned int route_gw(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route(skb, 0, route_info)!=1) + return NF_DROP; + + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; +} + +/* To detect and deter routed packet loopback when using the --tee option, + * we take a page out of the raw.patch book: on the copied skb, we set up + * a fake ->nfct entry, pointing to the local &route_tee_track. We skip + * routing packets when we see they already have that ->nfct. + */ + +static struct ip_conntrack route_tee_track; + +static unsigned int ipt_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + unsigned int res; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_IN) { + + struct iphdr *iph = skb->nh.iph; + + if (iph->ttl <= 1) { + struct rtable *rt; + + if (ip_route_output(&rt, iph->saddr, iph->daddr, + RT_TOS(iph->tos) | RTO_CONN, + 0)) { + return NF_DROP; + } + + if (skb->dev == rt->u.dst.dev) { + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(skb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + } + + return NF_DROP; + } + + /* + * If we are at INPUT the checksum must be recalculated since + * the length could change as the result of a defragmentation. + * -- Rickard Molin + */ + if(hooknum == NF_IP_LOCAL_IN) { + iph->ttl = iph->ttl - 1; + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + } else { + ip_decrease_ttl(iph); + } + } + + if ((route_info->flags & IPT_ROUTE_TEE)) { + /* + * Copy the *pskb, and route the copy. Will later return + * IPT_CONTINUE for the original skb, which should continue + * on its way as if nothing happened. The copy should be + * independantly delivered to the ROUTE --gw. + */ + skb = skb_copy(*pskb, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n"); + return IPT_CONTINUE; + } + } + + /* Tell conntrack to forget this packet since it may get confused + * when a packet is leaving with dst address == our address. + * Good idea ? Dunno. Need advice. + * + * NEW: mark the skb with our &route_tee_track, so we avoid looping + * on any already routed packet. + */ + if (!(route_info->flags & IPT_ROUTE_CONTINUE)) { + nf_conntrack_put(skb->nfct); + skb->nfct = &route_tee_track.infos[IP_CT_NEW]; + nf_conntrack_get(skb->nfct); + skb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif + } + + if (route_info->oif[0]) { + res = route_oif(route_info, skb); + } else if (route_info->iif[0]) { + res = route_iif(route_info, skb); + } else if (route_info->gw) { + res = route_gw(route_info, skb); + } else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n"); + res = IPT_CONTINUE; + } + + if ((route_info->flags & IPT_ROUTE_TEE)) + res = IPT_CONTINUE; + + return res; +} + + +static int ipt_route_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n", + tablename); + return 0; + } + + if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING) + | (1 << NF_IP_LOCAL_IN) + | (1 << NF_IP_FORWARD) + | (1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) { + printk("ipt_ROUTE: bad hook\n"); + return 0; + } + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) { + printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ipt_target ipt_route_reg += { { NULL, NULL }, "ROUTE", ipt_route_target, ipt_route_checkentry, NULL, + THIS_MODULE }; + + +static int __init init(void) +{ + /* Set up fake conntrack (stolen from raw.patch): + - to never be deleted, not in any hashes */ + atomic_set(&route_tee_track.ct_general.use, 1); + /* - and look it like as a confirmed connection */ + set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status); + /* - and prepare the ctinfo field for REJECT/NAT. */ + route_tee_track.infos[IP_CT_NEW].master = + route_tee_track.infos[IP_CT_RELATED].master = + route_tee_track.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = + &route_tee_track.ct_general; + /* Initialize fake conntrack so that NAT will skip it */ + route_tee_track.nat.info.initialized |= + (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); + + if (ipt_register_target(&ipt_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c index 568d1bf0af..abf8efff65 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c new file mode 100644 index 0000000000..c36b2005be --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c @@ -0,0 +1,868 @@ +#if defined(MODVERSIONS) +#include +#endif +#include +#include +#include +#include +#include +#include + +#define get_u8(X,O) (*(__u8 *)(X + O)) +#define get_u16(X,O) (*(__u16 *)(X + O)) +#define get_u32(X,O) (*(__u32 *)(X + O)) + +MODULE_AUTHOR("Eicke Friedrich/Klaus Degner "); +MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic."); +MODULE_LICENSE("GPL"); + + +/*Search for UDP eDonkey/eMule/Kad commands*/ +int +udp_search_edk (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + t += 8; + + switch (t[0]) { + case 0xe3: + { /*edonkey*/ + switch (t[1]) + { + /* client -> server status request */ + case 0x96: + if (packet_len == 14) return ((IPP2P_EDK * 100) + 50); + break; + /* server -> client status request */ + case 0x97: if (packet_len == 42) return ((IPP2P_EDK * 100) + 51); + break; + /* server description request */ + /* e3 2a ff f0 .. | size == 6 */ + case 0xa2: if ( (packet_len == 14) && ( get_u16(t,2) == __constant_htons(0xfff0) ) ) return ((IPP2P_EDK * 100) + 52); + break; + /* server description response */ + /* e3 a3 ff f0 .. | size > 40 && size < 200 */ + //case 0xa3: return ((IPP2P_EDK * 100) + 53); + // break; + case 0x9a: if (packet_len==26) return ((IPP2P_EDK * 100) + 54); + break; + + case 0x92: if (packet_len==18) return ((IPP2P_EDK * 100) + 55); + break; + } + break; + } + case 0xe4: + { + switch (t[1]) + { + /* e4 20 .. | size == 43 */ + case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 60); + break; + /* e4 00 .. 00 | size == 35 ? */ + case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 61); + break; + /* e4 10 .. 00 | size == 35 ? */ + case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 62); + break; + /* e4 18 .. 00 | size == 35 ? */ + case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 63); + break; + /* e4 52 .. | size = 44 */ + case 0x52: if (packet_len == 44 ) return ((IPP2P_EDK * 100) + 64); + break; + /* e4 58 .. | size == 6 */ + case 0x58: if (packet_len == 14 ) return ((IPP2P_EDK * 100) + 65); + break; + /* e4 59 .. | size == 2 */ + case 0x59: if (packet_len == 10 )return ((IPP2P_EDK * 100) + 66); + break; + /* e4 28 .. | packet_len == 52,77,102,127... */ + case 0x28: if (((packet_len-52) % 25) == 0) return ((IPP2P_EDK * 100) + 67); + break; + /* e4 50 xx xx | size == 4 */ + case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 68); + break; + /* e4 40 xx xx | size == 48 */ + case 0x40: if (packet_len == 56) return ((IPP2P_EDK * 100) + 69); + break; + } + break; + } + } /* end of switch (t[0]) */ + return 0; +}/*udp_search_edk*/ + + +/*Search for UDP Gnutella commands*/ +int +udp_search_gnu (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + t += 8; + + if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 51); + if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 52); + return 0; +}/*udp_search_gnu*/ + + +/*Search for UDP KaZaA commands*/ +int +udp_search_kazaa (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + + if (t[packet_len-1] == 0x00){ + t += (packet_len - 6); + if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100 +50); + } + + return 0; +}/*udp_search_kazaa*/ + +/*Search for UDP DirectConnect commands*/ +int +udp_search_directconnect (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + if ((*(t + 8) == 0x24) && (*(t + packet_len - 1) == 0x7c)) { + t+=8; + if (memcmp(t, "SR ", 3) == 0) return ((IPP2P_DC * 100) + 60); + if (memcmp(t, "Ping ", 5) == 0) return ((IPP2P_DC * 100) + 61); + } + return 0; +}/*udp_search_directconnect*/ + + + +/*Search for UDP BitTorrent commands*/ +int +udp_search_bit (unsigned char *haystack, int packet_len) +{ + switch(packet_len) + { + case 24: + /* ^ 00 00 04 17 27 10 19 80 */ + if ((ntohl(get_u32(haystack, 8)) == 0x00000417) && (ntohl(get_u32(haystack, 12)) == 0x27101980)) + return (IPP2P_BIT * 100 + 50); + break; + case 44: + if (get_u32(haystack, 16) == __constant_htonl(0x00000400) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 51); + if (get_u32(haystack, 16) == __constant_htonl(0x00000400)) + return (IPP2P_BIT * 100 + 61); + break; + case 65: + if (get_u32(haystack, 16) == __constant_htonl(0x00000404) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 52); + if (get_u32(haystack, 16) == __constant_htonl(0x00000404)) + return (IPP2P_BIT * 100 + 62); + break; + case 67: + if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 53); + if (get_u32(haystack, 16) == __constant_htonl(0x00000406)) + return (IPP2P_BIT * 100 + 63); + break; + case 211: + if (get_u32(haystack, 8) == __constant_htonl(0x00000405)) + return (IPP2P_BIT * 100 + 54); + break; + case 29: + if ((get_u32(haystack, 8) == __constant_htonl(0x00000401))) + return (IPP2P_BIT * 100 + 55); + break; + case 52: + if (get_u32(haystack,8) == __constant_htonl(0x00000827) && + get_u32(haystack,12) == __constant_htonl(0x37502950)) + return (IPP2P_BIT * 100 + 80); + break; + default: + /* this packet does not have a constant size */ + if (packet_len >= 40 && get_u32(haystack, 16) == __constant_htonl(0x00000402) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 56); + break; + } + + /* some extra-bitcomet rules: + * "d1:" [a|r] "d2:id20:" + */ + if (packet_len > 30 && get_u8(haystack, 8) == 'd' && get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':' ) + { + if (get_u8(haystack, 11) == 'a' || get_u8(haystack, 11) == 'r') + { + if (memcmp(haystack+12,"d2:id20:",8)==0) + return (IPP2P_BIT * 100 + 57); + } + } + +#if 0 + /* bitlord rules */ + /* packetlen must be bigger than 40 */ + /* first 4 bytes are zero */ + if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000) + { + /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/ + if (get_u32(haystack, 12) == 0x00000000 && + get_u32(haystack, 16) == 0x00010000 && + get_u32(haystack, 24) == 0x00000000 ) + return (IPP2P_BIT * 100 + 71); + + /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/ + if (get_u32(haystack, 12) == 0x00000001 && + get_u32(haystack, 16) == 0x000d0000 && + get_u32(haystack, 24) == 0x00000000 ) + return (IPP2P_BIT * 100 + 71); + + + } +#endif + + return 0; +}/*udp_search_bit*/ + + + +/*Search for Ares commands*/ +//#define IPP2P_DEBUG_ARES +int +search_ares (const unsigned char *payload, const u16 plen) +//int search_ares (unsigned char *haystack, int packet_len, int head_len) +{ +// const unsigned char *t = haystack + head_len; + + /* all ares packets start with */ + if (payload[1] == 0 && (plen - payload[0]) == 3) + { + switch (payload[2]) + { + case 0x5a: + /* ares connect */ + if ( plen == 6 && payload[5] == 0x05 ) return ((IPP2P_ARES * 100) + 1); + break; + case 0x09: + /* ares search, min 3 chars --> 14 bytes + * lets define a search can be up to 30 chars --> max 34 bytes + */ + if ( plen >= 14 && plen <= 34 ) return ((IPP2P_ARES * 100) + 1); + break; +#ifdef IPP2P_DEBUG_ARES + default: + printk(KERN_DEBUG "Unknown Ares command %x recognized, len: %u \n", (unsigned int) payload[2],plen); +#endif /* IPP2P_DEBUG_ARES */ + } + } + +#if 0 + /* found connect packet: 03 00 5a 04 03 05 */ + /* new version ares 1.8: 03 00 5a xx xx 05 */ + if ((plen) == 6){ /* possible connect command*/ + if ((payload[0] == 0x03) && (payload[1] == 0x00) && (payload[2] == 0x5a) && (payload[5] == 0x05)) + return ((IPP2P_ARES * 100) + 1); + } + if ((plen) == 60){ /* possible download command*/ + if ((payload[59] == 0x0a) && (payload[58] == 0x0a)){ + if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */ + return ((IPP2P_ARES * 100) + 2); + } + } +#endif + + return 0; +} /*search_ares*/ + +/*Search for SoulSeek commands*/ +int +search_soul (const unsigned char *payload, const u16 plen) +{ +//#define IPP2P_DEBUG_SOUL + /* match: xx xx xx xx | xx = sizeof(payload) - 4 */ + if (get_u32(payload, 0) == (plen - 4)){ + const __u32 m=get_u32(payload, 4); + /* match 00 yy yy 00, yy can be everything */ + if ( get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "0: Soulseek command 0x%x recognized\n",get_u32(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 1); + } + + /* next match: 01 yy 00 00 | yy can be everything */ + if ( get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "1: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 2); + } + + /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */ + /* try to do this in an intelligent way */ + /* get all small commandos */ + switch(m) + { + case 7: + case 9: + case 22: + case 23: + case 26: + case 28: + case 50: + case 51: + case 60: + case 91: + case 92: + case 1001: +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "2: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 3); + } + + if (m > 0 && m < 6 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "3: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 4); + } + if (m > 12 && m < 19 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "4: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 5); + } + + if (m > 34 && m < 38 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "5: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 6); + } + + if (m > 39 && m < 47 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "6: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 7); + } + + if (m > 61 && m < 70 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "7: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 8); + } + +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first 16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",get_u32(payload, 4),get_u16(payload, 4) >> 16,get_u8(payload, 4) >> 24); +#endif /* IPP2P_DEBUG_SOUL */ + } + + /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */ + /* without size at the beginning !!! */ + if ( get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01 ) + { + __u32 y=get_u32(payload, 5); + /* we need 19 chars + string */ + if ( (y + 19) <= (plen) ) + { + const unsigned char *w=payload+9+y; + if (get_u32(w, 0) == 0x01 && ( get_u16(w, 4) == 0x4600 || get_u16(w, 4) == 0x5000) && get_u32(w, 6) == 0x00); +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "Soulssek special client command recognized\n"); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 9); + } + } + return 0; +} + + +/*Search for WinMX commands*/ +int +search_winmx (const unsigned char *payload, const u16 plen) +{ +//#define IPP2P_DEBUG_WINMX + if (((plen) == 4) && (memcmp(payload, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1); + if (((plen) == 3) && (memcmp(payload, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2); + //if (packet_len < (head_len + 10)) return 0; + if (plen < 10) return 0; + + if ((memcmp(payload, "SEND", 4) == 0) || (memcmp(payload, "GET", 3) == 0)){ + u16 c=4; + const u16 end=plen-2; + u8 count=0; + while (c < end) + { + if (payload[c]== 0x20 && payload[c+1] == 0x22) + { + c++; + count++; + if (count>=2) return ((IPP2P_WINMX * 100) + 3); + } + c++; + } + } + + if ( plen == 149 && payload[0] == '8' ) + { +#ifdef IPP2P_DEBUG_WINMX + printk(KERN_INFO "maybe WinMX\n"); +#endif + if (get_u32(payload,17) == 0 && get_u32(payload,21) == 0 && get_u32(payload,25) == 0 && +// get_u32(payload,33) == __constant_htonl(0x71182b1a) && get_u32(payload,37) == __constant_htonl(0x05050000) && +// get_u32(payload,133) == __constant_htonl(0x31097edf) && get_u32(payload,145) == __constant_htonl(0xdcb8f792)) + get_u16(payload,39) == 0 && get_u16(payload,135) == __constant_htons(0x7edf) && get_u16(payload,147) == __constant_htons(0xf792)) + + { +#ifdef IPP2P_DEBUG_WINMX + printk(KERN_INFO "got WinMX\n"); +#endif + return ((IPP2P_WINMX * 100) + 4); + } + } + return 0; +} /*search_winmx*/ + + +/*Search for appleJuice commands*/ +int +search_apple (const unsigned char *payload, const u16 plen) +{ + if ( (plen > 7) && (payload[6] == 0x0d) && (payload[7] == 0x0a) && (memcmp(payload, "ajprot", 6) == 0)) return (IPP2P_APPLE * 100); + + return 0; +} + + +/*Search for BitTorrent commands*/ +int +search_bittorrent (const unsigned char *payload, const u16 plen) +{ + if (plen > 20) + { + /* test for match 0x13+"BitTorrent protocol" */ + if (payload[0] == 0x13) + { + if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100); + } + + /* get tracker commandos, all starts with GET / + * then it can follow: scrape| announce + * and then ?hash_info= + */ + if (memcmp(payload,"GET /",5) == 0) + { + /* message scrape */ + if ( memcmp(payload+5,"scrape?info_hash=",17)==0 ) return (IPP2P_BIT * 100 + 1); + /* message announce */ + if ( memcmp(payload+5,"announce?info_hash=",19)==0 ) return (IPP2P_BIT * 100 + 2); + } + } + else + { + /* bitcomet encryptes the first packet, so we have to detect another + * one later in the flow */ + /* first try failed, too many missdetections */ + //if ( size == 5 && get_u32(t,0) == __constant_htonl(1) && t[4] < 3) return (IPP2P_BIT * 100 + 3); + + /* second try: block request packets */ + if ( plen == 17 && get_u32(payload,0) == __constant_htonl(0x0d) && payload[4] == 0x06 && get_u32(payload,13) == __constant_htonl(0x4000) ) return (IPP2P_BIT * 100 + 3); + } + + return 0; +} + + + +/*check for Kazaa get command*/ +int +search_kazaa (const unsigned char *payload, const u16 plen) + +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a) && memcmp(payload, "GET /.hash=", 11) == 0) + return (IPP2P_DATA_KAZAA * 100); + + return 0; +} + + +/*check for gnutella get command*/ +int +search_gnu (const unsigned char *payload, const u16 plen) +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + if (memcmp(payload, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1); + if (memcmp(payload, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2); + } + return 0; +} + + +/*check for gnutella get commands and other typical data*/ +int +search_all_gnu (const unsigned char *payload, const u16 plen) +{ + + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + + if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1); + if (memcmp(payload, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2); + + + if ((memcmp(payload, "GET /get/", 9) == 0) || (memcmp(payload, "GET /uri-res/", 13) == 0)) + { + u16 c=8; + const u16 end=plen-22; + while (c < end) { + if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Gnutella-", 11) == 0) || (memcmp(&payload[c+2], "X-Queue:", 8) == 0))) + return ((IPP2P_GNU * 100) + 3); + c++; + } + } + } + return 0; +} + + +/*check for KaZaA download commands and other typical data*/ +int +search_all_kazaa (const unsigned char *payload, const u16 plen) +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + + if (memcmp(payload, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1); + + if (memcmp(payload, "GET /", 5) == 0) { + u16 c = 8; + const u16 end=plen-22; + while (c < end) { + if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) || (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0))) + return ((IPP2P_KAZAA * 100) + 2); + c++; + } + } + } + return 0; +} + +/*fast check for edonkey file segment transfer command*/ +int +search_edk (const unsigned char *payload, const u16 plen) +{ + if (payload[0] != 0xe3) + return 0; + else { + if (payload[5] == 0x47) + return (IPP2P_DATA_EDK * 100); + else + return 0; + } +} + + + +/*intensive but slower search for some edonkey packets including size-check*/ +int +search_all_edk (const unsigned char *payload, const u16 plen) +{ + if (payload[0] != 0xe3) + return 0; + else { + //t += head_len; + const u16 cmd = get_u16(payload, 1); + if (cmd == (plen - 5)) { + switch (payload[5]) { + case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/ + case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/ + } + } + return 0; + } +} + + +/*fast check for Direct Connect send command*/ +int +search_dc (const unsigned char *payload, const u16 plen) +{ + + if (payload[0] != 0x24 ) + return 0; + else { + if (memcmp(&payload[1], "Send|", 5) == 0) + return (IPP2P_DATA_DC * 100); + else + return 0; + } + +} + + +/*intensive but slower check for all direct connect packets*/ +int +search_all_dc (const unsigned char *payload, const u16 plen) +{ +// unsigned char *t = haystack; + + if (payload[0] == 0x24 && payload[plen-1] == 0x7c) + { + const unsigned char *t=&payload[1]; + /* Client-Hub-Protocol */ + if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1); + /* Client-Client-Protocol, some are already recognized by client-hub (like lock) */ + if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 38); + } + return 0; +} + +/*check for mute*/ +int +search_mute (const unsigned char *payload, const u16 plen) +{ + if ( plen == 209 || plen == 345 || plen == 473 || plen == 609 || plen == 1121 ) + { + //printk(KERN_DEBUG "size hit: %u",size); + if (memcmp(payload,"PublicKey: ",11) == 0 ) + { + return ((IPP2P_MUTE * 100) + 0); + +/* if (memcmp(t+size-14,"\x0aEndPublicKey\x0a",14) == 0) + { + printk(KERN_DEBUG "end pubic key hit: %u",size); + + }*/ + } + } + return 0; +} + + +/* check for xdcc */ +int +search_xdcc (const unsigned char *payload, const u16 plen) +{ + /* search in small packets only */ + if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a && payload[plen-2] == 0x0d && memcmp(payload,"PRIVMSG ",8) == 0) + { + + u16 x=10; + const u16 end=plen - 13; + + /* is seems to be a irc private massage, chedck for xdcc command */ + while (x < end) + { + if (payload[x] == ':') + { + if ( memcmp(&payload[x+1],"xdcc send #",11) == 0 ) + return ((IPP2P_XDCC * 100) + 0); + } + x++; + } + } + return 0; +} + +/* search for waste */ +int search_waste(const unsigned char *payload, const u16 plen) +{ + if ( plen >= 8 && memcmp(payload,"GET.sha1:",9) == 0) + return ((IPP2P_WASTE * 100) + 0); + + return 0; +} + + +static struct { + int command; + __u8 short_hand; /*for fucntions included in short hands*/ + int packet_len; + int (*function_name) (const unsigned char *, const u16); +} matchlist[] = { + {IPP2P_EDK,SHORT_HAND_IPP2P,20, &search_all_edk}, +// {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa}, +// {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk}, +// {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc}, + {IPP2P_DC,SHORT_HAND_IPP2P,5, search_all_dc}, +// {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu}, + {IPP2P_GNU,SHORT_HAND_IPP2P,5, &search_all_gnu}, + {IPP2P_KAZAA,SHORT_HAND_IPP2P,5, &search_all_kazaa}, + {IPP2P_BIT,SHORT_HAND_IPP2P,20, &search_bittorrent}, + {IPP2P_APPLE,SHORT_HAND_IPP2P,5, &search_apple}, + {IPP2P_SOUL,SHORT_HAND_IPP2P,5, &search_soul}, + {IPP2P_WINMX,SHORT_HAND_IPP2P,2, &search_winmx}, + {IPP2P_ARES,SHORT_HAND_IPP2P,5, &search_ares}, + {IPP2P_MUTE,SHORT_HAND_NONE,200, &search_mute}, + {IPP2P_WASTE,SHORT_HAND_NONE,5, &search_waste}, + {IPP2P_XDCC,SHORT_HAND_NONE,5, &search_xdcc}, + {0,0,0,NULL} +}; + + +static struct { + int command; + __u8 short_hand; /*for fucntions included in short hands*/ + int packet_len; + int (*function_name) (unsigned char *, int); +} udp_list[] = { + {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa}, + {IPP2P_BIT,SHORT_HAND_IPP2P,23, &udp_search_bit}, + {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu}, + {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk}, + {IPP2P_DC,SHORT_HAND_IPP2P,12, &udp_search_directconnect}, + {0,0,0,NULL} +}; + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + const void *hdr, + u_int16_t datalen, +#endif + + int *hotdrop) +{ + const struct ipt_p2p_info *info = matchinfo; + unsigned char *haystack; + struct iphdr *ip = skb->nh.iph; + int p2p_result = 0, i = 0; +// int head_len; + int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/ + + /*must not be a fragment*/ + if (offset) { + if (info->debug) printk("IPP2P.match: offset found %i \n",offset); + return 0; + } + + /*make sure that skb is linear*/ + if(skb_is_nonlinear(skb)){ + if (info->debug) printk("IPP2P.match: nonlinear skb found\n"); + return 0; + } + + + haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/ + + switch (ip->protocol){ + case IPPROTO_TCP: /*what to do with a TCP packet*/ + { + struct tcphdr *tcph = (void *) ip + ip->ihl * 4; + + if (tcph->fin) return 0; /*if FIN bit is set bail out*/ + if (tcph->syn) return 0; /*if SYN bit is set bail out*/ + if (tcph->rst) return 0; /*if RST bit is set bail out*/ + + haystack += tcph->doff * 4; /*get TCP-Header-Size*/ + hlen -= tcph->doff * 4; + while (matchlist[i].command) { + if ((((info->cmd & matchlist[i].command) == matchlist[i].command) || + ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) && + (hlen > matchlist[i].packet_len)) { + p2p_result = matchlist[i].function_name(haystack, hlen); + if (p2p_result) + { + if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", + p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen); + return p2p_result; + } + } + i++; + } + return p2p_result; + } + + case IPPROTO_UDP: /*what to do with an UDP packet*/ + { + struct udphdr *udph = (void *) ip + ip->ihl * 4; + + while (udp_list[i].command){ + if ((((info->cmd & udp_list[i].command) == udp_list[i].command) || + ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) && + (hlen > udp_list[i].packet_len)) { + p2p_result = udp_list[i].function_name(haystack, hlen); + if (p2p_result){ + if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", + p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen); + return p2p_result; + } + } + i++; + } + return p2p_result; + } + + default: return 0; + } +} + + + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Must specify -p tcp */ +/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { + * printk("ipp2p: Only works on TCP packets, use -p tcp\n"); + * return 0; + * }*/ + return 1; +} + + + + +static struct ipt_match ipp2p_match = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + { NULL, NULL }, + "ipp2p", + &match, + &checkentry, + NULL, + THIS_MODULE +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .name = "ipp2p", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE, +#endif +}; + + +static int __init init(void) +{ + printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION); + return ipt_register_match(&ipp2p_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipp2p_match); + printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION); +} + +module_init(init); +module_exit(fini); + + diff --git a/release/src/linux/linux/net/ipv4/route.c b/release/src/linux/linux/net/ipv4/route.c index f3cf20dfc4..dfae08719b 100644 --- a/release/src/linux/linux/net/ipv4/route.c +++ b/release/src/linux/linux/net/ipv4/route.c @@ -2465,7 +2465,6 @@ void __init ip_rt_init(void) panic("IP: failed to allocate ip_dst_cache\n"); goal = num_physpages >> (26 - PAGE_SHIFT); -// goal = num_physpages >> (21 - PAGE_SHIFT); for (order = 0; (1UL << order) < goal; order++) /* NOTHING */; @@ -2495,18 +2494,9 @@ void __init ip_rt_init(void) rt_hash_table[i].chain = NULL; } -// ip_rt_max_size = (rt_hash_mask + 1) * 2; -// ipv4_dst_ops.gc_thresh = (ip_rt_max_size / 4); - ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); ip_rt_max_size = (rt_hash_mask + 1) * 16; -// printk("gc_thresh=%d\n", ipv4_dst_ops.gc_thresh); -// printk("ip_rt_max_size=%d\n", ip_rt_max_size); -// printk("rt_hash_mask=%d\n", rt_hash_mask); -// printk("goal=%d\n", goal); - - devinet_init(); ip_fib_init(); 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 7fe1644556..1f4081a911 100644 --- a/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c +++ b/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c @@ -221,18 +221,6 @@ ctl_table ipv4_table[] = { &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_TW_REUSE, "tcp_tw_reuse", &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, - {NET_TCP_VEGAS, "tcp_vegas_cong_avoid", - &sysctl_tcp_vegas_cong_avoid, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_TCP_VEGAS_ALPHA, "tcp_vegas_alpha", - &sysctl_tcp_vegas_alpha, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_TCP_VEGAS_BETA, "tcp_vegas_beta", - &sysctl_tcp_vegas_beta, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_TCP_VEGAS_GAMMA, "tcp_vegas_gamma", - &sysctl_tcp_vegas_gamma, sizeof(int), 0644, NULL, - &proc_dointvec}, {0} }; diff --git a/release/src/linux/linux/net/ipv4/tcp_input.c b/release/src/linux/linux/net/ipv4/tcp_input.c index 243e2991d1..8c99dd52e7 100644 --- a/release/src/linux/linux/net/ipv4/tcp_input.c +++ b/release/src/linux/linux/net/ipv4/tcp_input.c @@ -87,16 +87,6 @@ int sysctl_tcp_stdurg = 0; int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; -int sysctl_tcp_vegas_cong_avoid = 0; - -/* Default values of the Vegas variables, in fixed-point representation - * with V_PARAM_SHIFT bits to the right of the binary point. - */ -#define V_PARAM_SHIFT 1 -int sysctl_tcp_vegas_alpha = 1<vegas.do_vegas = 1; - tp->vegas.baseRTT = 0x7fffffff; - tcp_vegas_enable(tp); - } else - tcp_vegas_disable(tp); -} - -/* Do RTT sampling needed for Vegas. - * Basically we: - * o min-filter RTT samples from within an RTT to get the current - * propagation delay + queuing delay (we are min-filtering to try to - * avoid the effects of delayed ACKs) - * o min-filter RTT samples from a much longer window (forever for now) - * to find the propagation delay (baseRTT) - */ -static inline void vegas_rtt_calc(struct tcp_opt *tp, __u32 rtt) -{ - __u32 vrtt = rtt + 1; /* Never allow zero rtt or baseRTT */ - - /* Filter to find propagation delay: */ - if (vrtt < tp->vegas.baseRTT) - tp->vegas.baseRTT = vrtt; - - /* Find the min RTT during the last RTT to find - * the current prop. delay + queuing delay: - */ - tp->vegas.minRTT = min(tp->vegas.minRTT, vrtt); - tp->vegas.cntRTT++; -} - /* Called to compute a smoothed rtt estimate. The data fed to this * routine either comes from timestamps, or from segments that were * known _not_ to have been retransmitted [see Karn/Partridge @@ -458,9 +412,6 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) { long m = mrtt; /* RTT */ - if (tcp_vegas_enabled(tp)) - vegas_rtt_calc(tp, mrtt); - /* The following amusing code comes from Jacobson's * article in SIGCOMM '88. Note that rtt and mdev * are scaled versions of rtt and mean deviation. @@ -1062,7 +1013,7 @@ void tcp_enter_loss(struct sock *sk, int how) tcp_sync_left_out(tp); tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); - tcp_set_ca_state(tp, TCP_CA_Loss); + tp->ca_state = TCP_CA_Loss; tp->high_seq = tp->snd_nxt; TCP_ECN_queue_cwr(tp); } @@ -1424,7 +1375,7 @@ static int tcp_try_undo_recovery(struct sock *sk, struct tcp_opt *tp) tcp_moderate_cwnd(tp); return 1; } - tcp_set_ca_state(tp, TCP_CA_Open); + tp->ca_state = TCP_CA_Open; return 0; } @@ -1484,7 +1435,7 @@ static int tcp_try_undo_loss(struct sock *sk, struct tcp_opt *tp) tp->retransmits = 0; tp->undo_marker = 0; if (!IsReno(tp)) - tcp_set_ca_state(tp, TCP_CA_Open); + tp->ca_state = TCP_CA_Open; return 1; } return 0; @@ -1515,7 +1466,7 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_opt *tp, int flag) state = TCP_CA_Disorder; if (tp->ca_state != state) { - tcp_set_ca_state(tp, state); + tp->ca_state = state; tp->high_seq = tp->snd_nxt; } tcp_moderate_cwnd(tp); @@ -1589,7 +1540,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, * is ACKed for CWR bit to reach receiver. */ if (tp->snd_una != tp->high_seq) { tcp_complete_cwr(tp); - tcp_set_ca_state(tp, TCP_CA_Open); + tp->ca_state = TCP_CA_Open; } break; @@ -1600,7 +1551,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, * catching for all duplicate ACKs. */ IsReno(tp) || tp->snd_una != tp->high_seq) { tp->undo_marker = 0; - tcp_set_ca_state(tp, TCP_CA_Open); + tp->ca_state = TCP_CA_Open; } break; @@ -1674,7 +1625,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, } tp->snd_cwnd_cnt = 0; - tcp_set_ca_state(tp, TCP_CA_Recovery); + tp->ca_state = TCP_CA_Recovery; } if (is_dupack || tcp_head_timedout(sk, tp)) @@ -1745,7 +1696,7 @@ tcp_ack_update_rtt(struct tcp_opt *tp, int flag, s32 seq_rtt) /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ -static __inline__ void reno_cong_avoid(struct tcp_opt *tp) +static __inline__ void tcp_cong_avoid(struct tcp_opt *tp) { if (tp->snd_cwnd <= tp->snd_ssthresh) { /* In "safe" area, increase. */ @@ -1765,236 +1716,6 @@ static __inline__ void reno_cong_avoid(struct tcp_opt *tp) tp->snd_cwnd_stamp = tcp_time_stamp; } -/* This is based on the congestion detection/avoidance scheme described in - * Lawrence S. Brakmo and Larry L. Peterson. - * "TCP Vegas: End to end congestion avoidance on a global internet." - * IEEE Journal on Selected Areas in Communication, 13(8):1465--1480, - * October 1995. Available from: - * ftp://ftp.cs.arizona.edu/xkernel/Papers/jsac.ps - * - * See http://www.cs.arizona.edu/xkernel/ for their implementation. - * The main aspects that distinguish this implementation from the - * Arizona Vegas implementation are: - * o We do not change the loss detection or recovery mechanisms of - * Linux in any way. Linux already recovers from losses quite well, - * using fine-grained timers, NewReno, and FACK. - * o To avoid the performance penalty imposed by increasing cwnd - * only every-other RTT during slow start, we increase during - * every RTT during slow start, just like Reno. - * o Largely to allow continuous cwnd growth during slow start, - * we use the rate at which ACKs come back as the "actual" - * rate, rather than the rate at which data is sent. - * o To speed convergence to the right rate, we set the cwnd - * to achieve the right ("actual") rate when we exit slow start. - * o To filter out the noise caused by delayed ACKs, we use the - * minimum RTT sample observed during the last RTT to calculate - * the actual rate. - * o When the sender re-starts from idle, it waits until it has - * received ACKs for an entire flight of new data before making - * a cwnd adjustment decision. The original Vegas implementation - * assumed senders never went idle. - */ -static void vegas_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) -{ - /* The key players are v_beg_snd_una and v_beg_snd_nxt. - * - * These are so named because they represent the approximate values - * of snd_una and snd_nxt at the beginning of the current RTT. More - * precisely, they represent the amount of data sent during the RTT. - * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt, - * we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding - * bytes of data have been ACKed during the course of the RTT, giving - * an "actual" rate of: - * - * (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration) - * - * Unfortunately, v_beg_snd_una is not exactly equal to snd_una, - * because delayed ACKs can cover more than one segment, so they - * don't line up nicely with the boundaries of RTTs. - * - * Another unfortunate fact of life is that delayed ACKs delay the - * advance of the left edge of our send window, so that the number - * of bytes we send in an RTT is often less than our cwnd will allow. - * So we keep track of our cwnd separately, in v_beg_snd_cwnd. - */ - - if (after(ack, tp->vegas.beg_snd_nxt)) { - /* Do the Vegas once-per-RTT cwnd adjustment. */ - u32 old_wnd, old_snd_cwnd; - - - /* Here old_wnd is essentially the window of data that was - * sent during the previous RTT, and has all - * been acknowledged in the course of the RTT that ended - * with the ACK we just received. Likewise, old_snd_cwnd - * is the cwnd during the previous RTT. - */ - old_wnd = (tp->vegas.beg_snd_nxt - tp->vegas.beg_snd_una) / - tp->mss_cache; - old_snd_cwnd = tp->vegas.beg_snd_cwnd; - - /* Save the extent of the current window so we can use this - * at the end of the next RTT. - */ - tp->vegas.beg_snd_una = tp->vegas.beg_snd_nxt; - tp->vegas.beg_snd_nxt = tp->snd_nxt; - tp->vegas.beg_snd_cwnd = tp->snd_cwnd; - - /* Take into account the current RTT sample too, to - * decrease the impact of delayed acks. This double counts - * this sample since we count it for the next window as well, - * but that's not too awful, since we're taking the min, - * rather than averaging. - */ - vegas_rtt_calc(tp, seq_rtt); - - /* We do the Vegas calculations only if we got enough RTT - * samples that we can be reasonably sure that we got - * at least one RTT sample that wasn't from a delayed ACK. - * If we only had 2 samples total, - * then that means we're getting only 1 ACK per RTT, which - * means they're almost certainly delayed ACKs. - * If we have 3 samples, we should be OK. - */ - - if (tp->vegas.cntRTT <= 2) { - /* We don't have enough RTT samples to do the Vegas - * calculation, so we'll behave like Reno. - */ - if (tp->snd_cwnd > tp->snd_ssthresh) - tp->snd_cwnd++; - } else { - u32 rtt, target_cwnd, diff; - - /* We have enough RTT samples, so, using the Vegas - * algorithm, we determine if we should increase or - * decrease cwnd, and by how much. - */ - - /* Pluck out the RTT we are using for the Vegas - * calculations. This is the min RTT seen during the - * last RTT. Taking the min filters out the effects - * of delayed ACKs, at the cost of noticing congestion - * a bit later. - */ - rtt = tp->vegas.minRTT; - - /* Calculate the cwnd we should have, if we weren't - * going too fast. - * - * This is: - * (actual rate in segments) * baseRTT - * We keep it as a fixed point number with - * V_PARAM_SHIFT bits to the right of the binary point. - */ - target_cwnd = ((old_wnd * tp->vegas.baseRTT) - << V_PARAM_SHIFT) / rtt; - - /* Calculate the difference between the window we had, - * and the window we would like to have. This quantity - * is the "Diff" from the Arizona Vegas papers. - * - * Again, this is a fixed point number with - * V_PARAM_SHIFT bits to the right of the binary - * point. - */ - diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd; - - if (tp->snd_cwnd < tp->snd_ssthresh) { - /* Slow start. */ - if (diff > sysctl_tcp_vegas_gamma) { - /* Going too fast. Time to slow down - * and switch to congestion avoidance. - */ - tp->snd_ssthresh = 2; - - /* Set cwnd to match the actual rate - * exactly: - * cwnd = (actual rate) * baseRTT - * Then we add 1 because the integer - * truncation robs us of full link - * utilization. - */ - tp->snd_cwnd = min(tp->snd_cwnd, - (target_cwnd >> - V_PARAM_SHIFT)+1); - - } - } else { - /* Congestion avoidance. */ - u32 next_snd_cwnd; - - /* Figure out where we would like cwnd - * to be. - */ - if (diff > sysctl_tcp_vegas_beta) { - /* The old window was too fast, so - * we slow down. - */ - next_snd_cwnd = old_snd_cwnd - 1; - } else if (diff < sysctl_tcp_vegas_alpha) { - /* We don't have enough extra packets - * in the network, so speed up. - */ - next_snd_cwnd = old_snd_cwnd + 1; - } else { - /* Sending just as fast as we - * should be. - */ - next_snd_cwnd = old_snd_cwnd; - } - - /* Adjust cwnd upward or downward, toward the - * desired value. - */ - if (next_snd_cwnd > tp->snd_cwnd) - tp->snd_cwnd++; - else if (next_snd_cwnd < tp->snd_cwnd) - tp->snd_cwnd--; - } - } - - /* Wipe the slate clean for the next RTT. */ - tp->vegas.cntRTT = 0; - tp->vegas.minRTT = 0x7fffffff; - } - - /* The following code is executed for every ack we receive, - * except for conditions checked in should_advance_cwnd() - * before the call to tcp_cong_avoid(). Mainly this means that - * we only execute this code if the ack actually acked some - * data. - */ - - /* If we are in slow start, increase our cwnd in response to this ACK. - * (If we are not in slow start then we are in congestion avoidance, - * and adjust our congestion window only once per RTT. See the code - * above.) - */ - if (tp->snd_cwnd <= tp->snd_ssthresh) - tp->snd_cwnd++; - - /* to keep cwnd from growing without bound */ - tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp); - - /* Make sure that we are never so timid as to reduce our cwnd below - * 2 MSS. - * - * Going below 2 MSS would risk huge delayed ACKs from our receiver. - */ - tp->snd_cwnd = max(tp->snd_cwnd, 2U); - - tp->snd_cwnd_stamp = tcp_time_stamp; -} - -static inline void tcp_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) -{ - if (tcp_vegas_enabled(tp)) - vegas_cong_avoid(tp, ack, seq_rtt); - else - reno_cong_avoid(tp); -} - /* Restart timer after forward progress on connection. * RFC2988 recommends to restart timer to now+rto. */ @@ -2009,7 +1730,7 @@ static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) } /* Remove acknowledged frames from the retransmission queue. */ -static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) +static int tcp_clean_rtx_queue(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; @@ -2092,7 +1813,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) } } #endif - *seq_rtt_p = seq_rtt; return acked; } @@ -2180,7 +1900,6 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) u32 ack_seq = TCP_SKB_CB(skb)->seq; u32 ack = TCP_SKB_CB(skb)->ack_seq; u32 prior_in_flight; - s32 seq_rtt; int prior_packets; /* If the ack is newer than sent or older than previous acks @@ -2228,19 +1947,17 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) prior_in_flight = tcp_packets_in_flight(tp); /* See if we can take anything off of the retransmit queue. */ - flag |= tcp_clean_rtx_queue(sk, &seq_rtt); + flag |= tcp_clean_rtx_queue(sk); if (tcp_ack_is_dubious(tp, flag)) { /* Advanve CWND, if state allows this. */ - if ((flag&FLAG_DATA_ACKED) && - (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd) && + if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd && tcp_may_raise_cwnd(tp, flag)) - tcp_cong_avoid(tp, ack, seq_rtt); + tcp_cong_avoid(tp); tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); } else { - if ((flag & FLAG_DATA_ACKED) && - (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd)) - tcp_cong_avoid(tp, ack, seq_rtt); + if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd) + tcp_cong_avoid(tp); } if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) diff --git a/release/src/linux/linux/net/ipv4/tcp_minisocks.c b/release/src/linux/linux/net/ipv4/tcp_minisocks.c index 6fdb768113..b69cc32c67 100644 --- a/release/src/linux/linux/net/ipv4/tcp_minisocks.c +++ b/release/src/linux/linux/net/ipv4/tcp_minisocks.c @@ -715,7 +715,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->snd_cwnd = 2; newtp->snd_cwnd_cnt = 0; - tcp_set_ca_state(newtp, TCP_CA_Open); + newtp->ca_state = TCP_CA_Open; tcp_init_xmit_timers(newsk); skb_queue_head_init(&newtp->out_of_order_queue); newtp->send_head = NULL; @@ -783,7 +783,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); - tcp_vegas_init(newtp); TCP_INC_STATS_BH(TcpPassiveOpens); } return newsk; diff --git a/release/src/linux/linux/net/ipv4/tcp_output.c b/release/src/linux/linux/net/ipv4/tcp_output.c index 3fd4871ff5..35cbbbf727 100644 --- a/release/src/linux/linux/net/ipv4/tcp_output.c +++ b/release/src/linux/linux/net/ipv4/tcp_output.c @@ -105,9 +105,6 @@ static void tcp_cwnd_restart(struct tcp_opt *tp) u32 restart_cwnd = tcp_init_cwnd(tp); u32 cwnd = tp->snd_cwnd; - if (tcp_is_vegas(tp)) - tcp_vegas_enable(tp); - tp->snd_ssthresh = tcp_current_ssthresh(tp); restart_cwnd = min(restart_cwnd, cwnd); @@ -226,19 +223,6 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb) tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); } - - /* - * If the connection is idle and we are restarting, - * then we don't want to do any Vegas calculations - * until we get fresh RTT samples. So when we - * restart, we reset our Vegas state to a clean - * slate. After we get acks for this flight of - * packets, _then_ we can make Vegas calculations - * again. - */ - if (tcp_is_vegas(tp) && tcp_packets_in_flight(tp) == 0) - tcp_vegas_enable(tp); - th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; skb_set_owner_w(skb, sk); @@ -816,7 +800,7 @@ void tcp_simple_retransmit(struct sock *sk) tp->snd_ssthresh = tcp_current_ssthresh(tp); tp->prior_ssthresh = 0; tp->undo_marker = 0; - tcp_set_ca_state(tp, TCP_CA_Loss); + tp->ca_state = TCP_CA_Loss; } tcp_xmit_retransmit_queue(sk); } @@ -1197,7 +1181,6 @@ static inline void tcp_connect_init(struct sock *sk) tp->window_clamp = dst->window; tp->advmss = dst->advmss; tcp_initialize_rcv_mss(sk); - tcp_vegas_init(tp); tcp_select_initial_window(tcp_full_space(sk), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), @@ -1248,7 +1231,6 @@ int tcp_connect(struct sock *sk) TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; - tcp_vegas_init(tp); /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; diff --git a/release/src/linux/linux/net/ipv6/netfilter/Config.in b/release/src/linux/linux/net/ipv6/netfilter/Config.in index c2311736d7..5d2dac2f3b 100644 --- a/release/src/linux/linux/net/ipv6/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv6/netfilter/Config.in @@ -56,6 +56,8 @@ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then if [ "$CONFIG_IP6_NF_MANGLE" != "n" ]; then # dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE dep_tristate ' MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE + dep_tristate ' ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE + dep_tristate ' IMQ target support' CONFIG_IP6_NF_TARGET_IMQ $CONFIG_IP6_NF_MANGLE fi #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES diff --git a/release/src/linux/linux/net/ipv6/netfilter/Makefile b/release/src/linux/linux/net/ipv6/netfilter/Makefile index 91cc75bcfd..2bd664f484 100644 --- a/release/src/linux/linux/net/ipv6/netfilter/Makefile +++ b/release/src/linux/linux/net/ipv6/netfilter/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o diff --git a/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c b/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c new file mode 100644 index 0000000000..bb6d11f83e --- /dev/null +++ b/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c @@ -0,0 +1,308 @@ +/* + * This implements the ROUTE v6 target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2003 Cedric de Launois + * + * v 1.1 2004/11/23 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) + +/* Route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int +route6(struct sk_buff *skb, + unsigned int ifindex, + const struct ip6t_route_target_info *route_info) +{ + struct rt6_info *rt = NULL; + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + + DEBUGP("ip6t_ROUTE: called with: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); + DEBUGP("OUT=%s\n", route_info->oif); + + if (ipv6_addr_any(gw)) + rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); + else + rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); + + if (!rt) + goto no_route; + + DEBUGP("ip6t_ROUTE: routing gives: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); + DEBUGP("OUT=%s\n", rt->rt6i_dev->name); + + if (ifindex && rt->rt6i_dev->ifindex!=ifindex) + goto wrong_route; + + if (!rt->rt6i_nexthop) { + DEBUGP("ip6t_ROUTE: discovering neighbour\n"); + rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + skb->dev = rt->rt6i_dev; + return 1; + + wrong_route: + dst_release(&rt->u.dst); + no_route: + if (!net_ratelimit()) + return 0; + + printk("ip6t_ROUTE: no explicit route found "); + if (ifindex) + printk("via interface %s ", route_info->oif); + if (!ipv6_addr_any(gw)) + printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); + printk("\n"); + return 0; +} + + +/* Stolen from ip6_output_finish + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +static unsigned int +route6_oif(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif); + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + else + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + if (route6(skb, ifindex, route_info)) { + dev_put(dev_out); + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +route6_gw(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route6(skb, 0, route_info)) { + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +ip6t_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + unsigned int res; + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + goto do_it; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP6_PRE_ROUTING || + hooknum == NF_IP6_LOCAL_IN) { + + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + + if (ipv6h->hop_limit <= 1) { + /* Force OUTPUT device used as source address */ + skb->dev = skb->dst->dev; + + icmpv6_send(skb, ICMPV6_TIME_EXCEED, + ICMPV6_EXC_HOPLIMIT, 0, skb->dev); + + return NF_DROP; + } + + ipv6h->hop_limit--; + } + + if ((route_info->flags & IP6T_ROUTE_TEE)) { + /* + * Copy the *pskb, and route the copy. Will later return + * IP6T_CONTINUE for the original skb, which should continue + * on its way as if nothing happened. The copy should be + * independantly delivered to the ROUTE --gw. + */ + skb = skb_copy(*pskb, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n"); + return IP6T_CONTINUE; + } + } + +do_it: + if (route_info->oif[0]) { + res = route6_oif(route_info, skb); + } else if (!ipv6_addr_any(gw)) { + res = route6_gw(route_info, skb); + } else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n"); + res = IP6T_CONTINUE; + } + + if ((route_info->flags & IP6T_ROUTE_TEE)) + res = IP6T_CONTINUE; + + return res; +} + + +static int +ip6t_route_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n"); + return 0; + } + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) { + printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IP6T_ALIGN(sizeof(struct ip6t_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ip6t_target ip6t_route_reg = { + .name = "ROUTE", + .target = ip6t_route_target, + .checkentry = ip6t_route_checkentry, + .me = THIS_MODULE +}; + + +static int __init init(void) +{ + printk(KERN_DEBUG "registering ipv6 ROUTE target\n"); + if (ip6t_register_target(&ip6t_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/router/Makefile b/release/src/router/Makefile index b6f75696bf..beb754ee55 100644 --- a/release/src/router/Makefile +++ b/release/src/router/Makefile @@ -13,15 +13,12 @@ include common.mak +# TOMATO_EXPERIMENTAL=1 # # # -ifeq ($(TOMATO_DEV),jon) -SEP=echo -e "\033[41;1m $@ \033[0m" -else -SEP=true -endif +SEP=echo "\033[41;1m $@ \033[0m" # # standard packages @@ -45,20 +42,11 @@ obj-y += ppp obj-y += ttcp obj-y += ntpc obj-y += rstats -# obj-y += ebtables -# obj-y += libbcm -# obj-y += libbcmcrypto -# obj-y += nas -# obj-y += wlconf - obj-y += mssl obj-y += mdu -ifeq ($(TEST_MINIUPNPD),1) obj-y += miniupnpd -else -obj-y += upnp -endif +# obj-y += upnp # @@ -66,13 +54,11 @@ endif # obj-$(TCONFIG_L2TP) += rp-l2tp obj-$(TCONFIG_PPTP) += pptp-client -# obj-$(TCONFIG_HEARTBEAT) += bpalogin -# obj-$(TCONFIG_DDNS) += ipupdate obj-$(TCONFIG_HTTPS) += openssl obj-$(TCONFIG_HTTPS) += matrixssl obj-$(TCONFIG_SSH) += dropbear obj-$(TCONFIG_ZEBRA) += zebra -obj-$(TCONFIG_IPP2P) += ipp2p +# obj-$(TCONFIG_IPP2P) += ipp2p ifeq ($(TCONFIG_L2TP),y) NEED_PPPD = y @@ -109,8 +95,9 @@ kernel: $(LINUXDIR)/.config kmod: dummy $(MAKE) -C $(LINUXDIR) modules -fooit: - @../btools/libfoo.pl +testfind: + cd $(TARGETDIR)/lib/modules/2.4.20 && find -name "*.o" -exec mv -i {} . \; || true + cd $(TARGETDIR)/lib/modules/2.4.20 && find -type d -delete || true install package: $(obj-install) $(LINUXDIR)/.config @$(SEP) @@ -165,13 +152,15 @@ endif install $(LIBDIR)/libc.so.0 $(TARGETDIR)/lib/ install $(LIBDIR)/libdl.so.0 $(TARGETDIR)/lib/ install $(LIBDIR)/libm.so.0 $(TARGETDIR)/lib/ - install $(LIBDIR)/libutil.so.0 $(TARGETDIR)/lib/ install $(LIBDIR)/libnsl.so.0 $(TARGETDIR)/lib/ +ifeq ($(TCONFIG_SSH),y) + install $(LIBDIR)/libutil.so.0 $(TARGETDIR)/lib/ +endif @cd $(TARGETDIR) && $(TOP)/others/rootprep.sh @echo --- - busybox/examples/depmod.pl -k $(LINUXDIR)/vmlinux -b $(TARGETDIR)/lib/modules/2.4.20/ + busybox/examples/depmod-t.pl -k $(LINUXDIR)/vmlinux -b $(TARGETDIR)/lib/modules/2.4.20/ @echo --- @rm -f $(TARGETDIR)/lib/modules/2.4.20/build @@ -262,31 +251,35 @@ oldconfig oldconf: roldconf koldconf # overrides and extra dependencies # -busybox: dummy - $(MAKE) -C busybox CFLAGS="-Os" +busybox: + @cd busybox && [ -s .config ] || ( cp config.save .config; $(MAKE) oldconfig ) + @$(MAKE) -C busybox CFLAGS="-Os" + @cp busybox/.config busybox/config.save + # V=1 busybox-install: rm -rf $(INSTALLDIR)/busybox $(MAKE) -C busybox install CONFIG_PREFIX=$(INSTALLDIR)/busybox CFLAGS="-Os" +busybox-clean: + cd busybox && [ -s .config ] && cp .config config.save + $(MAKE) -C busybox distclean + cd busybox && mv config.save .config + +busybox-config: + $(MAKE) -C busybox menuconfig + busybox-test: dummy $(MAKE) -C busybox objsizes CFLAGS="-Os" -# 1.2: -# busybox: busybox/include/bb_config.h -# @$(MAKE) -C busybox CROSS_CFLAGS="-mips2" -# busybox/include/bb_config.h: -# @$(MAKE) -C busybox oldconfig -# @$(MAKE) -C busybox clean -# busybox-install: -# rm -rf $(INSTALLDIR)/busybox -# $(MAKE) -C busybox install PREFIX=$(INSTALLDIR)/busybox httpd: matrixssl shared nvram mssl @$(SEP) @$(MAKE) -C httpd +www-install: + @$(MAKE) -C www install INSTALLDIR=$(INSTALLDIR)/www TOMATO_EXPERIMENTAL=$(TOMATO_EXPERIMENTAL) matrixssl: @$(SEP) @@ -364,12 +357,18 @@ ppp-%: $(MAKE) -C ppp/pppoecd $* INSTALLDIR=$(INSTALLDIR)/ppp - upnp: nvram shared iptables -# miniupnpd-install: -# install -D miniupnpd/miniupnpd $(INSTALLDIR)/miniupnpd/usr/sbin/miniupnpd -# $(STRIP) $(INSTALLDIR)/miniupnpd/usr/sbin/miniupnpd +miniupnpd: iptables + @$(SEP) + $(MAKE) -C miniupnpd -f Makefile.tomato + +miniupnpd-clean: + -$(MAKE) -C miniupnpd -f Makefile.tomato clean + +miniupnpd-install: + install -D miniupnpd/miniupnpd $(INSTALLDIR)/miniupnpd/usr/sbin/miniupnpd + $(STRIP) $(INSTALLDIR)/miniupnpd/usr/sbin/miniupnpd nvram: shared diff --git a/release/src/router/busybox/.config b/release/src/router/busybox/.config new file mode 100644 index 0000000000..472a37fb98 --- /dev/null +++ b/release/src/router/busybox/.config @@ -0,0 +1,883 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.14.0 +# Fri May 22 20:36:33 2009 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_FEATURE_ASSUME_UNICODE 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 is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_GETOPT_LONG=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_PIDFILE=y +CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_SUID_CONFIG 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_HAVE_RPC is not set + +# +# 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="mipsel-uclibc-" +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 +# CONFIG_INCLUDE_SUSv2 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_SIZE_VS_SPEED=2 +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 is not set +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# 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 is not set +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_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_DPKG_DEB_EXTRACT_ONLY is not set +CONFIG_GUNZIP=y +CONFIG_GZIP=y +# CONFIG_RPM2CPIO is not set +# CONFIG_RPM is not set +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +# CONFIG_FEATURE_TAR_AUTODETECT is not set +# CONFIG_FEATURE_TAR_FROM is not set +# CONFIG_FEATURE_TAR_OLDGNU_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_UNAME_GNAME is not set +# CONFIG_UNCOMPRESS is not set +# CONFIG_UNLZMA is not set +# CONFIG_FEATURE_LZMA_FAST is not set +CONFIG_UNZIP=y + +# +# Coreutils +# +# CONFIG_BASENAME is not set +# CONFIG_CAL is not set +CONFIG_CAT=y +# CONFIG_CATV is not set +# CONFIG_CHGRP is not set +CONFIG_CHMOD=y +# CONFIG_CHOWN is not set +# CONFIG_CHROOT is not set +# CONFIG_CKSUM is not set +# CONFIG_COMM is not set +CONFIG_CP=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +# CONFIG_FEATURE_DF_FANCY is not set +# 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_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_FOLD 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 +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 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 +CONFIG_PRINTF=y +CONFIG_PWD=y +# CONFIG_READLINK is not set +# CONFIG_FEATURE_READLINK_FOLLOW is not set +# CONFIG_REALPATH is not set +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_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +# CONFIG_SPLIT is not set +# CONFIG_FEATURE_SPLIT_FANCY is not set +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +# CONFIG_STTY is not set +# CONFIG_SUM is not set +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_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 is not set +# CONFIG_TTY is not set +CONFIG_UNAME=y +# CONFIG_UNEXPAND is not set +# 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_WC=y +CONFIG_FEATURE_WC_LARGE=y +# 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 +# +# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set + +# +# Console Utilities +# +# CONFIG_CHVT 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_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 + +# +# 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_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +# CONFIG_DIFF is not set +# CONFIG_FEATURE_DIFF_BINARY is not set +# CONFIG_FEATURE_DIFF_DIR is not set +# CONFIG_FEATURE_DIFF_MINIMAL is not set +# CONFIG_ED is not set +# CONFIG_PATCH 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_OPTIMIZE_CURSOR is not set +# CONFIG_FEATURE_ALLOW_EXEC is not set + +# +# Finding Utilities +# +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_EXEC=y +# CONFIG_FEATURE_FIND_USER is not set +# CONFIG_FEATURE_FIND_GROUP is not set +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_CONTEXT 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 + +# +# Init Utilities +# +# CONFIG_INIT is not set +# CONFIG_FEATURE_USE_INITTAB is not set +# 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_HALT is not set +# CONFIG_MESG is not set + +# +# Login/Password Management Utilities +# +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_ADDGROUP is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP 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_DELUSER is not set +# CONFIG_GETTY is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP 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 + +# +# Linux Ext2 FS Progs +# +# CONFIG_CHATTR is not set +# CONFIG_FSCK is not set +# CONFIG_LSATTR is not set + +# +# Linux Module Utilities +# +# 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_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +CONFIG_MODPROBE=y +# 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_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="/lib/modules/2.4.20/modules.dep" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +# CONFIG_BLKID 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_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_FDISK_ADVANCED is not set +# CONFIG_FINDFS is not set +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_VFAT is not set +# CONFIG_GETOPT 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_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_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_V0 is not set +CONFIG_MORE=y +CONFIG_FEATURE_USE_TERMIOS=y +# CONFIG_VOLUMEID is not set +# CONFIG_FEATURE_VOLUMEID_EXT is not set +# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +# 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 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 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=y +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +CONFIG_FEATURE_MOUNT_HELPERS=y +# 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 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_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# 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 is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_CHAT is not set +# CONFIG_FEATURE_CHAT_NOFAIL is not set +# 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_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_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 is not set +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +# CONFIG_FBSPLASH is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +# CONFIG_INOTIFYD is not set +# 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_FEATURE_MAKEDEVS_LEAF is not set +# CONFIG_FEATURE_MAKEDEVS_TABLE is not set +# CONFIG_MAN is not set +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +# CONFIG_RAIDAUTORUN is not set +# CONFIG_READAHEAD is not set +# CONFIG_RUNLEVEL is not set +# CONFIG_RX is not set +# CONFIG_SETSID is not set +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_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +CONFIG_ARPING=y +# 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_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_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_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_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE 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_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set +# 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_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_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_FEATURE_IPCALC_LONG_OPTIONS is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NC=y +# CONFIG_NC_SERVER is not set +CONFIG_NC_EXTRA=y +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +# CONFIG_FEATURE_NETSTAT_PRG is not set +CONFIG_NSLOOKUP=y +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_TELNET=y +# CONFIG_FEATURE_TELNET_TTYPE is not set +# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +# 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_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y +CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +# CONFIG_APP_UDHCPD is not set +# CONFIG_APP_DHCPRELAY is not set +# CONFIG_APP_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" +CONFIG_APP_UDHCPC=y +# CONFIG_FEATURE_UDHCPC_ARPING is not set +# CONFIG_FEATURE_UDHCP_PORT is not set +# CONFIG_UDHCP_DEBUG is not set +# CONFIG_FEATURE_UDHCP_RFC3397 is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" +# CONFIG_VCONFIG is not set +CONFIG_WGET=y +# CONFIG_FEATURE_WGET_STATUSBAR is not set +CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +# CONFIG_ZCIP is not set +# CONFIG_TCPSVD is not set +# CONFIG_TUNCTL is not set +# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_UDPSVD is not set + +# +# Print Utilities +# +# CONFIG_LPD is not set +# CONFIG_LPR is not set +# CONFIG_LPQ is not set + +# +# 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 + +# +# Process Utilities +# +CONFIG_FREE=y +# CONFIG_FUSER is not set +CONFIG_KILL=y +CONFIG_KILLALL=y +# 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_PKILL is not set +CONFIG_PS=y +CONFIG_FEATURE_PS_WIDE=y +# CONFIG_FEATURE_PS_TIME 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_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_UPTIME=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +# CONFIG_RUNSV is not set +# CONFIG_RUNSVDIR is not set +# 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_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_MSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y + +# +# Ash Shell Options +# +CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_READ_NCHARS is not set +# CONFIG_ASH_READ_TIMEOUT is not set +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_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_HUSH is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE 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_LASH is not set +# CONFIG_MSH is not set + +# +# Bourne Shell Options +# +CONFIG_SH_MATH_SUPPORT=y +# CONFIG_SH_MATH_SUPPORT_64 is not set +# 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_FEATURE_SYSLOGD_DUP is not set +# 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_LOGGER=y diff --git a/release/src/router/busybox/AUTHORS b/release/src/router/busybox/AUTHORS index 9755ad9dda..378c33295f 100644 --- a/release/src/router/busybox/AUTHORS +++ b/release/src/router/busybox/AUTHORS @@ -166,7 +166,7 @@ Paul Fox Roberto A. Foglietta port: dnsd -Bernhard Fischer +Bernhard Reutner-Fischer misc Mike Frysinger diff --git a/release/src/router/busybox/Config.in b/release/src/router/busybox/Config.in index c2005c78a8..fff6d83d58 100644 --- a/release/src/router/busybox/Config.in +++ b/release/src/router/busybox/Config.in @@ -155,15 +155,17 @@ config FEATURE_SUID default n help With this option you can install the busybox binary belonging - to root with the suid bit set, and it'll and it'll automatically drop + to root with the suid bit set, and it will automatically drop priviledges for applets that don't need root access. - If you're really paranoid and don't want to do this, build two + If you are really paranoid and don't want to do this, build two busybox binaries with different applets in them (and the appropriate symlinks pointing to each binary), and only set the suid bit on the one that needs it. The applets currently marked to need the suid bit - are login, passwd, su, ping, traceroute, crontab, dnsd, ipcrm, ipcs, - and vlock. + are: + + crontab, dnsd, findfs, ipcrm, ipcs, login, passwd, ping, su, + traceroute, vlock. config FEATURE_SUID_CONFIG bool "Runtime SUID/SGID configuration via /etc/busybox.conf" @@ -254,18 +256,18 @@ config BUSYBOX_EXEC_PATH # These are auto-selected by other options config FEATURE_SYSLOG - bool "Support for logging to syslog" + bool #No description makes it a hidden option default n - help - This option is auto-selected when you select any applet which may - send its output to syslog. You do not need to select it manually. + #help + # This option is auto-selected when you select any applet which may + # send its output to syslog. You do not need to select it manually. config FEATURE_HAVE_RPC - bool "RPC support" + bool #No description makes it a hidden option default n - help - This is automatically selected if any of enabled applets need it. - You do not need to select it manually. + #help + # This is automatically selected if any of enabled applets need it. + # You do not need to select it manually. endmenu @@ -402,9 +404,18 @@ config CROSS_COMPILER_PREFIX help If you want to build BusyBox with a cross compiler, then you will need to set this to the cross-compiler prefix, for example, - "i386-uclibc-". Note that CROSS_COMPILE environment variable - or "make CROSS_COMPILE=xxx ..." will override this selection. - For native build leave it empty. + "i386-uclibc-". + + Note that CROSS_COMPILE environment variable or + "make CROSS_COMPILE=xxx ..." will override this selection. + + Native builds leave this empty. + +config EXTRA_CFLAGS + string "Additional CFLAGS" + default "" + help + Additional CFLAGS to pass to the compiler verbatim. endmenu @@ -491,8 +502,8 @@ config INCLUDE_SUSv2 will be supported in head, tail, and fold. (Note: should affect renice too.) -config PARSE - bool "Uniform config file parser debugging applet: parse" +### config PARSE +### bool "Uniform config file parser debugging applet: parse" endmenu @@ -590,9 +601,10 @@ source modutils/Config.in source util-linux/Config.in source miscutils/Config.in source networking/Config.in +source printutils/Config.in +source mailutils/Config.in source procps/Config.in -source shell/Config.in -source sysklogd/Config.in source runit/Config.in source selinux/Config.in -source printutils/Config.in +source shell/Config.in +source sysklogd/Config.in diff --git a/release/src/router/busybox/Makefile b/release/src/router/busybox/Makefile index 1bfb270829..0d6e17d04c 100644 --- a/release/src/router/busybox/Makefile +++ b/release/src/router/busybox/Makefile @@ -1,6 +1,6 @@ VERSION = 1 -PATCHLEVEL = 12 -SUBLEVEL = 3 +PATCHLEVEL = 14 +SUBLEVEL = 0 EXTRAVERSION = NAME = Unnamed @@ -168,6 +168,7 @@ ifeq ($(CROSS_COMPILE),) CROSS_COMPILE := $(shell grep ^CONFIG_CROSS_COMPILER_PREFIX .config 2>/dev/null) CROSS_COMPILE := $(subst CONFIG_CROSS_COMPILER_PREFIX=,,$(CROSS_COMPILE)) CROSS_COMPILE := $(subst ",,$(CROSS_COMPILE)) +#") endif # SUBARCH tells the usermode build what the underlying arch is. That is set @@ -456,6 +457,7 @@ libs-y := \ libbb/ \ libpwdgrp/ \ loginutils/ \ + mailutils/ \ miscutils/ \ modutils/ \ networking/ \ @@ -505,7 +507,7 @@ endif # command line. # This allow a user to issue only 'make' to build a kernel including modules # Defaults busybox but it is usually overridden in the arch makefile -all: busybox +all: busybox doc -include $(srctree)/arch/$(ARCH)/Makefile @@ -966,6 +968,12 @@ clean: archclean $(clean-dirs) -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ -type f -print | xargs rm -f +PHONY += doc-clean +doc-clean: rm-files := docs/busybox.pod \ + docs/BusyBox.html docs/BusyBox.1 docs/BusyBox.txt +doc-clean: + $(call cmd,rmfiles) + # mrproper - Delete all generated files, including .config # mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) diff --git a/release/src/router/busybox/Makefile.custom b/release/src/router/busybox/Makefile.custom index 58a979e112..d9a2367ab3 100644 --- a/release/src/router/busybox/Makefile.custom +++ b/release/src/router/busybox/Makefile.custom @@ -105,6 +105,12 @@ bigdata: busybox_unstripped .PHONY: doc doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html +# FIXME: Doesn't belong here + cmd_doc = + quiet_cmd_doc = $(Q)echo " DOC $(@F)" +silent_cmd_doc = +disp_doc = $($(quiet)cmd_doc) + docs/busybox.pod: $(srctree)/docs/busybox_header.pod \ $(srctree)/include/usage.h \ $(srctree)/docs/busybox_footer.pod \ diff --git a/release/src/router/busybox/Makefile.flags b/release/src/router/busybox/Makefile.flags index e31480204e..2109fdf11c 100644 --- a/release/src/router/busybox/Makefile.flags +++ b/release/src/router/busybox/Makefile.flags @@ -23,6 +23,7 @@ CFLAGS += $(call cc-option,-Wwrite-strings,) CFLAGS += $(call cc-option,-Wundef,) CFLAGS += $(call cc-option,-Wstrict-prototypes,) CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,) +CFLAGS += $(call cc-option,-Wunused-function -Wunused-value,) CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,) # warn about C99 declaration after statement CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) @@ -81,6 +82,11 @@ CFLAGS_busybox += $(ARCH_PIE) CFLAGS += $(ARCH_FPIE) endif +ifneq ($(CONFIG_EXTRA_CFLAGS),) +CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS))) +#")) +endif + LDLIBS += m crypt ifeq ($(CONFIG_PAM),y) @@ -99,12 +105,12 @@ ifeq ($(CONFIG_DMALLOC),y) LDLIBS += dmalloc endif -# If a flat binary should be built, CFLAGS_busybox="-Wl,-elf2flt" +# If a flat binary should be built, CFLAGS_busybox="-elf2flt" # env var should be set for make invocation. # Here we check whether CFLAGS_busybox indeed contains that flag. # (For historical reasons, we also check LDFLAGS, which doesn't -# seem to be entirely correct variable to put "-Wl,-elf2flt" into). -W_ELF2FLT = -Wl,-elf2flt +# seem to be entirely correct variable to put "-elf2flt" into). +W_ELF2FLT = -elf2flt ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) SKIP_STRIP = y endif diff --git a/release/src/router/busybox/Makefile.help b/release/src/router/busybox/Makefile.help index f957403652..999d0298e5 100644 --- a/release/src/router/busybox/Makefile.help +++ b/release/src/router/busybox/Makefile.help @@ -6,6 +6,7 @@ help: @echo 'Cleaning:' @echo ' clean - delete temporary files created by build' @echo ' distclean - delete all non-source files (including .config)' + @echo ' doc-clean - delete all generated documentation' @echo @echo 'Build:' @echo ' all - Executable and documentation' diff --git a/release/src/router/busybox/README b/release/src/router/busybox/README index 57407b5504..40490449e3 100644 --- a/release/src/router/busybox/README +++ b/release/src/router/busybox/README @@ -78,7 +78,7 @@ Downloading the current source code: http://busybox.net/developer.html The developers also have a bug and patch tracking system - (http://bugs.busybox.net) although posting a bug/patch to the mailing list + (https://bugs.busybox.net) although posting a bug/patch to the mailing list is generally a faster way of getting it fixed, and the complete archive of what happened is the subversion changelog. diff --git a/release/src/router/busybox/TODO b/release/src/router/busybox/TODO index 133fd4bedc..d6a60d1dd2 100644 --- a/release/src/router/busybox/TODO +++ b/release/src/router/busybox/TODO @@ -23,7 +23,7 @@ Rob Landley suggested these: lash is phased out. hush can be configured down to be nearly as small, but less buggy :) init - General cleanup (should use ENABLE_FEATURE_INIT_SYSLOG and ENABLE_FEATURE_INIT_DEBUG). + General cleanup (should use ENABLE_FEATURE_INIT_SYSLOG). Do a SUSv3 audit Look at the full Single Unix Specification version 3 (available online at "http://www.opengroup.org/onlinepubs/009695399/nfindex.html") and @@ -99,15 +99,10 @@ Rob Landley suggested these: This one's open to everybody, but I'll wind up doing it... -Bernhard Fischer suggests to look at these: +Bernhard Reutner-Fischer suggests to look at these: New debug options: -Wlarger-than-127 Cleanup any big users - -Wunused-parameter - Facilitate applet PROTOTYPES to provide means for having applets that - do a) not take any arguments b) need only one of argc or argv c) need - both argc and argv. All of these three options should go for the most - feature complete denominator. Collate BUFSIZ IOBUF_SIZE MY_BUF_SIZE PIPE_PROGRESS_SIZE BUFSIZE PIPESIZE make bb_common_bufsiz1 configurable, size wise. make pipesize configurable, size wise. @@ -132,14 +127,6 @@ patch And while we're at it, a new patch filename quoting format is apparently coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 --- -man - It would be nice to have a man command. Not one that handles troff or - anything, just one that can handle preformatted ascii man pages, possibly - compressed. This could probably be a script in the extras directory that - calls cat/zcat/bzcat | less - - (How doclifter might work into this is anybody's guess.) ---- ar Write support! --- @@ -183,8 +170,7 @@ Unify archivers --- Text buffer support. Several existing applets (sort, vi, less...) read - a whole file into memory and act on it. There might be an opportunity - for shared code in there that could be moved into libbb... + a whole file into memory and act on it. Use open_read_close(). --- Memory Allocation We have a CONFIG_BUFFER mechanism that lets us select whether to do memory @@ -236,7 +222,7 @@ Switch CONFIG_SYMBOLS to ENABLE_SYMBOLS FEATURE_CLEAN_UP This is more an unresolved issue than a to-do item. More thought is needed. - Normally we rely on exit() to free memory, close files, and unmap segments + Normally we rely on exit() to free memory, close files and unmap segments for us. This makes most calls to free(), close(), and unmap() optional in busybox applets that don't intend to run for very long, and optional stuff can be omitted to save size. @@ -287,6 +273,7 @@ Minor stuff: --- in_ether duplicated in network/{interface,ifconfig}.c --- + unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. Code cleanup: diff --git a/release/src/router/busybox/TODO_config_nommu b/release/src/router/busybox/TODO_config_nommu index 8e13e1fe5e..2061bfd1cd 100644 --- a/release/src/router/busybox/TODO_config_nommu +++ b/release/src/router/busybox/TODO_config_nommu @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.12.0.svn -# Wed Aug 20 00:24:07 2008 +# Busybox version: 1.13.0.svn +# Sun Nov 9 17:09:13 2008 # CONFIG_HAVE_DOT_CONFIG=y @@ -13,8 +13,8 @@ CONFIG_HAVE_DOT_CONFIG=y # General Configuration # CONFIG_DESKTOP=y -# CONFIG_EXTRA_COMPAT is not set -CONFIG_FEATURE_ASSUME_UNICODE=y +CONFIG_EXTRA_COMPAT=y +# CONFIG_FEATURE_ASSUME_UNICODE 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 @@ -58,7 +58,6 @@ CONFIG_NO_DEBUG_LIB=y # CONFIG_DMALLOC is not set # CONFIG_EFENCE is not set CONFIG_INCLUDE_SUSv2=y -# CONFIG_PARSE is not set # # Installation Options @@ -111,6 +110,7 @@ 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 @@ -153,7 +153,7 @@ CONFIG_DD=y CONFIG_FEATURE_DD_SIGNAL_HANDLING=y CONFIG_FEATURE_DD_IBS_OBS=y CONFIG_DF=y -CONFIG_FEATURE_DF_INODE=y +CONFIG_FEATURE_DF_FANCY=y CONFIG_DIRNAME=y CONFIG_DOS2UNIX=y CONFIG_UNIX2DOS=y @@ -283,6 +283,8 @@ 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 @@ -304,7 +306,7 @@ CONFIG_WHICH=y # Editors # CONFIG_AWK=y -CONFIG_FEATURE_AWK_MATH=y +CONFIG_FEATURE_AWK_LIBM=y CONFIG_CMP=y CONFIG_DIFF=y CONFIG_FEATURE_DIFF_BINARY=y @@ -367,7 +369,6 @@ CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y # Init Utilities # CONFIG_INIT=y -# CONFIG_DEBUG_INIT is not set CONFIG_FEATURE_USE_INITTAB=y CONFIG_FEATURE_KILL_REMOVED=y CONFIG_FEATURE_KILL_DELAY=1 @@ -422,35 +423,36 @@ CONFIG_LSATTR=y # # Linux Module Utilities # +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" CONFIG_MODPROBE_SMALL=y CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y -# CONFIG_DEPMOD is not set -# CONFIG_FEATURE_DEPMOD_PRUNE_FANCY is not set -# CONFIG_FEATURE_DEPMOD_ALIAS is not set # CONFIG_INSMOD 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_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_MULTIPLE_OPTIONS is not set -# CONFIG_FEATURE_MODPROBE_FANCY_ALIAS is not set # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set -# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# # CONFIG_FEATURE_2_4_MODULES is not set -# CONFIG_FEATURE_2_6_MODULES is not set -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" -# CONFIG_FEATURE_QUERY_MODULE_INTERFACE 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 # # Linux System Utilities # +CONFIG_BLKID=y CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y CONFIG_FBSET=y @@ -555,15 +557,17 @@ CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y CONFIG_FEATURE_CHAT_CLR_ABORT=y CONFIG_CHRT=y CONFIG_CROND=y -CONFIG_DEBUG_CROND_OPTION=y +CONFIG_FEATURE_CROND_D=y CONFIG_FEATURE_CROND_CALL_SENDMAIL=y 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 @@ -575,9 +579,11 @@ CONFIG_LESS=y CONFIG_FEATURE_LESS_MAXLINES=9999999 CONFIG_FEATURE_LESS_BRACKETS=y CONFIG_FEATURE_LESS_FLAGS=y -CONFIG_FEATURE_LESS_FLAGCS=y +CONFIG_FEATURE_LESS_DASHCMD=y CONFIG_FEATURE_LESS_MARKS=y CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_LINENUMS=y +CONFIG_FEATURE_LESS_WINCH=y CONFIG_HDPARM=y CONFIG_FEATURE_HDPARM_GET_IDENTITY=y CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y @@ -625,11 +631,9 @@ CONFIG_HOSTNAME=y CONFIG_HTTPD=y CONFIG_FEATURE_HTTPD_RANGES=y CONFIG_FEATURE_HTTPD_USE_SENDFILE=y -CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP=y CONFIG_FEATURE_HTTPD_SETUID=y CONFIG_FEATURE_HTTPD_BASIC_AUTH=y CONFIG_FEATURE_HTTPD_AUTH_MD5=y -CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES=y CONFIG_FEATURE_HTTPD_CGI=y CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y @@ -689,8 +693,6 @@ CONFIG_PING6=y CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y -CONFIG_SENDMAIL=y -CONFIG_FETCHMAIL=y CONFIG_SLATTACH=y CONFIG_TELNET=y CONFIG_FEATURE_TELNET_TTYPE=y @@ -702,7 +704,7 @@ CONFIG_TFTPD=y CONFIG_FEATURE_TFTP_GET=y CONFIG_FEATURE_TFTP_PUT=y CONFIG_FEATURE_TFTP_BLOCKSIZE=y -CONFIG_DEBUG_TFTP=y +CONFIG_TFTP_DEBUG=y CONFIG_TRACEROUTE=y CONFIG_FEATURE_TRACEROUTE_VERBOSE=y CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y @@ -715,9 +717,9 @@ CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" CONFIG_APP_UDHCPC=y CONFIG_FEATURE_UDHCPC_ARPING=y CONFIG_FEATURE_UDHCP_PORT=y -CONFIG_FEATURE_UDHCP_DEBUG=y -CONFIG_FEATURE_RFC3397=y -CONFIG_DHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCP_DEBUG=y +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 CONFIG_VCONFIG=y CONFIG_WGET=y @@ -729,6 +731,26 @@ CONFIG_TCPSVD=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 +CONFIG_FEATURE_SENDMAIL_MAILX=y +CONFIG_FEATURE_SENDMAIL_MAILXX=y + +# # Process Utilities # CONFIG_FREE=y @@ -751,18 +773,54 @@ 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_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 is not set +CONFIG_FEATURE_SH_IS_HUSH=y # CONFIG_FEATURE_SH_IS_MSH is not set -CONFIG_FEATURE_SH_IS_NONE=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 @@ -812,42 +870,3 @@ CONFIG_LOGREAD=y CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y CONFIG_KLOGD=y CONFIG_LOGGER=y - -# -# Runit Utilities -# -CONFIG_RUNSV=y -CONFIG_RUNSVDIR=y -CONFIG_SV=y -CONFIG_SVLOGD=y -CONFIG_CHPST=y -CONFIG_SETUIDGID=y -CONFIG_ENVUIDGID=y -CONFIG_ENVDIR=y -CONFIG_SOFTLIMIT=y - -# -# Selinux Utilities -# -CONFIG_CHCON=y -CONFIG_FEATURE_CHCON_LONG_OPTIONS=y -CONFIG_GETENFORCE=y -CONFIG_GETSEBOOL=y -CONFIG_LOAD_POLICY=y -CONFIG_MATCHPATHCON=y -CONFIG_RESTORECON=y -CONFIG_RUNCON=y -CONFIG_FEATURE_RUNCON_LONG_OPTIONS=y -CONFIG_SELINUXENABLED=y -CONFIG_SETENFORCE=y -CONFIG_SETFILES=y -CONFIG_FEATURE_SETFILES_CHECK_OPTION=y -CONFIG_SETSEBOOL=y -CONFIG_SESTATUS=y - -# -# Print Utilities -# -CONFIG_LPD=y -CONFIG_LPR=y -CONFIG_LPQ=y diff --git a/release/src/router/busybox/applets/usage.c b/release/src/router/busybox/applets/usage.c index a35817f9f7..1e038b3672 100644 --- a/release/src/router/busybox/applets/usage.c +++ b/release/src/router/busybox/applets/usage.c @@ -1,4 +1,9 @@ /* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2008 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ #include /* Just #include "autoconf.h" doesn't work for builds in separate diff --git a/release/src/router/busybox/applets/usage_compressed b/release/src/router/busybox/applets/usage_compressed index 05ceafd4a9..c30bcfa29b 100755 --- a/release/src/router/busybox/applets/usage_compressed +++ b/release/src/router/busybox/applets/usage_compressed @@ -17,7 +17,7 @@ echo 'static const char packed_usage[] ALIGN1 = {' ## Breaks on big-endian systems! ## # Extra effort to avoid using "od -t x1": -t is not available ## # in non-CONFIG_DESKTOPed busybox od -## +## ## "$loc/usage" | bzip2 -1 | od -v -x \ ## | $SED -e 's/^[^ ]*//' \ ## | $SED -e 's/ //g' \ diff --git a/release/src/router/busybox/archival/Config.in b/release/src/router/busybox/archival/Config.in index 808757e28f..64b44c218c 100644 --- a/release/src/router/busybox/archival/Config.in +++ b/release/src/router/busybox/archival/Config.in @@ -110,9 +110,17 @@ config FEATURE_CPIO_O This implementation of cpio can create cpio archives in the "newc" format only. +config FEATURE_CPIO_P + bool "Support for passthrough mode" + default n + depends on FEATURE_CPIO_O + help + Passthrough mode. Rarely used. + config DPKG bool "dpkg" default n + select FEATURE_SEAMLESS_GZ help dpkg is a medium-level tool to install, build, remove and manage Debian packages. @@ -123,9 +131,9 @@ config DPKG config DPKG_DEB bool "dpkg_deb" default n + select FEATURE_SEAMLESS_GZ help - dpkg-deb packs, unpacks and provides information about Debian - archives. + dpkg-deb unpacks and provides information about Debian archives. This implementation of dpkg-deb cannot pack archives. diff --git a/release/src/router/busybox/archival/bbunzip.c b/release/src/router/busybox/archival/bbunzip.c index c7962058e2..75489f2a5a 100644 --- a/release/src/router/busybox/archival/bbunzip.c +++ b/release/src/router/busybox/archival/bbunzip.c @@ -30,13 +30,14 @@ int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) int FAST_FUNC bbunpack(char **argv, char* (*make_new_name)(char *filename), - USE_DESKTOP(long long) int (*unpacker)(void) + USE_DESKTOP(long long) int (*unpacker)(unpack_info_t *info) ) { struct stat stat_buf; USE_DESKTOP(long long) int status; char *filename, *new_name; smallint exitcode = 0; + unpack_info_t info; do { /* NB: new_name is *maybe* malloc'ed! */ @@ -92,14 +93,29 @@ int FAST_FUNC bbunpack(char **argv, "use -f to force it"); } - status = unpacker(); + /* memset(&info, 0, sizeof(info)); */ + info.mtime = 0; /* so far it has one member only */ + status = unpacker(&info); if (status < 0) exitcode = 1; if (filename) { char *del = new_name; if (status >= 0) { - /* TODO: restore user/group/times here? */ + /* TODO: restore other things? */ + if (info.mtime) { + struct utimbuf times; + + times.actime = info.mtime; + times.modtime = info.mtime; + /* Close first. + * On some systems calling utime + * then closing resets the mtime. */ + close(STDOUT_FILENO); + /* Ignoring errors */ + utime(new_name, ×); + } + /* Delete _compressed_ file */ del = filename; /* restore extension (unless tgz -> tar case) */ @@ -159,7 +175,7 @@ char* make_new_name_bunzip2(char *filename) } static -USE_DESKTOP(long long) int unpack_bunzip2(void) +USE_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) { return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); } @@ -235,7 +251,7 @@ char* make_new_name_gunzip(char *filename) } static -USE_DESKTOP(long long) int unpack_gunzip(void) +USE_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info) { USE_DESKTOP(long long) int status = -1; @@ -247,7 +263,7 @@ USE_DESKTOP(long long) int unpack_gunzip(void) if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) { status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); } else if (magic2 == 0x8b) { - status = unpack_gz_stream(STDIN_FILENO, STDOUT_FILENO); + status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info); } else { goto bad_magic; } @@ -309,7 +325,7 @@ char* make_new_name_unlzma(char *filename) } static -USE_DESKTOP(long long) int unpack_unlzma(void) +USE_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) { return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); } @@ -344,7 +360,7 @@ char* make_new_name_uncompress(char *filename) } static -USE_DESKTOP(long long) int unpack_uncompress(void) +USE_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM) { USE_DESKTOP(long long) int status = -1; diff --git a/release/src/router/busybox/archival/bzip2.c b/release/src/router/busybox/archival/bzip2.c index 1149cad2a5..8eb5ca9aef 100644 --- a/release/src/router/busybox/archival/bzip2.c +++ b/release/src/router/busybox/archival/bzip2.c @@ -8,6 +8,7 @@ */ #include "libbb.h" +#include "unarchive.h" #define CONFIG_BZIP2_FEATURE_SPEED 1 @@ -101,7 +102,7 @@ USE_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, v } static -USE_DESKTOP(long long) int compressStream(void) +USE_DESKTOP(long long) int compressStream(unpack_info_t *info UNUSED_PARAM) { USE_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 37b6b5ccea..11b22e4781 100644 --- a/release/src/router/busybox/archival/cpio.c +++ b/release/src/router/busybox/archival/cpio.c @@ -14,6 +14,87 @@ #include "libbb.h" #include "unarchive.h" +/* GNU cpio 2.9 --help (abridged): + + Modes: + -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?!] + + Options valid in any mode: + --block-size=SIZE I/O block size = SIZE * 512 bytes + -B I/O block size = 5120 bytes + -c Use the old portable (ASCII) archive format + -C, --io-size=NUMBER I/O block size in bytes + -f, --nonmatching Only copy files that do not match given pattern + -F, --file=FILE Use FILE instead of standard input or output + -H, --format=FORMAT Use given archive FORMAT + -M, --message=STRING Print STRING when the end of a volume of the + backup media is reached + -n, --numeric-uid-gid If -v, show numeric UID and GID + --quiet Do not print the number of blocks copied + --rsh-command=COMMAND Use remote COMMAND instead of rsh + -v, --verbose Verbosely list the files processed + -V, --dot Print a "." for each file processed + -W, --warning=FLAG Control warning display: 'none','truncate','all'; + multiple options accumulate + + Options valid only in --extract mode: + -b, --swap Swap both halfwords of words and bytes of + halfwords in the data (equivalent to -sS) + -r, --rename Interactively rename files + -s, --swap-bytes Swap the bytes of each halfword in the files + -S, --swap-halfwords Swap the halfwords of each word (4 bytes) + --to-stdout Extract files to standard output + -E, --pattern-file=FILE Read additional patterns specifying filenames to + extract or list from FILE + --only-verify-crc Verify CRC's, don't actually extract the files + + Options valid only in --create mode: + -A, --append Append to an existing archive + -O FILE File to use instead of standard output + + Options valid only in --pass-through mode: + -l, --link Link files instead of copying them, when possible + + Options valid in --extract and --create modes: + --absolute-filenames Do not strip file system prefix components from + the file names + --no-absolute-filenames Create all files relative to the current dir + + Options valid in --create and --pass-through modes: + -0, --null A list of filenames is terminated by a NUL + -a, --reset-access-time Reset the access times of files after reading them + -I FILE File to use instead of standard input + -L, --dereference Dereference symbolic links (copy the files + that they point to instead of copying the links) + -R, --owner=[USER][:.][GROUP] Set owner of created files + + Options valid in --extract and --pass-through modes: + -d, --make-directories Create leading directories where needed + -m, --preserve-modification-time Retain mtime when creating files + --no-preserve-owner Do not change the ownership of the files + --sparse Write files with blocks of zeros as sparse files + -u, --unconditional Replace all files unconditionally + */ +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), + CPIO_OPT_CREATE = (1 << 9) * ENABLE_FEATURE_CPIO_O, + CPIO_OPT_FORMAT = (1 << 10) * ENABLE_FEATURE_CPIO_O, + CPIO_OPT_PASSTHROUGH = (1 << 11) * ENABLE_FEATURE_CPIO_P, +}; + +#define OPTION_STR "it0uvdmLF:" + #if ENABLE_FEATURE_CPIO_O static off_t cpio_pad4(off_t size) { @@ -30,6 +111,7 @@ static off_t cpio_pad4(off_t size) * It's ok to exit instead of return. */ static int cpio_o(void) { + static const char trailer[] ALIGN1 = "TRAILER!!!"; struct name_s { struct name_s *next; char name[1]; @@ -48,7 +130,9 @@ static int cpio_o(void) char *line; struct stat st; - line = xmalloc_fgetline(stdin); + line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) + ? bb_get_chunk_from_file(stdin, NULL) + : xmalloc_fgetline(stdin); if (line) { /* Strip leading "./[./]..." from the filename */ @@ -61,7 +145,10 @@ static int cpio_o(void) free(line); continue; } - if (lstat(name, &st)) { + if ((option_mask32 & CPIO_OPT_DEREF) + ? stat(name, &st) + : lstat(name, &st) + ) { abort_cpio_o: bb_simple_perror_msg_and_die(name); } @@ -119,7 +206,7 @@ static int cpio_o(void) } else { /* If no (more) hardlinks to output, * output "trailer" entry */ - name = "TRAILER!!!"; + name = trailer; /* st.st_size == 0 is a must, but for uniformity * in the output, we zero out everything */ memset(&st, 0, sizeof(st)); @@ -167,7 +254,7 @@ static int cpio_o(void) } if (!line) { - if (links) + if (name != trailer) goto next_link; /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */ return EXIT_SUCCESS; @@ -178,71 +265,6 @@ static int cpio_o(void) } #endif -/* GNU cpio 2.9 --help (abridged): - - Modes: - -i, --extract Extract files from an archive - -o, --create Create the archive - -p, --pass-through Copy-pass mode [was ist das?!] - -t, --list List the archive - - Options valid in any mode: - --block-size=SIZE I/O block size = SIZE * 512 bytes - -B I/O block size = 5120 bytes - -c Use the old portable (ASCII) archive format - -C, --io-size=NUMBER I/O block size in bytes - -f, --nonmatching Only copy files that do not match given pattern - -F, --file=FILE Use FILE instead of standard input or output - -H, --format=FORMAT Use given archive FORMAT - -M, --message=STRING Print STRING when the end of a volume of the - backup media is reached - -n, --numeric-uid-gid If -v, show numeric UID and GID - --quiet Do not print the number of blocks copied - --rsh-command=COMMAND Use remote COMMAND instead of rsh - -v, --verbose Verbosely list the files processed - -V, --dot Print a "." for each file processed - -W, --warning=FLAG Control warning display: 'none','truncate','all'; - multiple options accumulate - - Options valid only in --extract mode: - -b, --swap Swap both halfwords of words and bytes of - halfwords in the data (equivalent to -sS) - -r, --rename Interactively rename files - -s, --swap-bytes Swap the bytes of each halfword in the files - -S, --swap-halfwords Swap the halfwords of each word (4 bytes) - --to-stdout Extract files to standard output - -E, --pattern-file=FILE Read additional patterns specifying filenames to - extract or list from FILE - --only-verify-crc Verify CRC's, don't actually extract the files - - Options valid only in --create mode: - -A, --append Append to an existing archive - -O FILE File to use instead of standard output - - Options valid only in --pass-through mode: - -l, --link Link files instead of copying them, when possible - - Options valid in --extract and --create modes: - --absolute-filenames Do not strip file system prefix components from - the file names - --no-absolute-filenames Create all files relative to the current dir - - Options valid in --create and --pass-through modes: - -0, --null A list of filenames is terminated by a NUL - -a, --reset-access-time Reset the access times of files after reading them - -I FILE File to use instead of standard input - -L, --dereference Dereference symbolic links (copy the files - that they point to instead of copying the links) - -R, --owner=[USER][:.][GROUP] Set owner of created files - - Options valid in --extract and --pass-through modes: - -d, --make-directories Create leading directories where needed - -m, --preserve-modification-time Retain mtime when creating files - --no-preserve-owner Do not change the ownership of the files - --sparse Write files with blocks of zeros as sparse files - -u, --unconditional Replace all files unconditionally - */ - int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cpio_main(int argc UNUSED_PARAM, char **argv) { @@ -250,17 +272,6 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) char *cpio_filename; USE_FEATURE_CPIO_O(const char *cpio_fmt = "";) unsigned opt; - enum { - CPIO_OPT_EXTRACT = (1 << 0), - CPIO_OPT_TEST = (1 << 1), - CPIO_OPT_UNCONDITIONAL = (1 << 2), - CPIO_OPT_VERBOSE = (1 << 3), - CPIO_OPT_FILE = (1 << 4), - CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), - CPIO_OPT_PRESERVE_MTIME = (1 << 6), - CPIO_OPT_CREATE = (1 << 7), - CPIO_OPT_FORMAT = (1 << 8), - }; #if ENABLE_GETOPT_LONG applet_long_options = @@ -269,21 +280,67 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_CPIO_O "create\0" No_argument "o" "format\0" Required_argument "H" +#if ENABLE_FEATURE_CPIO_P + "pass-through\0" No_argument "p" +#endif #endif ; #endif - /* Initialize */ - archive_handle = init_handle(); - archive_handle->src_fd = STDIN_FILENO; - archive_handle->seek = seek_by_read; - archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER; + /* As of now we do not enforce this: */ + /* -i,-t,-o,-p are mutually exclusive */ + /* -u,-d,-m make sense only with -i or -p */ + /* -L makes sense only with -o or -p */ -#if ENABLE_FEATURE_CPIO_O - opt = getopt32(argv, "ituvF:dmoH:", &cpio_filename, &cpio_fmt); +#if !ENABLE_FEATURE_CPIO_O + opt = getopt32(argv, OPTION_STR, &cpio_filename); +#else + opt = getopt32(argv, OPTION_STR "oH:" USE_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); + if (opt & CPIO_OPT_PASSTHROUGH) { + pid_t pid; + struct fd_pair pp; + if (argv[optind] == NULL) + bb_show_usage(); + if (opt & CPIO_OPT_CREATE_LEADING_DIR) + mkdir(argv[optind], 0777); + /* Crude existence check: + * close(xopen(argv[optind], O_RDONLY | O_DIRECTORY)); + * We can also xopen, fstat, IS_DIR, later fchdir. + * This would check for existence earlier and cleaner. + * As it stands now, if we fail xchdir later, + * child dies on EPIPE, unless it caught + * a diffrerent problem earlier. + * This is good enough for now. + */ +#if !BB_MMU + pp.rd = 3; + pp.wr = 4; + if (!re_execed) { + close(3); + close(4); + xpiped_pair(pp); + } +#else + xpiped_pair(pp); +#endif + pid = fork_or_rexec(argv); + if (pid == 0) { /* child */ + close(pp.rd); + xmove_fd(pp.wr, STDOUT_FILENO); + goto dump; + } + /* parent */ + xchdir(argv[optind++]); + close(pp.wr); + xmove_fd(pp.rd, STDIN_FILENO); + opt &= ~CPIO_OPT_PASSTHROUGH; + opt |= CPIO_OPT_EXTRACT; + goto skip; + } + /* -o */ if (opt & CPIO_OPT_CREATE) { - if (*cpio_fmt != 'n') + if (*cpio_fmt != 'n') /* we _require_ "-H newc" */ bb_show_usage(); if (opt & CPIO_OPT_FILE) { fclose(stdout); @@ -291,13 +348,18 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* Paranoia: I don't trust libc that much */ xdup2(fileno(stdout), STDOUT_FILENO); } + dump: return cpio_o(); } -#else - opt = getopt32(argv, "ituvF:dm", &cpio_filename); + skip: #endif argv += optind; + archive_handle = init_handle(); + archive_handle->src_fd = STDIN_FILENO; + archive_handle->seek = seek_by_read; + archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER; + /* One of either extract or test options must be given */ if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { bb_show_usage(); @@ -305,9 +367,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) if (opt & CPIO_OPT_TEST) { /* if both extract and test options are given, ignore extract option */ - if (opt & CPIO_OPT_EXTRACT) { - opt &= ~CPIO_OPT_EXTRACT; - } + opt &= ~CPIO_OPT_EXTRACT; archive_handle->action_header = header_list; } if (opt & CPIO_OPT_EXTRACT) { @@ -341,8 +401,13 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) argv++; } + /* see get_header_cpio */ + archive_handle->ah_priv[2] = (void*) ~(ptrdiff_t)0; while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; + if (archive_handle->ah_priv[2] != (void*) ~(ptrdiff_t)0) + printf("%lu blocks\n", (unsigned long)(ptrdiff_t)(archive_handle->ah_priv[2])); + return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/archival/dpkg.c b/release/src/router/busybox/archival/dpkg.c index f31a7f0170..577b77fec6 100644 --- a/release/src/router/busybox/archival/dpkg.c +++ b/release/src/router/busybox/archival/dpkg.c @@ -6,6 +6,10 @@ * written by glenn mcgrath with the help of others * copyright (c) 2001 by glenn mcgrath * + * parts of the version comparison code is plucked from the real dpkg + * application which is licensed GPLv2 and + * copyright (c) 1995 Ian Jackson + * * started life as a busybox implementation of udpkg * * licensed under gplv2 or later, see file license in this tarball for details. @@ -25,6 +29,7 @@ */ #include "libbb.h" +#include #include "unarchive.h" /* note: if you vary hash_prime sizes be aware, @@ -134,7 +139,7 @@ static void make_hash(const char *key, unsigned *start, unsigned *decrement, con /* shifts the ascii based value and adds it to previous value * shift amount is mod 24 because long int is 32 bit and data * to be shifted is 8, don't want to shift data to where it has - * no effect*/ + * no effect */ hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24); } *start = (unsigned) hash_num % hash_prime; @@ -182,60 +187,52 @@ static unsigned search_status_hashtable(const char *key) return probe_address; } -/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ -static int version_compare_part(const char *version1, const char *version2) +static int order(char x) { - int upstream_len1 = 0; - int upstream_len2 = 0; - char *name1_char; - char *name2_char; - int len1 = 0; - int len2 = 0; - int tmp_int; - int ver_num1; - int ver_num2; - - if (version1 == NULL) { - version1 = xstrdup(""); - } - if (version2 == NULL) { - version2 = xstrdup(""); - } - upstream_len1 = strlen(version1); - upstream_len2 = strlen(version2); - - while ((len1 < upstream_len1) || (len2 < upstream_len2)) { - /* Compare non-digit section */ - tmp_int = strcspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strcspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - tmp_int = strcmp(name1_char, name2_char); - free(name1_char); - free(name2_char); - if (tmp_int != 0) { - return tmp_int; + return (x == '~' ? -1 + : x == '\0' ? 0 + : isdigit(x) ? 0 + : isalpha(x) ? x + : (unsigned char)x + 256 + ); +} + +/* This code is taken from dpkg and modified slightly to work with busybox */ +static int version_compare_part(const char *val, const char *ref) +{ + if (!val) val = ""; + if (!ref) ref = ""; + + while (*val || *ref) { + int first_diff; + + while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) { + int vc = order(*val); + int rc = order(*ref); + if (vc != rc) + return vc - rc; + val++; + ref++; } - /* Compare digits */ - tmp_int = strspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - ver_num1 = atoi(name1_char); - ver_num2 = atoi(name2_char); - free(name1_char); - free(name2_char); - if (ver_num1 < ver_num2) { - return -1; + while (*val == '0') + val++; + while (*ref == '0') + ref++; + + first_diff = 0; + while (isdigit(*val) && isdigit(*ref)) { + if (first_diff == 0) + first_diff = *val - *ref; + val++; + ref++; } - if (ver_num1 > ver_num2) { + if (isdigit(*val)) return 1; - } + if (isdigit(*ref)) + return -1; + if (first_diff) + return first_diff; } return 0; } @@ -248,39 +245,34 @@ static int version_compare(const unsigned ver1, const unsigned ver2) { char *ch_ver1 = name_hashtable[ver1]; char *ch_ver2 = name_hashtable[ver2]; - - char epoch1, epoch2; + unsigned long epoch1 = 0, epoch2 = 0; + char *colon; char *deb_ver1, *deb_ver2; - char *ver1_ptr, *ver2_ptr; char *upstream_ver1; char *upstream_ver2; int result; /* Compare epoch */ - if (ch_ver1[1] == ':') { - epoch1 = ch_ver1[0]; - ver1_ptr = strchr(ch_ver1, ':') + 1; - } else { - epoch1 = '0'; - ver1_ptr = ch_ver1; + colon = strchr(ch_ver1, ':'); + if (colon) { + epoch1 = atoi(ch_ver1); + ch_ver1 = colon + 1; } - if (ch_ver2[1] == ':') { - epoch2 = ch_ver2[0]; - ver2_ptr = strchr(ch_ver2, ':') + 1; - } else { - epoch2 = '0'; - ver2_ptr = ch_ver2; + colon = strchr(ch_ver2, ':'); + if (colon) { + epoch2 = atoi(ch_ver2); + ch_ver2 = colon + 1; } if (epoch1 < epoch2) { return -1; } - else if (epoch1 > epoch2) { + if (epoch1 > epoch2) { return 1; } /* Compare upstream version */ - upstream_ver1 = xstrdup(ver1_ptr); - upstream_ver2 = xstrdup(ver2_ptr); + upstream_ver1 = xstrdup(ch_ver1); + upstream_ver2 = xstrdup(ch_ver2); /* Chop off debian version, and store for later use */ deb_ver1 = strrchr(upstream_ver1, '-'); @@ -1293,7 +1285,7 @@ static void free_array(char **array) * the status_hashtable to retrieve the info. This results in smaller code than * scanning the status file. The resulting list, however, is unsorted. */ -static void list_packages(void) +static void list_packages(const char *pattern) { int i; @@ -1314,6 +1306,9 @@ static void list_packages(void) name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; + if (pattern && fnmatch(pattern, name_str, 0)) + continue; + /* get abbreviation for status field 1 */ s1 = stat_str[0] == 'i' ? 'i' : 'r'; @@ -1626,7 +1621,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) /* if the list action was given print the installed packages and exit */ if (opt & OPT_list_installed) { - list_packages(); + list_packages(argv[0]); return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/archival/gzip.c b/release/src/router/busybox/archival/gzip.c index ee051356e5..43804b2e40 100644 --- a/release/src/router/busybox/archival/gzip.c +++ b/release/src/router/busybox/archival/gzip.c @@ -40,6 +40,7 @@ aa: 85.1% -- replaced with aa.gz */ #include "libbb.h" +#include "unarchive.h" /* =========================================================================== @@ -2014,7 +2015,7 @@ char* make_new_name_gzip(char *filename) } static -USE_DESKTOP(long long) int pack_gzip(void) +USE_DESKTOP(long long) int pack_gzip(unpack_info_t *info UNUSED_PARAM) { struct stat s; diff --git a/release/src/router/busybox/archival/libunarchive/data_extract_all.c b/release/src/router/busybox/archival/libunarchive/data_extract_all.c index a67587d72e..8b1ee2a6ea 100644 --- a/release/src/router/busybox/archival/libunarchive/data_extract_all.c +++ b/release/src/router/busybox/archival/libunarchive/data_extract_all.c @@ -77,7 +77,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); - if ((res == -1) && (errno != EISDIR) + if ((res == -1) + && (errno != EISDIR) /* btw, Linux doesn't return this */ + && (errno != EEXIST) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("cannot make dir %s", file_header->name); diff --git a/release/src/router/busybox/archival/libunarchive/decompress_unzip.c b/release/src/router/busybox/archival/libunarchive/decompress_unzip.c index f25808a1a4..86969251e0 100644 --- a/release/src/router/busybox/archival/libunarchive/decompress_unzip.c +++ b/release/src/router/busybox/archival/libunarchive/decompress_unzip.c @@ -1083,8 +1083,7 @@ static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) { uint16_t res; #if BB_LITTLE_ENDIAN - /* gcc 4.2.1 is very clever */ - memcpy(&res, &bytebuffer[bytebuffer_offset], 2); + move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); #else res = bytebuffer[bytebuffer_offset]; res |= bytebuffer[bytebuffer_offset + 1] << 8; @@ -1097,7 +1096,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) { uint32_t res; #if BB_LITTLE_ENDIAN - memcpy(&res, &bytebuffer[bytebuffer_offset], 4); + move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); #else res = bytebuffer[bytebuffer_offset]; res |= bytebuffer[bytebuffer_offset + 1] << 8; @@ -1108,18 +1107,21 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) return res; } -static int check_header_gzip(STATE_PARAM_ONLY) +static int check_header_gzip(STATE_PARAM unpack_info_t *info) { union { unsigned char raw[8]; struct { uint8_t gz_method; uint8_t flags; - //uint32_t mtime; - unused fields - //uint8_t xtra_flags; - //uint8_t os_flags; - } formatted; /* packed */ + uint32_t mtime; + uint8_t xtra_flags_UNUSED; + uint8_t os_flags_UNUSED; + } __attribute__((packed)) formatted; } header; + struct BUG_header { + char BUG_header[sizeof(header) == 8 ? 1 : -1]; + }; /* * Rewind bytebuffer. We use the beginning because the header has 8 @@ -1167,6 +1169,9 @@ static int check_header_gzip(STATE_PARAM_ONLY) } } + if (info) + info->mtime = SWAP_LE32(header.formatted.mtime); + /* Read the header checksum */ if (header.formatted.flags & 0x02) { if (!top_up(PASS_STATE 2)) @@ -1177,7 +1182,7 @@ static int check_header_gzip(STATE_PARAM_ONLY) } USE_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) +unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) { uint32_t v32; USE_DESKTOP(long long) int n; @@ -1192,7 +1197,7 @@ unpack_gz_stream(int in, int out) gunzip_src_fd = in; again: - if (!check_header_gzip(PASS_STATE_ONLY)) { + if (!check_header_gzip(PASS_STATE info)) { bb_error_msg("corrupted data"); n = -1; goto ret; @@ -1239,3 +1244,9 @@ unpack_gz_stream(int in, int out) DEALLOC_STATE; return n; } + +USE_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream(int in, int out) +{ + return unpack_gz_stream_with_info(in, out, NULL); +} diff --git a/release/src/router/busybox/archival/libunarchive/get_header_cpio.c b/release/src/router/busybox/archival/libunarchive/get_header_cpio.c index 93f6c61aa0..302f122331 100644 --- a/release/src/router/busybox/archival/libunarchive/get_header_cpio.c +++ b/release/src/router/busybox/archival/libunarchive/get_header_cpio.c @@ -27,6 +27,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) #define hardlinks_to_create (*(hardlinks_t **)(&archive_handle->ah_priv[0])) #define created_hardlinks (*(hardlinks_t **)(&archive_handle->ah_priv[1])) +#define block_count (archive_handle->ah_priv[2]) // if (!archive_handle->ah_priv_inited) { // archive_handle->ah_priv_inited = 1; // hardlinks_to_create = NULL; @@ -76,7 +77,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) if (strcmp(file_header->name, "TRAILER!!!") == 0) { /* Always round up. ">> 9" divides by 512 */ - printf("%"OFF_FMT"u blocks\n", (archive_handle->offset + 511) >> 9); + block_count = (void*)(ptrdiff_t) ((archive_handle->offset + 511) >> 9); goto create_hardlinks; } diff --git a/release/src/router/busybox/archival/libunarchive/get_header_tar.c b/release/src/router/busybox/archival/libunarchive/get_header_tar.c index bf0f92b258..443052f7e0 100644 --- a/release/src/router/busybox/archival/libunarchive/get_header_tar.c +++ b/release/src/router/busybox/archival/libunarchive/get_header_tar.c @@ -14,6 +14,74 @@ #include "libbb.h" #include "unarchive.h" +/* + * GNU tar uses "base-256 encoding" for very large numbers (>8 billion). + * 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 + * + * We expect it only in size field, where negative numbers don't make sense. + */ +static off_t getBase256_len12(const char *str) +{ + off_t value; + int len; + + /* if (*str & 0x40) error; - caller prevents this */ + + if (sizeof(off_t) >= 12) { + /* Probably 128-bit (16 byte) off_t. Can be optimized. */ + len = 12; + value = *str++ & 0x3f; + while (--len) + value = (value << 8) + (unsigned char) *str++; + return value; + } + +#ifdef CHECK_FOR_OVERFLOW + /* Can be optimized to eat 32-bit chunks */ + char c = *str++ & 0x3f; + len = 12; + while (1) { + if (c) + bb_error_msg_and_die("overflow in base-256 encoded file size"); + if (--len == sizeof(off_t)) + break; + c = *str++; + } +#else + str += (12 - sizeof(off_t)); +#endif + +/* Now str points to sizeof(off_t) least significant bytes. + * + * Example of tar file with 8914993153 (0x213600001) byte file. + * Field starts at offset 7c: + * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| + * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| + * + * str is at offset 80 or 84 now (64-bit or 32-bit off_t). + * We (ab)use the fact that value happens to be aligned, + * and fetch it in one go: + */ + if (sizeof(off_t) == 8) { + value = *(off_t*)str; + value = SWAP_BE64(value); + } else if (sizeof(off_t) == 4) { + value = *(off_t*)str; + value = SWAP_BE32(value); + } else { + value = 0; + len = sizeof(off_t); + while (--len) + value = (value << 8) + (unsigned char) *str++; + } + return value; +} + /* NB: _DESTROYS_ str[len] character! */ static unsigned long long getOctal(char *str, int len) { @@ -91,7 +159,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) again_after_align: -#if ENABLE_DESKTOP +#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT /* to prevent misdetection of bz2 sig */ *(uint32_t*)(&tar) = 0; i = full_read(archive_handle->src_fd, &tar, 512); @@ -142,7 +210,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) #if ENABLE_FEATURE_TAR_AUTODETECT char FAST_FUNC (*get_header_ptr)(archive_handle_t *); - USE_DESKTOP(autodetect:) + autodetect: /* 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(). @@ -234,7 +302,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; #endif file_header->mtime = GET_OCTAL(tar.mtime); - file_header->size = GET_OCTAL(tar.size); + /* Size field: handle GNU tar's "base256 encoding" */ + file_header->size = (*tar.size & 0xc0) == 0x80 /* positive base256? */ + ? getBase256_len12(tar.size) + : GET_OCTAL(tar.size); file_header->gid = GET_OCTAL(tar.gid); file_header->uid = GET_OCTAL(tar.uid); /* Set bits 0-11 of the files mode */ diff --git a/release/src/router/busybox/archival/libunarchive/header_verbose_list.c b/release/src/router/busybox/archival/libunarchive/header_verbose_list.c index f059dd9818..dc31003613 100644 --- a/release/src/router/busybox/archival/libunarchive/header_verbose_list.c +++ b/release/src/router/busybox/archival/libunarchive/header_verbose_list.c @@ -24,11 +24,11 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid); group = gid; } - printf("%s %s/%s %9u %4u-%02u-%02u %02u:%02u:%02u %s", + printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", bb_mode_string(file_header->mode), user, group, - (unsigned int) file_header->size, + file_header->size, 1900 + mtime->tm_year, 1 + mtime->tm_mon, mtime->tm_mday, diff --git a/release/src/router/busybox/archival/rpm.c b/release/src/router/busybox/archival/rpm.c index e1f3c89305..4c36067c4d 100644 --- a/release/src/router/busybox/archival/rpm.c +++ b/release/src/router/busybox/archival/rpm.c @@ -115,8 +115,8 @@ int rpm_main(int argc, char **argv) } } argv += optind; - argc -= optind; - if (!argc) bb_show_usage(); + //argc -= optind; + if (!argv[0]) bb_show_usage(); while (*argv) { rpm_fd = xopen(*argv++, O_RDONLY); @@ -202,7 +202,12 @@ static void extract_cpio_gz(int fd) archive_handle->seek = seek_by_read; //archive_handle->action_header = header_list; archive_handle->action_data = data_extract_all; - archive_handle->ah_flags = ARCHIVE_PRESERVE_DATE | ARCHIVE_CREATE_LEADING_DIRS; + archive_handle->ah_flags = ARCHIVE_PRESERVE_DATE | ARCHIVE_CREATE_LEADING_DIRS + /* compat: overwrite existing files. + * try "rpm -i foo.src.rpm" few times in a row - + * standard rpm will not complain. + * (TODO? real rpm creates "file;1234" and then renames it) */ + | ARCHIVE_EXTRACT_UNCONDITIONAL; archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ @@ -246,7 +251,7 @@ static void extract_cpio_gz(int fd) static rpm_index **rpm_gettags(int fd, int *num_tags) { /* We should never need mode than 200, and realloc later */ - rpm_index **tags = xzalloc(200 * sizeof(struct rpmtag *)); + rpm_index **tags = xzalloc(200 * sizeof(tags[0])); int pass, tagindex = 0; xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ @@ -260,6 +265,9 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) uint32_t entries; /* Number of entries in header (4 bytes) */ uint32_t size; /* Size of store (4 bytes) */ } header; + struct BUG_header { + char BUG_header[sizeof(header) == 16 ? 1 : -1]; + }; rpm_index *tmpindex; int storepos; @@ -273,8 +281,8 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16; while (header.entries--) { - tmpindex = tags[tagindex++] = xmalloc(sizeof(rpm_index)); - xread(fd, tmpindex, sizeof(rpm_index)); + tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); + xread(fd, tmpindex, sizeof(*tmpindex)); tmpindex->tag = ntohl(tmpindex->tag); tmpindex->type = ntohl(tmpindex->type); tmpindex->count = ntohl(tmpindex->count); @@ -287,7 +295,7 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) if (pass == 0) xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); } - tags = xrealloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */ + tags = xrealloc(tags, tagindex * sizeof(tags[0])); /* realloc tags to save space */ *num_tags = tagindex; return tags; /* All done, leave the file at the start of the gzipped cpio archive */ } @@ -378,9 +386,11 @@ static void fileaction_dobackup(char *filename, int fileref) static void fileaction_setowngrp(char *filename, int fileref) { - int uid, gid; - uid = xuname2uid(rpm_getstr(TAG_FILEUSERNAME, fileref)); - gid = xgroup2gid(rpm_getstr(TAG_FILEGROUPNAME, fileref)); + /* real rpm warns: "user foo does not exist - using " */ + struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref)); + int uid = pw ? pw->pw_uid : getuid(); /* or euid? */ + struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref)); + int gid = gr ? gr->gr_gid : getgid(); chown(filename, uid, gid); } diff --git a/release/src/router/busybox/archival/tar.c b/release/src/router/busybox/archival/tar.c index 45701c9850..eeaf3586bf 100644 --- a/release/src/router/busybox/archival/tar.c +++ b/release/src/router/busybox/archival/tar.c @@ -357,7 +357,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, if (tbInfo->verboseFlag) { FILE *vbFd = stdout; - if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ + /* If archive goes to stdout, verbose goes to stderr */ + if (tbInfo->tarFd == STDOUT_FILENO) vbFd = stderr; /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ /* We don't have such excesses here: for us "v" == "vv" */ @@ -591,8 +592,6 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; - - fchmod(tar_fd, 0644); tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; @@ -818,6 +817,10 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; + /* Apparently only root's tar preserves perms (see bug 3844) */ + if (getuid() != 0) + tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM; + /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v diff --git a/release/src/router/busybox/archival/unzip.c b/release/src/router/busybox/archival/unzip.c index 1c9bc246c7..7b47a8ab8c 100644 --- a/release/src/router/busybox/archival/unzip.c +++ b/release/src/router/busybox/archival/unzip.c @@ -16,12 +16,7 @@ */ /* TODO - * Endian issues * Zip64 + other methods - * Improve handling of zip format, ie. - * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3) - * - unix file permissions, etc. - * - central directory */ #include "libbb.h" @@ -31,12 +26,12 @@ enum { #if BB_BIG_ENDIAN ZIP_FILEHEADER_MAGIC = 0x504b0304, ZIP_CDS_MAGIC = 0x504b0102, - ZIP_CDS_END_MAGIC = 0x504b0506, + ZIP_CDE_MAGIC = 0x504b0506, ZIP_DD_MAGIC = 0x504b0708, #else ZIP_FILEHEADER_MAGIC = 0x04034b50, ZIP_CDS_MAGIC = 0x02014b50, - ZIP_CDS_END_MAGIC = 0x06054b50, + ZIP_CDE_MAGIC = 0x06054b50, ZIP_DD_MAGIC = 0x08074b50, #endif }; @@ -46,16 +41,16 @@ enum { typedef union { uint8_t raw[ZIP_HEADER_LEN]; struct { - uint16_t version; /* 0-1 */ - uint16_t flags; /* 2-3 */ - uint16_t method; /* 4-5 */ - uint16_t modtime; /* 6-7 */ - uint16_t moddate; /* 8-9 */ - uint32_t crc32 PACKED; /* 10-13 */ - uint32_t cmpsize PACKED; /* 14-17 */ - uint32_t ucmpsize PACKED; /* 18-21 */ - uint16_t filename_len; /* 22-23 */ - uint16_t extra_len; /* 24-25 */ + uint16_t version; /* 0-1 */ + uint16_t flags; /* 2-3 */ + uint16_t method; /* 4-5 */ + uint16_t modtime; /* 6-7 */ + uint16_t moddate; /* 8-9 */ + uint32_t crc32 PACKED; /* 10-13 */ + uint32_t cmpsize PACKED; /* 14-17 */ + uint32_t ucmpsize PACKED; /* 18-21 */ + uint16_t filename_len; /* 22-23 */ + uint16_t extra_len; /* 24-25 */ } formatted PACKED; } zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ @@ -65,11 +60,11 @@ typedef union { */ struct BUG_zip_header_must_be_26_bytes { char BUG_zip_header_must_be_26_bytes[ - offsetof(zip_header_t, formatted.extra_len) + 2 == - ZIP_HEADER_LEN ? 1 : -1]; + offsetof(zip_header_t, formatted.extra_len) + 2 + == ZIP_HEADER_LEN ? 1 : -1]; }; -#define FIX_ENDIANNESS(zip_header) do { \ +#define FIX_ENDIANNESS_ZIP(zip_header) do { \ (zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \ (zip_header).formatted.flags = SWAP_LE16((zip_header).formatted.flags ); \ (zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \ @@ -82,9 +77,138 @@ struct BUG_zip_header_must_be_26_bytes { (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ } while (0) -static void unzip_skip(int fd, off_t skip) +#define CDS_HEADER_LEN 42 + +typedef union { + uint8_t raw[CDS_HEADER_LEN]; + struct { + /* uint32_t signature; 50 4b 01 02 */ + uint16_t version_made_by; /* 0-1 */ + uint16_t version_needed; /* 2-3 */ + uint16_t cds_flags; /* 4-5 */ + uint16_t method; /* 6-7 */ + uint16_t mtime; /* 8-9 */ + uint16_t mdate; /* 10-11 */ + uint32_t crc32; /* 12-15 */ + uint32_t cmpsize; /* 16-19 */ + uint32_t ucmpsize; /* 20-23 */ + uint16_t file_name_length; /* 24-25 */ + uint16_t extra_field_length; /* 26-27 */ + uint16_t file_comment_length; /* 28-29 */ + uint16_t disk_number_start; /* 30-31 */ + uint16_t internal_file_attributes; /* 32-33 */ + uint32_t external_file_attributes PACKED; /* 34-37 */ + uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ + } formatted PACKED; +} cds_header_t; + +struct BUG_cds_header_must_be_42_bytes { + char BUG_cds_header_must_be_42_bytes[ + offsetof(cds_header_t, formatted.relative_offset_of_local_header) + 4 + == CDS_HEADER_LEN ? 1 : -1]; +}; + +#define FIX_ENDIANNESS_CDS(cds_header) do { \ + (cds_header).formatted.crc32 = SWAP_LE32((cds_header).formatted.crc32 ); \ + (cds_header).formatted.cmpsize = SWAP_LE32((cds_header).formatted.cmpsize ); \ + (cds_header).formatted.ucmpsize = SWAP_LE32((cds_header).formatted.ucmpsize ); \ + (cds_header).formatted.file_name_length = SWAP_LE16((cds_header).formatted.file_name_length); \ + (cds_header).formatted.extra_field_length = SWAP_LE16((cds_header).formatted.extra_field_length); \ + (cds_header).formatted.file_comment_length = SWAP_LE16((cds_header).formatted.file_comment_length); \ +} while (0) + +#define CDE_HEADER_LEN 16 + +typedef union { + uint8_t raw[CDE_HEADER_LEN]; + struct { + /* uint32_t signature; 50 4b 05 06 */ + uint16_t this_disk_no; + uint16_t disk_with_cds_no; + uint16_t cds_entries_on_this_disk; + uint16_t cds_entries_total; + uint32_t cds_size; + uint32_t cds_offset; + /* uint16_t file_comment_length; */ + /* .ZIP file comment (variable size) */ + } formatted PACKED; +} cde_header_t; + +struct BUG_cde_header_must_be_16_bytes { + char BUG_cde_header_must_be_16_bytes[ + sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1]; +}; + +#define FIX_ENDIANNESS_CDE(cde_header) do { \ + (cde_header).formatted.cds_offset = SWAP_LE32((cde_header).formatted.cds_offset); \ +} while (0) + +enum { zip_fd = 3 }; + + +#if ENABLE_DESKTOP +/* NB: does not preserve file position! */ +static uint32_t find_cds_offset(void) +{ + unsigned char buf[1024]; + cde_header_t cde_header; + unsigned char *p; + off_t end; + + end = xlseek(zip_fd, 0, SEEK_END); + if (end < 1024) + end = 1024; + end -= 1024; + xlseek(zip_fd, end, SEEK_SET); + full_read(zip_fd, buf, 1024); + + p = buf; + while (p <= buf + 1024 - CDE_HEADER_LEN - 4) { + if (*p != 'P') { + p++; + continue; + } + if (*++p != 'K') + continue; + if (*++p != 5) + continue; + if (*++p != 6) + continue; + /* we found CDE! */ + memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); + FIX_ENDIANNESS_CDE(cde_header); + return cde_header.formatted.cds_offset; + } + bb_error_msg_and_die("can't find file table"); +}; + +static uint32_t read_next_cds(int count_m1, uint32_t cds_offset, cds_header_t *cds_ptr) { - bb_copyfd_exact_size(fd, -1, skip); + off_t org; + + org = xlseek(zip_fd, 0, SEEK_CUR); + + if (!cds_offset) + cds_offset = find_cds_offset(); + + while (count_m1-- >= 0) { + xlseek(zip_fd, cds_offset + 4, SEEK_SET); + xread(zip_fd, cds_ptr->raw, CDS_HEADER_LEN); + FIX_ENDIANNESS_CDS(*cds_ptr); + cds_offset += 4 + CDS_HEADER_LEN + + cds_ptr->formatted.file_name_length + + cds_ptr->formatted.extra_field_length + + cds_ptr->formatted.file_comment_length; + } + + xlseek(zip_fd, org, SEEK_SET); + return cds_offset; +}; +#endif + +static void unzip_skip(off_t skip) +{ + bb_copyfd_exact_size(zip_fd, -1, skip); } static void unzip_create_leading_dirs(const char *fn) @@ -97,17 +221,17 @@ static void unzip_create_leading_dirs(const char *fn) free(name); } -static void unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd) +static void unzip_extract(zip_header_t *zip_header, int dst_fd) { if (zip_header->formatted.method == 0) { /* Method 0 - stored (not compressed) */ off_t size = zip_header->formatted.ucmpsize; if (size) - bb_copyfd_exact_size(src_fd, dst_fd, size); + 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, src_fd, dst_fd) < 0) + if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { @@ -131,9 +255,12 @@ int unzip_main(int argc, char **argv) smallint verbose = 1; smallint listing = 0; smallint overwrite = O_PROMPT; +#if ENABLE_DESKTOP + uint32_t cds_offset; + unsigned cds_entries; +#endif unsigned total_size; unsigned total_entries; - int src_fd = -1; int dst_fd = -1; char *src_fn = NULL; char *dst_fn = NULL; @@ -221,13 +348,14 @@ int unzip_main(int argc, char **argv) /* Open input file */ if (LONE_DASH(src_fn)) { - src_fd = STDIN_FILENO; + xdup2(STDIN_FILENO, zip_fd); /* Cannot use prompt mode since zip data is arriving on STDIN */ if (overwrite == O_PROMPT) overwrite = O_NEVER; } else { static const char extn[][5] = {"", ".zip", ".ZIP"}; int orig_src_fn_len = strlen(src_fn); + int src_fd = -1; for (i = 0; (i < 3) && (src_fd == -1); i++) { strcpy(src_fn + orig_src_fn_len, extn[i]); @@ -237,6 +365,7 @@ int unzip_main(int argc, char **argv) src_fn[orig_src_fn_len] = '\0'; bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn); } + xmove_fd(src_fd, zip_fd); } /* Change dir if necessary */ @@ -253,37 +382,63 @@ int unzip_main(int argc, char **argv) total_size = 0; total_entries = 0; +#if ENABLE_DESKTOP + cds_entries = 0; + cds_offset = 0; +#endif while (1) { uint32_t magic; /* Check magic number */ - xread(src_fd, &magic, 4); + xread(zip_fd, &magic, 4); /* Central directory? It's at the end, so exit */ if (magic == ZIP_CDS_MAGIC) break; +#if ENABLE_DESKTOP + /* Data descriptor? It was a streaming file, go on */ + if (magic == ZIP_DD_MAGIC) { + /* skip over duplicate crc32, cmpsize and ucmpsize */ + unzip_skip(3 * 4); + continue; + } +#endif if (magic != ZIP_FILEHEADER_MAGIC) bb_error_msg_and_die("invalid zip magic %08X", (int)magic); /* Read the file header */ - xread(src_fd, zip_header.raw, ZIP_HEADER_LEN); - FIX_ENDIANNESS(zip_header); + xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); + FIX_ENDIANNESS_ZIP(zip_header); if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) { bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method); } - if (zip_header.formatted.flags & (0x0008|0x0001)) { +#if !ENABLE_DESKTOP + if (zip_header.formatted.flags & 0x0009) { + bb_error_msg_and_die("zip flags 1 and 8 are not supported"); + } +#else + if (zip_header.formatted.flags & 0x0001) { /* 0x0001 - encrypted */ + bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); + } + if (zip_header.formatted.flags & 0x0008) { + cds_header_t cds_header; /* 0x0008 - streaming. [u]cmpsize can be reliably gotten * only from Central Directory. See unzip_doc.txt */ - bb_error_msg_and_die("zip flags 8 and 1 are not supported"); + cds_offset = read_next_cds(total_entries - cds_entries, cds_offset, &cds_header); + cds_entries = total_entries + 1; + zip_header.formatted.crc32 = cds_header.formatted.crc32; + zip_header.formatted.cmpsize = cds_header.formatted.cmpsize; + zip_header.formatted.ucmpsize = cds_header.formatted.ucmpsize; } +#endif /* Read filename */ free(dst_fn); dst_fn = xzalloc(zip_header.formatted.filename_len + 1); - xread(src_fd, dst_fn, zip_header.formatted.filename_len); + xread(zip_fd, dst_fn, zip_header.formatted.filename_len); /* Skip extra header bytes */ - unzip_skip(src_fd, zip_header.formatted.extra_len); + unzip_skip(zip_header.formatted.extra_len); /* Filter zip entries */ if (find_list_entry(zreject, dst_fn) @@ -304,7 +459,6 @@ int unzip_main(int argc, char **argv) (dostime & 0x000007e0) >> 5, dst_fn); total_size += zip_header.formatted.ucmpsize; - total_entries++; } else { /* short listing -- filenames only */ puts(dst_fn); @@ -315,7 +469,7 @@ int unzip_main(int argc, char **argv) } else if (last_char_is(dst_fn, '/')) { /* Extract directory */ if (stat(dst_fn, &stat_buf) == -1) { if (errno != ENOENT) { - bb_perror_msg_and_die("cannot stat '%s'", dst_fn); + bb_perror_msg_and_die("can't stat '%s'", dst_fn); } if (verbose) { printf(" creating: %s\n", dst_fn); @@ -335,7 +489,7 @@ int unzip_main(int argc, char **argv) check_file: if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */ if (errno != ENOENT) { - bb_perror_msg_and_die("cannot stat '%s'", dst_fn); + bb_perror_msg_and_die("can't stat '%s'", dst_fn); } i = 'y'; } else { /* File already exists */ @@ -347,7 +501,7 @@ int unzip_main(int argc, char **argv) } else { printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); if (!fgets(key_buf, sizeof(key_buf), stdin)) { - bb_perror_msg_and_die("cannot read input"); + bb_perror_msg_and_die("can't read input"); } i = key_buf[0]; } @@ -368,7 +522,7 @@ int unzip_main(int argc, char **argv) if (verbose) { printf(" inflating: %s\n", dst_fn); } - unzip_extract(&zip_header, src_fd, dst_fd); + unzip_extract(&zip_header, dst_fd); if (dst_fd != STDOUT_FILENO) { /* closing STDOUT is potentially bad for future business */ close(dst_fd); @@ -379,14 +533,14 @@ int unzip_main(int argc, char **argv) overwrite = O_NEVER; case 'n': /* Skip entry data */ - unzip_skip(src_fd, zip_header.formatted.cmpsize); + unzip_skip(zip_header.formatted.cmpsize); break; case 'r': /* Prompt for new name */ printf("new name: "); if (!fgets(key_buf, sizeof(key_buf), stdin)) { - bb_perror_msg_and_die("cannot read input"); + bb_perror_msg_and_die("can't read input"); } free(dst_fn); dst_fn = xstrdup(key_buf); @@ -398,12 +552,7 @@ int unzip_main(int argc, char **argv) goto check_file; } -// Looks like bug (data descriptor cannot be identified this way) -// /* Data descriptor section */ -// if (zip_header.formatted.flags & 4) { -// /* skip over duplicate crc, compressed size and uncompressed size */ -// unzip_skip(src_fd, 12); -// } + total_entries++; } if (listing && verbose) { diff --git a/release/src/router/busybox/config_g b/release/src/router/busybox/config_g deleted file mode 100644 index 8fa45da7bb..0000000000 --- a/release/src/router/busybox/config_g +++ /dev/null @@ -1,853 +0,0 @@ -# -# Automatically generated make config: don't edit -# Busybox version: 1.12.2 -# Fri Nov 28 22:55:05 2008 -# -CONFIG_HAVE_DOT_CONFIG=y - -# -# Busybox Settings -# - -# -# General Configuration -# -# CONFIG_DESKTOP is not set -# CONFIG_EXTRA_COMPAT is not set -# CONFIG_FEATURE_ASSUME_UNICODE 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 is not set -# CONFIG_LOCALE_SUPPORT is not set -CONFIG_GETOPT_LONG=y -CONFIG_FEATURE_DEVPTS=y -# CONFIG_FEATURE_CLEAN_UP is not set -CONFIG_FEATURE_PIDFILE=y -CONFIG_FEATURE_SUID=y -# CONFIG_FEATURE_SUID_CONFIG 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_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="mipsel-uclibc-" - -# -# 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 -CONFIG_INCLUDE_SUSv2=y -# CONFIG_PARSE 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_SIZE_VS_SPEED=2 -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 is not set -CONFIG_FEATURE_TAB_COMPLETION=y -# CONFIG_FEATURE_USERNAME_COMPLETION is not set -# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set -# 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 is not set -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_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_FEATURE_CPIO_O is not set -# 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_RPM2CPIO is not set -# CONFIG_RPM is not set -CONFIG_TAR=y -CONFIG_FEATURE_TAR_CREATE=y -# CONFIG_FEATURE_TAR_AUTODETECT is not set -# CONFIG_FEATURE_TAR_FROM is not set -# CONFIG_FEATURE_TAR_OLDGNU_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_UNAME_GNAME is not set -# CONFIG_UNCOMPRESS is not set -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -CONFIG_UNZIP=y - -# -# Coreutils -# -# CONFIG_BASENAME is not set -# CONFIG_CAL is not set -CONFIG_CAT=y -# CONFIG_CATV is not set -# CONFIG_CHGRP is not set -CONFIG_CHMOD=y -# CONFIG_CHOWN is not set -# CONFIG_CHROOT is not set -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set -CONFIG_CP=y -CONFIG_CUT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y -CONFIG_DD=y -CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y -# CONFIG_FEATURE_DF_INODE is not set -# 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_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_FOLD 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 -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 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 -CONFIG_PRINTF=y -CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set -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_SLEEP=y -CONFIG_FEATURE_FANCY_SLEEP=y -# CONFIG_FEATURE_FLOAT_SLEEP is not set -CONFIG_SORT=y -CONFIG_FEATURE_SORT_BIG=y -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set -# CONFIG_STAT is not set -# CONFIG_FEATURE_STAT_FORMAT is not set -# CONFIG_STTY is not set -# CONFIG_SUM is not set -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_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 is not set -# CONFIG_TTY is not set -CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set -# 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_WC=y -CONFIG_FEATURE_WC_LARGE=y -# 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 -# -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set - -# -# Console Utilities -# -# CONFIG_CHVT 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_SETCONSOLE=y -# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set -# CONFIG_SETFONT is not set -# CONFIG_SETKEYCODES is not set -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set - -# -# 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_WHICH=y - -# -# Editors -# -CONFIG_AWK=y -CONFIG_FEATURE_AWK_MATH=y -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_BINARY is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_FEATURE_DIFF_MINIMAL is not set -# CONFIG_ED is not set -# CONFIG_PATCH 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_OPTIMIZE_CURSOR is not set -# CONFIG_FEATURE_ALLOW_EXEC is not set - -# -# Finding Utilities -# -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_EXEC=y -# CONFIG_FEATURE_FIND_USER is not set -# CONFIG_FEATURE_FIND_GROUP is not set -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_CONTEXT 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 - -# -# Init Utilities -# -# CONFIG_INIT is not set -# CONFIG_DEBUG_INIT is not set -# CONFIG_FEATURE_USE_INITTAB is not set -# 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_HALT is not set -# CONFIG_MESG is not set - -# -# Login/Password Management Utilities -# -CONFIG_FEATURE_SHADOWPASSWDS=y -CONFIG_USE_BB_PWD_GRP=y -CONFIG_USE_BB_SHADOW=y -# CONFIG_USE_BB_CRYPT is not set -# CONFIG_ADDGROUP is not set -# CONFIG_FEATURE_ADDUSER_TO_GROUP 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_DELUSER is not set -# CONFIG_GETTY is not set -CONFIG_FEATURE_UTMP=y -# CONFIG_FEATURE_WTMP 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 - -# -# Linux Ext2 FS Progs -# -# CONFIG_CHATTR is not set -# CONFIG_FSCK is not set -# CONFIG_LSATTR is not set - -# -# Linux Module Utilities -# -# 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_DEPMOD is not set -# CONFIG_FEATURE_DEPMOD_PRUNE_FANCY is not set -# CONFIG_FEATURE_DEPMOD_ALIAS is not set -CONFIG_INSMOD=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_RMMOD=y -CONFIG_LSMOD=y -# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -CONFIG_MODPROBE=y -CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS=y -# CONFIG_FEATURE_MODPROBE_FANCY_ALIAS is not set -# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set - -# -# Options common to multiple modutils -# -CONFIG_FEATURE_CHECK_TAINTED_MODULE=y -CONFIG_FEATURE_2_4_MODULES=y -# CONFIG_FEATURE_2_6_MODULES is not set -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" -CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y - -# -# Linux System Utilities -# -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_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_FDISK_ADVANCED is not set -# CONFIG_FINDFS is not set -# CONFIG_FREERAMDISK is not set -# CONFIG_FSCK_MINIX is not set -# CONFIG_MKFS_MINIX is not set -# CONFIG_FEATURE_MINIX2 is not set -# CONFIG_GETOPT 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_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_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_V0 is not set -CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=y -# CONFIG_VOLUMEID is not set -# CONFIG_FEATURE_VOLUMEID_EXT is not set -# CONFIG_FEATURE_VOLUMEID_REISERFS is not set -# 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 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 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=y -# CONFIG_FEATURE_MOUNT_FAKE is not set -# CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -# 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 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_SETARCH is not set -# CONFIG_SWAPONOFF is not set -# 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 is not set -# CONFIG_FEATURE_MTAB_SUPPORT is not set - -# -# Miscellaneous Utilities -# -# CONFIG_ADJTIMEX is not set -# CONFIG_BBCONFIG is not set -# CONFIG_CHAT is not set -# CONFIG_FEATURE_CHAT_NOFAIL is not set -# 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_DEBUG_CROND_OPTION is not set -# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set -# CONFIG_CRONTAB is not set -# CONFIG_DC is not set -# CONFIG_DEVFSD is not set -# CONFIG_DEVFSD_MODLOAD is not set -# CONFIG_DEVFSD_FG_NP is not set -# CONFIG_DEVFSD_VERBOSE is not set -# CONFIG_FEATURE_DEVFS is not set -# CONFIG_EJECT is not set -# CONFIG_FEATURE_EJECT_SCSI is not set -# CONFIG_FBSPLASH is not set -# CONFIG_INOTIFYD is not set -# 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_FLAGCS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP 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_FEATURE_MAKEDEVS_LEAF is not set -# CONFIG_FEATURE_MAKEDEVS_TABLE is not set -# CONFIG_MAN is not set -# CONFIG_MICROCOM is not set -# CONFIG_MOUNTPOINT is not set -# CONFIG_MT is not set -# CONFIG_RAIDAUTORUN is not set -# CONFIG_READAHEAD is not set -# CONFIG_RUNLEVEL is not set -# CONFIG_RX is not set -# CONFIG_SETSID is not set -CONFIG_STRINGS=y -# CONFIG_TASKSET is not set -# CONFIG_FEATURE_TASKSET_FANCY is not set -# CONFIG_TIME is not set -# CONFIG_TTYSIZE is not set -# CONFIG_WATCHDOG is not set - -# -# Networking Utilities -# -# CONFIG_FEATURE_IPV6 is not set -# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set -# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set -CONFIG_ARP=y -CONFIG_ARPING=y -# 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_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_RELOAD_CONFIG_SIGHUP 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_CONFIG_WITH_MIME_TYPES 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_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_HW=y -CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y -# CONFIG_IFENSLAVE 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_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set -# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set -# 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_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_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_FEATURE_IPCALC_LONG_OPTIONS is not set -# CONFIG_NAMEIF is not set -# CONFIG_FEATURE_NAMEIF_EXTENDED is not set -CONFIG_NC=y -# CONFIG_NC_SERVER is not set -CONFIG_NC_EXTRA=y -CONFIG_NETSTAT=y -CONFIG_FEATURE_NETSTAT_WIDE=y -# CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y -CONFIG_PING=y -# CONFIG_PING6 is not set -CONFIG_FEATURE_FANCY_PING=y -CONFIG_PSCAN=y -CONFIG_ROUTE=y -# CONFIG_SENDMAIL is not set -# CONFIG_FETCHMAIL is not set -# CONFIG_SLATTACH is not set -CONFIG_TELNET=y -# CONFIG_FEATURE_TELNET_TTYPE is not set -# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set -CONFIG_TELNETD=y -CONFIG_FEATURE_TELNETD_STANDALONE=y -# 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_DEBUG_TFTP is not set -CONFIG_TRACEROUTE=y -CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_APP_UDHCPD is not set -# CONFIG_APP_DHCPRELAY is not set -# CONFIG_APP_DUMPLEASES is not set -# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set -CONFIG_DHCPD_LEASES_FILE="" -CONFIG_APP_UDHCPC=y -CONFIG_FEATURE_UDHCPC_ARPING=y -# CONFIG_FEATURE_UDHCP_PORT is not set -# CONFIG_FEATURE_UDHCP_DEBUG is not set -CONFIG_FEATURE_RFC3397=y -CONFIG_DHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 -# CONFIG_VCONFIG is not set -CONFIG_WGET=y -# CONFIG_FEATURE_WGET_STATUSBAR is not set -CONFIG_FEATURE_WGET_AUTHENTICATION=y -# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set -# CONFIG_ZCIP is not set -# CONFIG_TCPSVD is not set -# CONFIG_UDPSVD is not set - -# -# Process Utilities -# -CONFIG_FREE=y -# CONFIG_FUSER is not set -CONFIG_KILL=y -CONFIG_KILLALL=y -# 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_PKILL is not set -CONFIG_PS=y -CONFIG_FEATURE_PS_WIDE=y -# CONFIG_FEATURE_PS_TIME 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_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOPMEM is not set -CONFIG_UPTIME=y -CONFIG_WATCH=y - -# -# Shells -# -CONFIG_FEATURE_SH_IS_ASH=y -# CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_MSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set -CONFIG_ASH=y - -# -# Ash Shell Options -# -CONFIG_ASH_BASH_COMPAT=y -# CONFIG_ASH_JOB_CONTROL is not set -# CONFIG_ASH_READ_NCHARS is not set -# CONFIG_ASH_READ_TIMEOUT is not set -CONFIG_ASH_ALIAS=y -CONFIG_ASH_MATH_SUPPORT=y -CONFIG_ASH_MATH_SUPPORT_64=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_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_HUSH is not set -# CONFIG_HUSH_HELP is not set -# CONFIG_HUSH_INTERACTIVE 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_LASH is not set -# CONFIG_MSH is not set - -# -# Bourne Shell Options -# -# 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_FEATURE_SYSLOGD_DUP is not set -# CONFIG_FEATURE_IPC_SYSLOG is not set -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE= -# CONFIG_LOGREAD is not set -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -CONFIG_LOGGER=y - -# -# Runit Utilities -# -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set -# CONFIG_SV is not set -# 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_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 - -# -# Print Utilities -# -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set diff --git a/release/src/router/busybox/console-tools/Config.in b/release/src/router/busybox/console-tools/Config.in index 254e2f7c85..994140b79c 100644 --- a/release/src/router/busybox/console-tools/Config.in +++ b/release/src/router/busybox/console-tools/Config.in @@ -101,6 +101,21 @@ config SETFONT help Allows to load console screen map. Useful for i18n. +config FEATURE_SETFONT_TEXTUAL_MAP + bool "Support reading textual screen maps" + default n + depends on SETFONT + help + Support reading textual screen maps. + +config DEFAULT_SETFONT_DIR + string "Default directory for console-tools files" + default "" + depends on SETFONT + help + Directory to use if setfont's params are simple filenames + (not /path/to/file or ./file). Default is "" (no default directory). + config SETKEYCODES bool "setkeycodes" default n diff --git a/release/src/router/busybox/console-tools/kbd_mode.c b/release/src/router/busybox/console-tools/kbd_mode.c index cb97947ce6..544bbb7894 100644 --- a/release/src/router/busybox/console-tools/kbd_mode.c +++ b/release/src/router/busybox/console-tools/kbd_mode.c @@ -2,37 +2,37 @@ /* * Mini kbd_mode implementation for busybox * - * Copyright (C) 2007 Loïc Grenié + * Copyright (C) 2007 Loic Grenie * written using Andries Brouwer 's kbd_mode from * console-utils v0.2.3, licensed under GNU GPLv2 * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * */ - #include "libbb.h" #include int kbd_mode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int kbd_mode_main(int argc UNUSED_PARAM, char **argv) { - int fd; - unsigned opt; enum { SCANCODE = (1 << 0), ASCII = (1 << 1), MEDIUMRAW = (1 << 2), - UNICODE = (1 << 3) + UNICODE = (1 << 3), }; - static const char KD_xxx[] ALIGN1 = "saku"; - opt = getopt32(argv, KD_xxx); - fd = get_console_fd_or_die(); + int fd; + unsigned opt; + const char *tty_name = CURRENT_TTY; + + opt = getopt32(argv, "sakuC:", &tty_name); + fd = xopen(tty_name, O_NONBLOCK); + opt &= 0xf; /* clear -C bit, see (*) */ if (!opt) { /* print current setting */ const char *mode = "unknown"; int m; - ioctl(fd, KDGKBMODE, &m); + xioctl(fd, KDGKBMODE, &m); if (m == K_RAW) mode = "raw (scancode)"; else if (m == K_XLATE) @@ -43,6 +43,7 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) mode = "Unicode (UTF-8)"; printf("The keyboard is in %s mode\n", mode); } else { + /* here we depend on specific bits assigned to options (*) */ opt = opt & UNICODE ? 3 : opt >> 1; /* double cast prevents warnings about widening conversion */ xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); diff --git a/release/src/router/busybox/console-tools/loadfont.c b/release/src/router/busybox/console-tools/loadfont.c index 78700706f3..336418061a 100644 --- a/release/src/router/busybox/console-tools/loadfont.c +++ b/release/src/router/busybox/console-tools/loadfont.c @@ -6,10 +6,34 @@ * * Loads the console font, and possibly the corresponding screen map(s). * (Adapted for busybox by Matej Vela.) + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" #include +#ifndef KDFONTOP +#define KDFONTOP 0x4B72 +struct console_font_op { + unsigned op; /* KD_FONT_OP_* */ + unsigned flags; /* KD_FONT_FLAG_* */ + unsigned width, height; + unsigned charcount; + unsigned char *data; /* font data with height fixed to 32 */ +}; + +#define KD_FONT_OP_SET 0 /* Set font */ +#define KD_FONT_OP_GET 1 /* Get font */ +#define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, + data points to name / NULL */ +#define KD_FONT_OP_COPY 3 /* Copy from another console */ + +#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ +#define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ + /* (Used internally for PIO_FONT support) */ +#endif /* KDFONTOP */ + + enum { PSF_MAGIC1 = 0x36, PSF_MAGIC2 = 0x04, @@ -17,7 +41,7 @@ enum { PSF_MODE512 = 0x01, PSF_MODEHASTAB = 0x02, PSF_MAXMODE = 0x03, - PSF_SEPARATOR = 0xFFFF + PSF_SEPARATOR = 0xffff }; struct psf_header { @@ -40,6 +64,28 @@ static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize) for (i = 0; i < fontsize; i++) memcpy(buf + (32 * i), inbuf + (unit * i), unit); + { /* KDFONTOP */ + struct console_font_op cfo; + + cfo.op = KD_FONT_OP_SET; + cfo.flags = 0; + cfo.width = 8; + cfo.height = unit; + cfo.charcount = fontsize; + cfo.data = (void*)buf; +#if 0 + if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)")) + goto ret; /* success */ +#else + xioctl(fd, KDFONTOP, &cfo); +#endif + } + +#if 0 +/* These ones do not honour -C tty (they set font on current tty regardless) + * On x86, this distinction is visible on framebuffer consoles + * (regular character consoles may have only one shared font anyway) + */ #if defined(PIO_FONTX) && !defined(__sparc__) { struct consolefontdesc cfd; @@ -49,11 +95,12 @@ static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize) cfd.chardata = buf; if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)")) - goto ret; /* success */ + goto ret; /* success */ } #endif xioctl(fd, PIO_FONT, buf); ret: +#endif /* 0 */ free(buf); } @@ -155,7 +202,7 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) * just read the entire file. */ len = 32*1024; // can't be larger - psfhdr = (struct psf_header *) xmalloc_read(STDIN_FILENO, &len); + psfhdr = xmalloc_read(STDIN_FILENO, &len); // xmalloc_open_zipped_read_close(filename, &len); if (!psfhdr) bb_perror_msg_and_die("error reading input font"); @@ -166,30 +213,159 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) #endif #if ENABLE_SETFONT + +/* +kbd-1.12: + +setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] +[-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console] +[-hNN] [-v] [-V] + +-h NN Override font height +-o file + Save previous font in file +-O file + Save previous font and Unicode map in file +-om file + Store console map in file +-ou file + Save previous Unicode map in file +-m file + Load console map or Unicode console map from file +-u file + Load Unicode table describing the font from file + Example: + # cp866 + 0x00-0x7f idem + # + 0x80 U+0410 # CYRILLIC CAPITAL LETTER A + 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE + 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE +-C console + Set the font for the indicated console +-v Verbose +-V Version +*/ + +#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP +static int ctoi(char *s) +{ + if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0') + return s[1]; + // U+ means 0x + if (s[0] == 'U' && s[1] == '+') { + s[0] = '0'; + s[1] = 'x'; + } + if (!isdigit(s[0])) + return -1; + return xstrtoul(s, 0); +} +#endif + int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int setfont_main(int argc UNUSED_PARAM, char **argv) { size_t len; + unsigned opts; + int fd; struct psf_header *psfhdr; char *mapfilename; - int fd; + const char *tty_name = CURRENT_TTY; opt_complementary = "=1"; - getopt32(argv, "m:", &mapfilename); + opts = getopt32(argv, "m:C:", &mapfilename, &tty_name); argv += optind; + fd = xopen(tty_name, O_NONBLOCK); + + if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not "" + if (*argv[0] != '/') { + // goto default fonts location. don't die if doesn't exist + chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts"); + } + } // load font len = 32*1024; // can't be larger - psfhdr = (struct psf_header *) xmalloc_open_zipped_read_close(*argv, &len); - fd = get_console_fd_or_die(); + psfhdr = xmalloc_open_zipped_read_close(*argv, &len); + if (!psfhdr) + bb_simple_perror_msg_and_die(*argv); do_load(fd, psfhdr, len); // load the screen map, if any - if (option_mask32 & 1) { // -m - void *map = xmalloc_open_zipped_read_close(mapfilename, &len); + if (opts & 1) { // -m + unsigned mode = PIO_SCRNMAP; + void *map; + + if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not "" + if (mapfilename[0] != '/') { + // goto default keymaps location + chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans"); + } + } + // fetch keymap + map = xmalloc_open_zipped_read_close(mapfilename, &len); + if (!map) + bb_simple_perror_msg_and_die(mapfilename); + // file size is 256 or 512 bytes? -> assume binary map if (len == E_TABSZ || len == 2*E_TABSZ) { - xioctl(fd, (len == 2*E_TABSZ) ? PIO_UNISCRNMAP : PIO_SCRNMAP, map); + if (len == 2*E_TABSZ) + mode = PIO_UNISCRNMAP; } +#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP + // assume textual Unicode console maps: + // 0x00 U+0000 # NULL (NUL) + // 0x01 U+0001 # START OF HEADING (SOH) + // 0x02 U+0002 # START OF TEXT (STX) + // 0x03 U+0003 # END OF TEXT (ETX) + else { + int i; + char *token[2]; + parser_t *parser; + + if (ENABLE_FEATURE_CLEAN_UP) + free(map); + map = xmalloc(E_TABSZ * sizeof(unsigned short)); + +#define unicodes ((unsigned short *)map) + // fill vanilla map + for (i = 0; i < E_TABSZ; i++) + unicodes[i] = 0xf000 + i; + + parser = config_open(mapfilename); + while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) { + // parse code/value pair + int a = ctoi(token[0]); + int b = ctoi(token[1]); + if (a < 0 || a >= E_TABSZ + || b < 0 || b > 65535 + ) { + bb_error_msg_and_die("map format"); + } + // patch map + unicodes[a] = b; + // unicode character is met? + if (b > 255) + mode = PIO_UNISCRNMAP; + } + if (ENABLE_FEATURE_CLEAN_UP) + config_close(parser); + + if (mode != PIO_UNISCRNMAP) { +#define asciis ((unsigned char *)map) + for (i = 0; i < E_TABSZ; i++) + asciis[i] = unicodes[i]; +#undef asciis + } +#undef unicodes + } +#endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP + + // do set screen map + xioctl(fd, mode, map); + + if (ENABLE_FEATURE_CLEAN_UP) + free(map); } return EXIT_SUCCESS; diff --git a/release/src/router/busybox/console-tools/loadkmap.c b/release/src/router/busybox/console-tools/loadkmap.c index 56948e0d05..ac2c0a6e00 100644 --- a/release/src/router/busybox/console-tools/loadkmap.c +++ b/release/src/router/busybox/console-tools/loadkmap.c @@ -5,9 +5,7 @@ * Copyright (C) 1998 Enrique Zanardi * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * */ - #include "libbb.h" #define BINARY_KEYMAP_MAGIC "bkeymap" @@ -31,11 +29,15 @@ int loadkmap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) struct kbentry ke; int i, j, fd; uint16_t ibuff[NR_KEYS]; +/* const char *tty_name = CURRENT_TTY; */ RESERVE_CONFIG_BUFFER(flags,MAX_NR_KEYMAPS); -/* bb_warn_ignoring_args(argc>=2);*/ - +/* bb_warn_ignoring_args(argc >= 2); */ fd = get_console_fd_or_die(); +/* or maybe: + opt = getopt32(argv, "C:", &tty_name); + fd = xopen(tty_name, O_NONBLOCK); +*/ xread(STDIN_FILENO, flags, 7); if (strncmp(flags, BINARY_KEYMAP_MAGIC, 7)) diff --git a/release/src/router/busybox/console-tools/resize.c b/release/src/router/busybox/console-tools/resize.c index ea7fe5fcac..4504cc85d6 100644 --- a/release/src/router/busybox/console-tools/resize.c +++ b/release/src/router/busybox/console-tools/resize.c @@ -2,7 +2,7 @@ /* * resize - set terminal width and height. * - * Copyright 2006 Bernhard Fischer + * Copyright 2006 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/console-tools/setconsole.c b/release/src/router/busybox/console-tools/setconsole.c index b685937ae1..8ad9948dd5 100644 --- a/release/src/router/busybox/console-tools/setconsole.c +++ b/release/src/router/busybox/console-tools/setconsole.c @@ -3,7 +3,7 @@ * setconsole.c - redirect system console output * * Copyright (C) 2004,2005 Enrik Berkhan - * Copyright (C) 2008 Bernhard Fischer + * Copyright (C) 2008 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/console-tools/showkey.c b/release/src/router/busybox/console-tools/showkey.c index 95db6e16eb..681114df79 100644 --- a/release/src/router/busybox/console-tools/showkey.c +++ b/release/src/router/busybox/console-tools/showkey.c @@ -72,9 +72,9 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) // 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_RAW ? "RAW" : + (kbmode == K_XLATE ? "XLATE" : + (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?"))) , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress" ); diff --git a/release/src/router/busybox/coreutils/Config.in b/release/src/router/busybox/coreutils/Config.in index 413839035a..b047ce5e29 100644 --- a/release/src/router/busybox/coreutils/Config.in +++ b/release/src/router/busybox/coreutils/Config.in @@ -136,12 +136,12 @@ config DF df reports the amount of disk space used and available on filesystems. -config FEATURE_DF_INODE - bool "Enable -i (inode information)" +config FEATURE_DF_FANCY + bool "Enable -a, -i, -B" default n depends on DF help - This option enables support for df -i. + This option enables -a, -i and -B. config DIRNAME bool "dirname" @@ -189,7 +189,7 @@ config ECHO config FEATURE_FANCY_ECHO bool "Enable echo options (-n and -e)" default y - depends on ECHO + depends on ECHO || ASH_BUILTIN_ECHO || HUSH help This adds options (-n and -e) to echo. @@ -509,6 +509,18 @@ config SHA1SUM help Compute and check SHA1 message digest +config SHA256SUM + bool "sha256sum" + default n + help + Compute and check SHA256 message digest + +config SHA512SUM + bool "sha512sum" + default n + help + Compute and check SHA512 message digest + config SLEEP bool "sleep" default n @@ -649,7 +661,7 @@ config TEST config FEATURE_TEST_64 bool "Extend test to 64 bit" default n - depends on TEST + depends on TEST || ASH_BUILTIN_TEST help Enable 64-bit support in test. @@ -754,7 +766,7 @@ config FEATURE_WC_LARGE default n depends on WC help - Use "unsigned long long" in wc for count variables. + Use "unsigned long long" in wc for counter variables. config WHO bool "who" diff --git a/release/src/router/busybox/coreutils/Kbuild b/release/src/router/busybox/coreutils/Kbuild index a5a2d4c26f..57100a9cf0 100644 --- a/release/src/router/busybox/coreutils/Kbuild +++ b/release/src/router/busybox/coreutils/Kbuild @@ -44,6 +44,7 @@ lib-$(CONFIG_LENGTH) += length.o lib-$(CONFIG_LN) += ln.o lib-$(CONFIG_LOGNAME) += logname.o lib-$(CONFIG_LS) += ls.o +lib-$(CONFIG_FTPD) += ls.o lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o lib-$(CONFIG_MKDIR) += mkdir.o lib-$(CONFIG_MKFIFO) += mkfifo.o @@ -62,6 +63,8 @@ lib-$(CONFIG_RM) += rm.o lib-$(CONFIG_RMDIR) += rmdir.o lib-$(CONFIG_SEQ) += seq.o lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o +lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o +lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o lib-$(CONFIG_SLEEP) += sleep.o lib-$(CONFIG_SPLIT) += split.o lib-$(CONFIG_SORT) += sort.o diff --git a/release/src/router/busybox/coreutils/basename.c b/release/src/router/busybox/coreutils/basename.c index 8a05e92e5f..8a5597e65d 100644 --- a/release/src/router/busybox/coreutils/basename.c +++ b/release/src/router/busybox/coreutils/basename.c @@ -48,5 +48,6 @@ int basename_main(int argc, char **argv) /* puts(s) will do, but we can do without stdio this way: */ s[m++] = '\n'; + /* NB: != is correct here: */ return full_write(STDOUT_FILENO, s, m) != (ssize_t)m; } diff --git a/release/src/router/busybox/coreutils/cksum.c b/release/src/router/busybox/coreutils/cksum.c index 598718486a..3a77c753ac 100644 --- a/release/src/router/busybox/coreutils/cksum.c +++ b/release/src/router/busybox/coreutils/cksum.c @@ -13,8 +13,9 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) { uint32_t *crc32_table = crc32_filltable(NULL, 1); uint32_t crc; - long length, filesize; + off_t length, filesize; int bytes_read; + int exit_code = EXIT_SUCCESS; uint8_t *cp; #if ENABLE_DESKTOP @@ -27,8 +28,10 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) do { int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input); - if (fd < 0) + if (fd < 0) { + exit_code = EXIT_FAILURE; continue; + } crc = 0; length = 0; @@ -44,13 +47,21 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) filesize = length; - for (; length; length >>= 8) - crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ length) & 0xff]; - crc ^= 0xffffffffL; + while (length) { + crc = (crc << 8) ^ crc32_table[(uint8_t)(crc >> 24) ^ (uint8_t)length]; + /* must ensure that shift is unsigned! */ + if (sizeof(length) <= sizeof(unsigned)) + length = (unsigned)length >> 8; + else if (sizeof(length) <= sizeof(unsigned long)) + length = (unsigned long)length >> 8; + else + length = (unsigned long long)length >> 8; + } + crc = ~crc; - printf((*argv ? "%" PRIu32 " %li %s\n" : "%" PRIu32 " %li\n"), + printf((*argv ? "%"PRIu32" %"OFF_FMT"i %s\n" : "%"PRIu32" %"OFF_FMT"i\n"), crc, filesize, *argv); } while (*argv && *++argv); - fflush_stdout_and_exit(EXIT_SUCCESS); + fflush_stdout_and_exit(exit_code); } diff --git a/release/src/router/busybox/coreutils/cp.c b/release/src/router/busybox/coreutils/cp.c index 40d3625b32..71a29396f8 100644 --- a/release/src/router/busybox/coreutils/cp.c +++ b/release/src/router/busybox/coreutils/cp.c @@ -46,7 +46,55 @@ int cp_main(int argc, char **argv) // -R (and therefore -r) turns on -d (coreutils does this) // -a = -pdR opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL"; - flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPH"); + // -v (--verbose) is ignored + flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv"); + /* Options of cp from GNU coreutils 6.10: + * -a, --archive + * -f, --force + * -i, --interactive + * -l, --link + * -L, --dereference + * -P, --no-dereference + * -R, -r, --recursive + * -s, --symbolic-link + * -v, --verbose + * -H follow command-line symbolic links in SOURCE + * -d same as --no-dereference --preserve=links + * -p same as --preserve=mode,ownership,timestamps + * -c same as --preserve=context + * NOT SUPPORTED IN BBOX: + * long options are not supported (even those above). + * --backup[=CONTROL] + * make a backup of each existing destination file + * -b like --backup but does not accept an argument + * --copy-contents + * copy contents of special files when recursive + * --preserve[=ATTR_LIST] + * preserve attributes (default: mode,ownership,timestamps), + * if possible additional attributes: security context,links,all + * --no-preserve=ATTR_LIST + * --parents + * use full source file name under DIRECTORY + * --remove-destination + * remove each existing destination file before attempting to open + * --sparse=WHEN + * control creation of sparse files + * --strip-trailing-slashes + * remove any trailing slashes from each SOURCE argument + * -S, --suffix=SUFFIX + * override the usual backup suffix + * -t, --target-directory=DIRECTORY + * copy all SOURCE arguments into DIRECTORY + * -T, --no-target-directory + * treat DEST as a normal file + * -u, --update + * copy only when the SOURCE file is newer than the destination + * file or when the destination file is missing + * -x, --one-file-system + * stay on this file system + * -Z, --context=CONTEXT + * (SELinux) set SELinux security context of copy to CONTEXT + */ argc -= optind; argv += optind; flags ^= FILEUTILS_DEREFERENCE; /* the sense of this flag was reversed */ diff --git a/release/src/router/busybox/coreutils/cut.c b/release/src/router/busybox/coreutils/cut.c index 3c9fdbda37..9cc22be16e 100644 --- a/release/src/router/busybox/coreutils/cut.c +++ b/release/src/router/busybox/coreutils/cut.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999,2000,2001 by Lineo, inc. * Written by Mark Whitley - * debloated by Bernhard Fischer + * debloated by Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/coreutils/date.c b/release/src/router/busybox/coreutils/date.c index 8469190cf4..177b7d0757 100644 --- a/release/src/router/busybox/coreutils/date.c +++ b/release/src/router/busybox/coreutils/date.c @@ -5,7 +5,7 @@ * by Matthew Grant * * iso-format handling added by Robert Griebl - * bugfixes and cleanup by Bernhard Fischer + * bugfixes and cleanup by Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/coreutils/dd.c b/release/src/router/busybox/coreutils/dd.c index 8a40aa77f8..38dacc71db 100644 --- a/release/src/router/busybox/coreutils/dd.c +++ b/release/src/router/busybox/coreutils/dd.c @@ -8,7 +8,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include /* For FEATURE_DD_SIGNAL_HANDLING */ #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ diff --git a/release/src/router/busybox/coreutils/df.c b/release/src/router/busybox/coreutils/df.c index 9cb328aa31..dfd6e0b419 100644 --- a/release/src/router/busybox/coreutils/df.c +++ b/release/src/router/busybox/coreutils/df.c @@ -8,7 +8,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -/* BB_AUDIT SUSv3 _NOT_ compliant -- options -P and -t missing. Also blocksize. */ +/* BB_AUDIT SUSv3 _NOT_ compliant -- option -t missing. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/df.html */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -16,6 +16,10 @@ * Size reduction. Removed floating point dependency. Added error checking * on output. Output stats on 0-sized filesystems if specifically listed on * the command line. Properly round *-blocks, Used, and Available quantities. + * + * Aug 28, 2008 Bernhard Reutner-Fischer + * + * Implement -P and -B; better coreutils compat; cleanup */ #include @@ -34,51 +38,72 @@ int df_main(int argc, char **argv) { unsigned long blocks_used; unsigned blocks_percent_used; -#if ENABLE_FEATURE_HUMAN_READABLE - unsigned df_disp_hr = 1024; -#endif + unsigned long df_disp_hr = 1024; int status = EXIT_SUCCESS; unsigned opt; FILE *mount_table; struct mntent *mount_entry; struct statfs s; - /* default display is kilobytes */ - const char *disp_units_hdr = "1k-blocks"; + static const char ignored_mounts[] ALIGN1 = "rootfs\0"; enum { - OPT_ALL = (1 << 0), - OPT_INODE = (ENABLE_FEATURE_HUMAN_READABLE ? (1 << 4) : (1 << 2)) - * ENABLE_FEATURE_DF_INODE + OPT_KILO = (1 << 0), + OPT_POSIX = (1 << 1), + OPT_ALL = (1 << 2) * ENABLE_FEATURE_DF_FANCY, + OPT_INODE = (1 << 3) * ENABLE_FEATURE_DF_FANCY, + OPT_BSIZE = (1 << 4) * ENABLE_FEATURE_DF_FANCY, + OPT_HUMAN = (1 << (2 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_MEGA = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, }; + const char *disp_units_hdr = NULL; + char *chp; -#if ENABLE_FEATURE_HUMAN_READABLE - opt_complementary = "h-km:k-hm:m-hk"; - opt = getopt32(argv, "ahmk" USE_FEATURE_DF_INODE("i")); - if (opt & (1 << 1)) { // -h +#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY + opt_complementary = "k-mB:m-Bk:B-km"; +#elif ENABLE_FEATURE_HUMAN_READABLE + opt_complementary = "k-m:m-k"; +#endif + opt = getopt32(argv, "kP" + USE_FEATURE_DF_FANCY("aiB:") + USE_FEATURE_HUMAN_READABLE("hm") + USE_FEATURE_DF_FANCY(, &chp)); + if (opt & OPT_MEGA) + df_disp_hr = 1024*1024; + + if (opt & OPT_BSIZE) + df_disp_hr = xatoul_range(chp, 1, ULONG_MAX); /* disallow 0 */ + + /* From the manpage of df from coreutils-6.10: + Disk space is shown in 1K blocks by default, unless the environment + variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. + */ + if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */ + df_disp_hr = 512; + + if (opt & OPT_HUMAN) { df_disp_hr = 0; disp_units_hdr = " Size"; } - if (opt & (1 << 2)) { // -m - df_disp_hr = 1024*1024; - disp_units_hdr = "1M-blocks"; - } - if (opt & OPT_INODE) { + if (opt & OPT_INODE) disp_units_hdr = " Inodes"; - } + + if (disp_units_hdr == NULL) { +#if ENABLE_FEATURE_HUMAN_READABLE + disp_units_hdr = xasprintf("%s-blocks", + make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX))); #else - opt = getopt32(argv, "ak" USE_FEATURE_DF_INODE("i")); + disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr); #endif - - printf("Filesystem %-15sUsed Available Use%% Mounted on\n", - disp_units_hdr); + } + printf("Filesystem %-15sUsed Available %s Mounted on\n", + disp_units_hdr, (opt & OPT_POSIX) ? "Capacity" : "Use%"); mount_table = NULL; argv += optind; if (optind >= argc) { mount_table = setmntent(bb_path_mtab_file, "r"); - if (!mount_table) { + if (!mount_table) bb_perror_msg_and_die(bb_path_mtab_file); - } } while (1) { @@ -93,13 +118,12 @@ int df_main(int argc, char **argv) } } else { mount_point = *argv++; - if (!mount_point) { + if (!mount_point) break; - } mount_entry = find_mount_point(mount_point, bb_path_mtab_file); if (!mount_entry) { bb_error_msg("%s: can't find mount point", mount_point); - SET_ERROR: + set_error: status = EXIT_FAILURE; continue; } @@ -110,7 +134,7 @@ int df_main(int argc, char **argv) if (statfs(mount_point, &s) != 0) { bb_simple_perror_msg(mount_point); - goto SET_ERROR; + goto set_error; } if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) { @@ -118,10 +142,9 @@ int df_main(int argc, char **argv) s.f_blocks = s.f_files; s.f_bavail = s.f_bfree = s.f_ffree; s.f_bsize = 1; -#if ENABLE_FEATURE_HUMAN_READABLE + if (df_disp_hr) df_disp_hr = 1; -#endif } blocks_used = s.f_blocks - s.f_bfree; blocks_percent_used = 0; @@ -131,11 +154,10 @@ int df_main(int argc, char **argv) ) / (blocks_used + s.f_bavail); } -#ifdef WHY_IT_SHOULD_BE_HIDDEN - if (strcmp(device, "rootfs") == 0) { + /* GNU coreutils 6.10 skip certain mounts, try to be compatible. */ + if (index_in_strings(device, ignored_mounts) != -1) continue; - } -#endif + #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY /* ... and also this is the only user of find_block_device */ if (strcmp(device, "/dev/root") == 0) { @@ -143,7 +165,7 @@ int df_main(int argc, char **argv) * or leaves device alone if it can't find it */ device = find_block_device("/"); if (!device) { - goto SET_ERROR; + goto set_error; } } #endif @@ -164,12 +186,12 @@ int df_main(int argc, char **argv) #else printf(" %9lu %9lu %9lu %3u%% %s\n", kscale(s.f_blocks, s.f_bsize), - kscale(s.f_blocks-s.f_bfree, s.f_bsize), + kscale(s.f_blocks - s.f_bfree, s.f_bsize), kscale(s.f_bavail, s.f_bsize), blocks_percent_used, mount_point); #endif } } - fflush_stdout_and_exit(status); + return status; } diff --git a/release/src/router/busybox/coreutils/du.c b/release/src/router/busybox/coreutils/du.c index efc9bb9fa0..16c7732435 100644 --- a/release/src/router/busybox/coreutils/du.c +++ b/release/src/router/busybox/coreutils/du.c @@ -25,19 +25,28 @@ #include "libbb.h" +enum { + OPT_a_files_too = (1 << 0), + OPT_H_follow_links = (1 << 1), + OPT_k_kbytes = (1 << 2), + OPT_L_follow_links = (1 << 3), + OPT_s_total_norecurse = (1 << 4), + OPT_x_one_FS = (1 << 5), + OPT_d_maxdepth = (1 << 6), + OPT_l_hardlinks = (1 << 7), + OPT_c_total = (1 << 8), + OPT_h_for_humans = (1 << 9), + OPT_m_mbytes = (1 << 10), +}; + struct globals { #if ENABLE_FEATURE_HUMAN_READABLE unsigned long disp_hr; #else unsigned disp_k; #endif - int max_print_depth; - nlink_t count_hardlinks; - bool status; - bool one_file_system; - int print_files; int slink_depth; int du_depth; dev_t dir_dev; @@ -72,7 +81,7 @@ static unsigned long du(const char *filename) return 0; } - if (G.one_file_system) { + if (option_mask32 & OPT_x_one_FS) { if (G.du_depth == 0) { G.dir_dev = statbuf.st_dev; } else if (G.dir_dev != statbuf.st_dev) { @@ -83,7 +92,7 @@ static unsigned long du(const char *filename) sum = statbuf.st_blocks; if (S_ISLNK(statbuf.st_mode)) { - if (G.slink_depth > G.du_depth) { /* -H or -L */ + if (G.slink_depth > G.du_depth) { /* -H or -L */ if (stat(filename, &statbuf) != 0) { bb_simple_perror_msg(filename); G.status = EXIT_FAILURE; @@ -91,12 +100,15 @@ static unsigned long du(const char *filename) } sum = statbuf.st_blocks; if (G.slink_depth == 1) { - G.slink_depth = INT_MAX; /* Convert -H to -L. */ + /* Convert -H to -L */ + G.slink_depth = INT_MAX; } } } - if (statbuf.st_nlink > G.count_hardlinks) { + if (!(option_mask32 & OPT_l_hardlinks) + && statbuf.st_nlink > 1 + ) { /* Add files/directories with links only once */ if (is_in_ino_dev_hashtable(&statbuf)) { return 0; @@ -115,14 +127,8 @@ static unsigned long du(const char *filename) return sum; } - newfile = last_char_is(filename, '/'); - if (newfile) - *newfile = '\0'; - while ((entry = readdir(dir))) { - char *name = entry->d_name; - - newfile = concat_subpath_file(filename, name); + newfile = concat_subpath_file(filename, entry->d_name); if (newfile == NULL) continue; ++G.du_depth; @@ -131,8 +137,9 @@ static unsigned long du(const char *filename) free(newfile); } closedir(dir); - } else if (G.du_depth > G.print_files) { - return sum; + } else { + if (!(option_mask32 & OPT_a_files_too) && G.du_depth != 0) + return sum; } if (G.du_depth <= G.max_print_depth) { print(sum, filename); @@ -145,7 +152,6 @@ int du_main(int argc UNUSED_PARAM, char **argv) { unsigned long total; int slink_depth_save; - bool print_final_total; unsigned opt; #if ENABLE_FEATURE_HUMAN_READABLE @@ -158,7 +164,6 @@ int du_main(int argc UNUSED_PARAM, char **argv) /* SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */ #endif G.max_print_depth = INT_MAX; - G.count_hardlinks = 1; /* Note: SUSv3 specifies that -a and -s options cannot be used together * in strictly conforming applications. However, it also says that some @@ -170,16 +175,13 @@ int du_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s:d+"; opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &G.max_print_depth); argv += optind; - if (opt & (1 << 9)) { - /* -h opt */ + if (opt & OPT_h_for_humans) { G.disp_hr = 0; } - if (opt & (1 << 10)) { - /* -m opt */ + if (opt & OPT_m_mbytes) { G.disp_hr = 1024*1024; } - if (opt & (1 << 2)) { - /* -k opt */ + if (opt & OPT_k_kbytes) { G.disp_hr = 1024; } #else @@ -187,34 +189,20 @@ int du_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "aHkLsx" "d:" "lc", &G.max_print_depth); argv += optind; #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K - if (opt & (1 << 2)) { - /* -k opt */ + if (opt & OPT_k_kbytes) { G.disp_k = 1; } #endif #endif - if (opt & (1 << 0)) { - /* -a opt */ - G.print_files = INT_MAX; - } - if (opt & (1 << 1)) { - /* -H opt */ + if (opt & OPT_H_follow_links) { G.slink_depth = 1; } - if (opt & (1 << 3)) { - /* -L opt */ + if (opt & OPT_L_follow_links) { G.slink_depth = INT_MAX; } - if (opt & (1 << 4)) { - /* -s opt */ + if (opt & OPT_s_total_norecurse) { G.max_print_depth = 0; } - G.one_file_system = opt & (1 << 5); /* -x opt */ - if (opt & (1 << 7)) { - /* -l opt */ - G.count_hardlinks = MAXINT(nlink_t); - } - print_final_total = opt & (1 << 8); /* -c opt */ /* go through remaining args (if any) */ if (!*argv) { @@ -228,12 +216,12 @@ int du_main(int argc UNUSED_PARAM, char **argv) total = 0; do { total += du(*argv); + /* otherwise du /dir /dir won't show /dir twice: */ + reset_ino_dev_hashtable(); G.slink_depth = slink_depth_save; } while (*++argv); - if (ENABLE_FEATURE_CLEAN_UP) - reset_ino_dev_hashtable(); - if (print_final_total) + if (opt & OPT_c_total) print(total, "total"); fflush_stdout_and_exit(G.status); diff --git a/release/src/router/busybox/coreutils/env.c b/release/src/router/busybox/coreutils/env.c index 2f8c8b71d0..f50a03e8b6 100644 --- a/release/src/router/busybox/coreutils/env.c +++ b/release/src/router/busybox/coreutils/env.c @@ -43,8 +43,6 @@ static const char env_longopts[] ALIGN1 = int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int env_main(int argc UNUSED_PARAM, char **argv) { - /* cleanenv was static - why? */ - char *cleanenv[1]; char **ep; unsigned opt; llist_t *unset_env = NULL; @@ -60,12 +58,16 @@ int env_main(int argc UNUSED_PARAM, char **argv) ++argv; } if (opt & 1) { - cleanenv[0] = NULL; - environ = cleanenv; - } else { - while (unset_env) { - unsetenv(llist_pop(&unset_env)); - } + clearenv(); + } + while (unset_env) { + char *var = llist_pop(&unset_env); + /* This does not handle -uVAR=VAL + * (coreutils _sets_ the variable in that case): */ + /*unsetenv(var);*/ + /* This does, but uses somewhan undocumented feature that + * putenv("name_without_equal_sign") unsets the variable: */ + putenv(var); } while (*argv && (strchr(*argv, '=') != NULL)) { diff --git a/release/src/router/busybox/coreutils/expand.c b/release/src/router/busybox/coreutils/expand.c index ee51c032fa..0967e25346 100644 --- a/release/src/router/busybox/coreutils/expand.c +++ b/release/src/router/busybox/coreutils/expand.c @@ -29,98 +29,78 @@ enum { OPT_ALL = 1 << 2, }; -static void xputchar(char c) -{ - if (putchar(c) < 0) - bb_error_msg_and_die(bb_msg_write_error); -} - #if ENABLE_EXPAND -static void expand(FILE *file, unsigned tab_size, unsigned opt) +static void expand(FILE *file, int tab_size, unsigned opt) { char *line; - char *ptr; - int convert; - unsigned pos; - /* Increment tab_size by 1 locally.*/ - tab_size++; + tab_size = -tab_size; while ((line = xmalloc_fgets(file)) != NULL) { - convert = 1; - pos = 0; - ptr = line; - while (*line) { - pos++; - if (*line == '\t' && convert) { - for (; pos < tab_size; pos++) { - xputchar(' '); - } - } else { - if ((opt & OPT_INITIAL) && !isblank(*line)) { - convert = 0; - } - xputchar(*line); + int pos; + unsigned char c; + char *ptr = line; + + goto start; + while ((c = *ptr) != '\0') { + if ((opt & OPT_INITIAL) && !isblank(c)) { + fputs(ptr, stdout); + break; } - if (pos == tab_size) { - pos = 0; + ptr++; + if (c == '\t') { + c = ' '; + while (++pos < 0) + bb_putchar(c); + } + bb_putchar(c); + if (++pos >= 0) { + start: + pos = tab_size; } - line++; } - free(ptr); + free(line); } } #endif #if ENABLE_UNEXPAND -static void unexpand(FILE *file, unsigned int tab_size, unsigned opt) +static void unexpand(FILE *file, unsigned tab_size, unsigned opt) { char *line; - char *ptr; - int convert; - int pos; - int i = 0; - unsigned column = 0; while ((line = xmalloc_fgets(file)) != NULL) { - convert = 1; - pos = 0; - ptr = line; - while (*line) { - while ((*line == ' ' || *line == '\t') && convert) { - pos += (*line == ' ') ? 1 : tab_size; - line++; + char *ptr = line; + unsigned column = 0; + + while (*ptr) { + unsigned n; + + while (*ptr == ' ') { column++; - if ((opt & OPT_ALL) && column == tab_size) { - column = 0; - goto put_tab; - } + ptr++; + } + if (*ptr == '\t') { + column += tab_size - (column % tab_size); + ptr++; + continue; } - if (pos) { - i = pos / tab_size; - if (i) { - for (; i > 0; i--) { - put_tab: - xputchar('\t'); - } - } else { - for (i = pos % tab_size; i > 0; i--) { - xputchar(' '); - } - } - pos = 0; - } else { - if (opt & OPT_INITIAL) { - convert = 0; - } - if (opt & OPT_ALL) { - column++; - } - xputchar(*line); - line++; + + n = column / tab_size; + column = column % tab_size; + while (n--) + putchar('\t'); + + if ((opt & OPT_INITIAL) && ptr != line) { + printf("%*s%s", column, "", ptr); + break; } + n = strcspn(ptr, "\t "); + printf("%*s%.*s", column, "", n, ptr); + ptr += n; + column = (column + n) % tab_size; } - free(ptr); + free(line); } } #endif diff --git a/release/src/router/busybox/coreutils/expr.c b/release/src/router/busybox/coreutils/expr.c index 2f9c5c1e37..54c2ee1655 100644 --- a/release/src/router/busybox/coreutils/expr.c +++ b/release/src/router/busybox/coreutils/expr.c @@ -223,13 +223,13 @@ static VALUE *docolon(VALUE *sv, VALUE *pv) tostring(pv); if (pv->u.s[0] == '^') { - bb_error_msg("\ -warning: unportable BRE: `%s': using `^' as the first character\n\ -of a basic regular expression is not portable; it is being ignored", pv->u.s); + bb_error_msg( +"warning: '%s': using '^' as the first character\n" +"of a basic regular expression is not portable; it is ignored", pv->u.s); } memset(&re_buffer, 0, sizeof(re_buffer)); - memset(re_regs, 0, sizeof(*re_regs)); + memset(re_regs, 0, sizeof(re_regs)); xregcomp(&re_buffer, pv->u.s, 0); /* expr uses an anchored pattern match, so check that there was a @@ -238,7 +238,7 @@ of a basic regular expression is not portable; it is being ignored", pv->u.s); && re_regs[0].rm_so == 0 ) { /* Were \(...\) used? */ - if (re_buffer.re_nsub > 0) { + if (re_buffer.re_nsub > 0 && re_regs[1].rm_so >= 0) { sv->u.s[re_regs[1].rm_eo] = '\0'; v = str_value(sv->u.s + re_regs[1].rm_so); } else { @@ -251,7 +251,7 @@ of a basic regular expression is not portable; it is being ignored", pv->u.s); else v = int_value(0); } -//FIXME: sounds like here is a bit missing: regfree(&re_buffer); + regfree(&re_buffer); return v; } @@ -481,24 +481,21 @@ static VALUE *eval(void) } int expr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int expr_main(int argc, char **argv) +int expr_main(int argc UNUSED_PARAM, char **argv) { VALUE *v; - if (argc == 1) { + xfunc_error_retval = 2; /* coreutils compat */ + G.args = argv + 1; + if (*G.args == NULL) { bb_error_msg_and_die("too few arguments"); } - - G.args = argv + 1; - v = eval(); if (*G.args) bb_error_msg_and_die("syntax error"); - if (v->type == INTEGER) printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); else puts(v->u.s); - fflush_stdout_and_exit(null(v)); } diff --git a/release/src/router/busybox/coreutils/head.c b/release/src/router/busybox/coreutils/head.c index 570f140b1d..ac476d0919 100644 --- a/release/src/router/busybox/coreutils/head.c +++ b/release/src/router/busybox/coreutils/head.c @@ -40,7 +40,6 @@ int head_main(int argc, char **argv) int count_bytes = 0; int header_threshhold = 1; #endif - FILE *fp; const char *fmt; char *p; @@ -50,7 +49,7 @@ int head_main(int argc, char **argv) #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD /* Allow legacy syntax of an initial numeric option without -n. */ - if (argc > 1 && argv[1][0] == '-' + if (argv[1] && argv[1][0] == '-' && isdigit(argv[1][1]) ) { --argc; @@ -79,7 +78,6 @@ int head_main(int argc, char **argv) #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD GET_COUNT: #endif - #if !ENABLE_FEATURE_FANCY_HEAD count = xatoul(p); #else @@ -128,10 +126,12 @@ int head_main(int argc, char **argv) putchar(c); } if (fclose_if_not_stdin(fp)) { - bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */ + bb_simple_perror_msg(*argv); retval = EXIT_FAILURE; } die_if_ferror_stdout(); + } else { + retval = EXIT_FAILURE; } fmt = header_fmt_str; } while (*++argv); diff --git a/release/src/router/busybox/coreutils/id.c b/release/src/router/busybox/coreutils/id.c dissimilarity index 76% index 0fadd98d3e..43f403fa37 100644 --- a/release/src/router/busybox/coreutils/id.c +++ b/release/src/router/busybox/coreutils/id.c @@ -1,126 +1,214 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini id implementation for busybox - * - * Copyright (C) 2000 by Randolph Chung - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -/* BB_AUDIT SUSv3 _NOT_ compliant -- option -G is not currently supported. */ -/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever length and to - * be more similar to GNU id. - * -Z option support: by Yuichi Nakamura - */ - -#include "libbb.h" - -#define PRINT_REAL 1 -#define NAME_NOT_NUMBER 2 -#define JUST_USER 4 -#define JUST_GROUP 8 -#if ENABLE_SELINUX -#define JUST_CONTEXT 16 -#endif - -static int printf_full(unsigned int id, const char *arg, const char prefix) -{ - const char *fmt = "%cid=%u"; - int status = EXIT_FAILURE; - - if (arg) { - fmt = "%cid=%u(%s)"; - status = EXIT_SUCCESS; - } - printf(fmt, prefix, id, arg); - return status; -} - -int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int id_main(int argc UNUSED_PARAM, char **argv) -{ - struct passwd *p; - uid_t uid; - gid_t gid; - unsigned long flags; - short status; -#if ENABLE_SELINUX - security_context_t scontext; -#endif - /* Don't allow -n -r -nr -ug -rug -nug -rnug */ - /* Don't allow more than one username */ - opt_complementary = "?1:u--g:g--u:r?ug:n?ug" USE_SELINUX(":u--Z:Z--u:g--Z:Z--g"); - flags = getopt32(argv, "rnug" USE_SELINUX("Z")); - - /* This values could be overwritten later */ - uid = geteuid(); - gid = getegid(); - if (flags & PRINT_REAL) { - uid = getuid(); - gid = getgid(); - } - - if (argv[optind]) { - p = getpwnam(argv[optind]); - /* xuname2uid is needed because it exits on failure */ - uid = xuname2uid(argv[optind]); - gid = p->pw_gid; - /* in this case PRINT_REAL is the same */ - } - - if (flags & (JUST_GROUP | JUST_USER USE_SELINUX(| JUST_CONTEXT))) { - /* JUST_GROUP and JUST_USER are mutually exclusive */ - if (flags & NAME_NOT_NUMBER) { - /* bb_getXXXid(-1) exit on failure, puts cannot segfault */ - puts((flags & JUST_USER) ? bb_getpwuid(NULL, -1, uid) : bb_getgrgid(NULL, -1, gid)); - } else { - if (flags & JUST_USER) { - printf("%u\n", uid); - } - if (flags & JUST_GROUP) { - printf("%u\n", gid); - } - } - -#if ENABLE_SELINUX - if (flags & JUST_CONTEXT) { - selinux_or_die(); - if (argc - optind == 1) { - bb_error_msg_and_die("user name can't be passed with -Z"); - } - - if (getcon(&scontext)) { - bb_error_msg_and_die("can't get process context"); - } - puts(scontext); - } -#endif - /* exit */ - fflush_stdout_and_exit(EXIT_SUCCESS); - } - - /* Print full info like GNU id */ - /* bb_getpwuid(0) doesn't exit on failure (returns NULL) */ - status = printf_full(uid, bb_getpwuid(NULL, 0, uid), 'u'); - bb_putchar(' '); - status |= printf_full(gid, bb_getgrgid(NULL, 0, gid), 'g'); - -#if ENABLE_SELINUX - if (is_selinux_enabled()) { - security_context_t mysid; - const char *context; - - context = "unknown"; - getcon(&mysid); - if (mysid) { - context = alloca(strlen(mysid) + 1); - strcpy((char*)context, mysid); - freecon(mysid); - } - printf(" context=%s", context); - } -#endif - - bb_putchar('\n'); - fflush_stdout_and_exit(status); -} +/* vi: set sw=4 ts=4: */ +/* + * Mini id implementation for busybox + * + * Copyright (C) 2000 by Randolph Chung + * Copyright (C) 2008 by Tito Ragusa + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +/* BB_AUDIT SUSv3 compliant. */ +/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever + * length and to be more similar to GNU id. + * -Z option support: by Yuichi Nakamura + * Added -G option Tito Ragusa (C) 2008 for SUSv3. + */ + +#include "libbb.h" + +#if !ENABLE_USE_BB_PWD_GRP +#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0) +#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30) +#error "Sorry, you need at least uClibc version 0.9.30 for id applet to build" +#endif +#endif +#endif + +enum { + PRINT_REAL = (1 << 0), + NAME_NOT_NUMBER = (1 << 1), + JUST_USER = (1 << 2), + JUST_GROUP = (1 << 3), + JUST_ALL_GROUPS = (1 << 4), +#if ENABLE_SELINUX + JUST_CONTEXT = (1 << 5), +#endif +}; + +static int print_common(unsigned id, const char *name, const char *prefix) +{ + if (prefix) { + printf("%s", prefix); + } + if (!(option_mask32 & NAME_NOT_NUMBER) || !name) { + printf("%u", id); + } + if (!option_mask32 || (option_mask32 & NAME_NOT_NUMBER)) { + if (name) { + printf(option_mask32 ? "%s" : "(%s)", name); + } else { + /* Don't set error status flag in default mode */ + if (option_mask32) { + if (ENABLE_DESKTOP) + bb_error_msg("unknown ID %u", id); + return EXIT_FAILURE; + } + } + } + return EXIT_SUCCESS; +} + +static int print_group(gid_t id, const char *prefix) +{ + return print_common(id, gid2group(id), prefix); +} + +static int print_user(uid_t id, const char *prefix) +{ + return print_common(id, uid2uname(id), 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) + * Otherwise fill in groups[] and return >= 0 + */ +static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n) +{ + int m; + + if (username) { + /* If the user is a member of more than + * *n groups, then -1 is returned. Otherwise >= 0. + * (and no defined way of detecting errors?!) */ + 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; /* error, don't return < 0! */ + return m; +} + +int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int id_main(int argc UNUSED_PARAM, char **argv) +{ + uid_t ruid; + gid_t rgid; + uid_t euid; + gid_t egid; + unsigned opt; + int i; + int status = EXIT_SUCCESS; + const char *prefix; + const char *username; +#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" + USE_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); + opt = getopt32(argv, "rnugG" USE_SELINUX("Z")); + + username = argv[optind]; + if (username) { + struct passwd *p = xgetpwnam(username); + euid = ruid = p->pw_uid; + egid = rgid = p->pw_gid; + } else { + egid = getegid(); + rgid = getgid(); + euid = geteuid(); + ruid = getuid(); + } + /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */ + /* id says: print the real ID instead of the effective ID, with -ugG */ + /* in fact in this case egid is always printed if egid != rgid */ + if (!opt || (opt & JUST_ALL_GROUPS)) { + gid_t *groups; + int n; + + if (!opt) { + /* Default Mode */ + status |= print_user(ruid, "uid="); + status |= print_group(rgid, " gid="); + if (euid != ruid) + status |= print_user(euid, " euid="); + if (egid != rgid) + status |= print_group(egid, " egid="); + } else { + /* JUST_ALL_GROUPS */ + status |= print_group(rgid, NULL); + if (egid != rgid) + status |= print_group(egid, " "); + } + /* 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)); + n = 64; + if (get_groups(username, rgid, groups, &n) < 0) { + /* Need bigger buffer after all */ + groups = xrealloc(groups, n * sizeof(gid_t)); + get_groups(username, rgid, groups, &n); + } + if (n > 0) { + /* Print the list */ + prefix = " groups="; + for (i = 0; i < n; i++) { + if (opt && (groups[i] == rgid || groups[i] == egid)) + continue; + status |= print_group(groups[i], opt ? " " : prefix); + prefix = ","; + } + } else if (n < 0) { /* error in get_groups() */ + if (!ENABLE_DESKTOP) + bb_error_msg_and_die("cannot get groups"); + else + return EXIT_FAILURE; + } + if (ENABLE_FEATURE_CLEAN_UP) + free(groups); +#if ENABLE_SELINUX + if (is_selinux_enabled()) { + if (getcon(&scontext) == 0) + printf(" context=%s", scontext); + } +#endif + } else if (opt & PRINT_REAL) { + euid = ruid; + egid = rgid; + } + + if (opt & JUST_USER) + status |= print_user(euid, NULL); + else if (opt & JUST_GROUP) + status |= print_group(egid, NULL); +#if ENABLE_SELINUX + else if (opt & JUST_CONTEXT) { + selinux_or_die(); + if (username || getcon(&scontext)) { + bb_error_msg_and_die("can't get process context%s", + username ? " for a different user" : ""); + } + fputs(scontext, stdout); + } + /* freecon(NULL) seems to be harmless */ + if (ENABLE_FEATURE_CLEAN_UP) + freecon(scontext); +#endif + bb_putchar('\n'); + fflush_stdout_and_exit(status); +} diff --git a/release/src/router/busybox/coreutils/id_test.sh b/release/src/router/busybox/coreutils/id_test.sh new file mode 100644 index 0000000000..0d65f2ae31 --- /dev/null +++ b/release/src/router/busybox/coreutils/id_test.sh @@ -0,0 +1,244 @@ +#!/bin/bash +# Test script for busybox id vs. coreutils id. +# Needs root privileges for some tests. + +cp /usr/bin/id . +BUSYBOX=./busybox +ID=./id +LIST=`awk -F: '{ printf "%s\n", $1 }' /etc/passwd` +FLAG_USER_EXISTS="no" +TEST_USER="f583ca884c1d93458fb61ed137ff44f6" + +echo "test 1: id [options] nousername" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar +done + +echo "test 2: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + if test "$i" = "$TEST_USER"; then + FLAG_USER_EXISTS="yes" + fi + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +if test $FLAG_USER_EXISTS = "yes"; then + echo "test 3,4,5,6,7,8,9,10,11,12 skipped because test user $TEST_USER already exists" + rm -f foo bar + exit 1 +fi + +adduser -s /bin/true -g "" -H -D "$TEST_USER" || exit 1 + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod u+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod u+s $ID 2>&1 /dev/null + +echo "test 3 setuid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 4 setuid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod g+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod g+s $ID 2>&1 /dev/null + +echo "test 5 setgid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 6 setgid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod u+s,g+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod u+s,g+s $ID 2>&1 /dev/null + +echo "test 7 setuid, setgid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 8 setuid, setgid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +deluser $TEST_USER || exit 1 + +echo "test 9 setuid, setgid, not existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar +done + +echo "test 10 setuid, setgid, not existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown .root $BUSYBOX 2>&1 /dev/null +chown .root $ID 2>&1 /dev/null +chmod g+s $BUSYBOX 2>&1 /dev/null +chmod g+s $ID 2>&1 /dev/null + +echo "test 11 setgid, not existing group: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 12 setgid, not existing group: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown root.root $BUSYBOX 2>&1 /dev/null +chown root.root $ID 2>&1 /dev/null +rm -f $ID +rm -f foo bar diff --git a/release/src/router/busybox/coreutils/install.c b/release/src/router/busybox/coreutils/install.c index e99f1a3bd6..2b796e2a17 100644 --- a/release/src/router/busybox/coreutils/install.c +++ b/release/src/router/busybox/coreutils/install.c @@ -4,9 +4,6 @@ * SELinux support: by Yuichi Nakamura * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * TODO: -d option, need a way of recursively making directories and changing - * owner/group, will probably modify bb_make_directory(...) */ #include "libbb.h" @@ -53,7 +50,8 @@ static void setdefaultfilecon(const char *path) if (lsetfilecon(path, scontext) < 0) { if (errno != ENOTSUP) { - bb_perror_msg("warning: failed to change context of %s to %s", path, scontext); + bb_perror_msg("warning: failed to change context" + " of %s to %s", path, scontext); } } @@ -75,7 +73,7 @@ int install_main(int argc, char **argv) const char *uid_str; const char *mode_str; int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; - int flags; + int opts; int min_args = 1; int ret = EXIT_SUCCESS; int isdir = 0; @@ -87,15 +85,16 @@ int install_main(int argc, char **argv) OPT_c = 1 << 0, OPT_v = 1 << 1, OPT_b = 1 << 2, - OPT_DIRECTORY = 1 << 3, - OPT_PRESERVE_TIME = 1 << 4, - OPT_STRIP = 1 << 5, - OPT_GROUP = 1 << 6, - OPT_MODE = 1 << 7, - OPT_OWNER = 1 << 8, + OPT_MKDIR_LEADING = 1 << 3, + OPT_DIRECTORY = 1 << 4, + OPT_PRESERVE_TIME = 1 << 5, + OPT_STRIP = 1 << 6, + OPT_GROUP = 1 << 7, + OPT_MODE = 1 << 8, + OPT_OWNER = 1 << 9, #if ENABLE_SELINUX - OPT_SET_SECURITY_CONTEXT = 1 << 9, - OPT_PRESERVE_SECURITY_CONTEXT = 1 << 10, + OPT_SET_SECURITY_CONTEXT = 1 << 10, + OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11, #endif }; @@ -106,37 +105,38 @@ int install_main(int argc, char **argv) /* -c exists for backwards compatibility, it's needed */ /* -v is ignored ("print name of each created directory") */ /* -b is ignored ("make a backup of each existing destination file") */ - flags = getopt32(argv, "cvb" "dpsg:m:o:" USE_SELINUX("Z:"), + opts = getopt32(argv, "cvb" "Ddpsg:m:o:" USE_SELINUX("Z:"), &gid_str, &mode_str, &uid_str USE_SELINUX(, &scontext)); argc -= optind; argv += optind; #if ENABLE_SELINUX - if (flags & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) { + if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) { selinux_or_die(); use_default_selinux_context = 0; - if (flags & OPT_PRESERVE_SECURITY_CONTEXT) { + if (opts & OPT_PRESERVE_SECURITY_CONTEXT) { copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; } - if (flags & OPT_SET_SECURITY_CONTEXT) { + if (opts & OPT_SET_SECURITY_CONTEXT) { setfscreatecon_or_die(scontext); copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT; } } #endif - /* preserve access and modification time, this is GNU behaviour, BSD only preserves modification time */ - if (flags & OPT_PRESERVE_TIME) { + /* preserve access and modification time, this is GNU behaviour, + * BSD only preserves modification time */ + if (opts & OPT_PRESERVE_TIME) { copy_flags |= FILEUTILS_PRESERVE_STATUS; } mode = 0666; - if (flags & OPT_MODE) + if (opts & OPT_MODE) bb_parse_mode(mode_str, &mode); - uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); - gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); + uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); + gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); last = argv[argc - 1]; - if (!(flags & OPT_DIRECTORY)) { + if (!(opts & OPT_DIRECTORY)) { argv[argc - 1] = NULL; min_args++; @@ -149,7 +149,7 @@ int install_main(int argc, char **argv) while ((arg = *argv++) != NULL) { char *dest = last; - if (flags & OPT_DIRECTORY) { + if (opts & OPT_DIRECTORY) { dest = arg; /* GNU coreutils 6.9 does not set uid:gid * on intermediate created directories @@ -159,6 +159,13 @@ int install_main(int argc, char **argv) goto next; } } else { + if (opts & OPT_MKDIR_LEADING) { + char *ddir = xstrdup(dest); + bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR); + /* errors are not checked. copy_file + * will fail if dir is not created. */ + free(ddir); + } if (isdir) dest = concat_path_file(last, basename(arg)); if (copy_file(arg, dest, copy_flags)) { @@ -169,7 +176,7 @@ int install_main(int argc, char **argv) } /* Set the file mode */ - if ((flags & OPT_MODE) && chmod(dest, mode) == -1) { + if ((opts & OPT_MODE) && chmod(dest, mode) == -1) { bb_perror_msg("can't change %s of %s", "permissions", dest); ret = EXIT_FAILURE; } @@ -178,13 +185,13 @@ int install_main(int argc, char **argv) setdefaultfilecon(dest); #endif /* Set the user and group id */ - if ((flags & (OPT_OWNER|OPT_GROUP)) + if ((opts & (OPT_OWNER|OPT_GROUP)) && lchown(dest, uid, gid) == -1 ) { bb_perror_msg("can't change %s of %s", "ownership", dest); ret = EXIT_FAILURE; } - if (flags & OPT_STRIP) { + if (opts & OPT_STRIP) { char *args[3]; args[0] = (char*)"strip"; args[1] = dest; diff --git a/release/src/router/busybox/coreutils/length.c b/release/src/router/busybox/coreutils/length.c index c7523a02a1..43a0f59880 100644 --- a/release/src/router/busybox/coreutils/length.c +++ b/release/src/router/busybox/coreutils/length.c @@ -1,4 +1,7 @@ /* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ /* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */ diff --git a/release/src/router/busybox/coreutils/libcoreutils/coreutils.h b/release/src/router/busybox/coreutils/libcoreutils/coreutils.h index 89cd9532f2..99b67b14d6 100644 --- a/release/src/router/busybox/coreutils/libcoreutils/coreutils.h +++ b/release/src/router/busybox/coreutils/libcoreutils/coreutils.h @@ -4,11 +4,9 @@ */ #ifndef COREUTILS_H -#define COREUTILS_H 1 +#define COREUTILS_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN typedef int (*stat_func)(const char *fn, struct stat *ps); @@ -17,8 +15,6 @@ int cp_mv_stat(const char *fn, struct stat *fn_stat) FAST_FUNC; mode_t getopt_mk_fifo_nod(char **argv) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/coreutils/ls.c b/release/src/router/busybox/coreutils/ls.c index f4e71bc6a4..61baa9a110 100644 --- a/release/src/router/busybox/coreutils/ls.c +++ b/release/src/router/busybox/coreutils/ls.c @@ -6,7 +6,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -/* +/* [date unknown. Perhaps before year 2000] * To achieve a small memory footprint, this version of 'ls' doesn't do any * file sorting, and only has the most essential command line switches * (i.e., the ones I couldn't live without :-) All features which involve @@ -18,8 +18,7 @@ * * KNOWN BUGS: * 1. ls -l of a directory doesn't give "total " header - * 2. ls of a symlink to a directory doesn't list directory contents - * 3. hidden files can make column width too large + * 2. hidden files can make column width too large * * NON-OPTIMAL BEHAVIOUR: * 1. autowidth reads directories twice @@ -27,6 +26,9 @@ * appended, there's no need to stat each one * PORTABILITY: * 1. requires lstat (BSD) - how do you do it without? + * + * [2009-03] + * ls sorts listing now, and supports almost all options. */ #include "libbb.h" @@ -38,6 +40,21 @@ /* This is a NOEXEC applet. Be very careful! */ +#if ENABLE_FTPD +/* ftpd uses ls, and without timestamps Mozilla won't understand + * ftpd's LIST output. + */ +# undef CONFIG_FEATURE_LS_TIMESTAMPS +# undef ENABLE_FEATURE_LS_TIMESTAMPS +# undef USE_FEATURE_LS_TIMESTAMPS +# undef SKIP_FEATURE_LS_TIMESTAMPS +# define CONFIG_FEATURE_LS_TIMESTAMPS 1 +# define ENABLE_FEATURE_LS_TIMESTAMPS 1 +# define USE_FEATURE_LS_TIMESTAMPS(...) __VA_ARGS__ +# define SKIP_FEATURE_LS_TIMESTAMPS(...) +#endif + + enum { TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ @@ -59,7 +76,7 @@ LIST_ID_NAME = 1 << 4, LIST_ID_NUMERIC = 1 << 5, LIST_CONTEXT = 1 << 6, LIST_SIZE = 1 << 7, -LIST_DEV = 1 << 8, +//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE LIST_DATE_TIME = 1 << 9, LIST_FULLTIME = 1 << 10, LIST_FILENAME = 1 << 11, @@ -110,13 +127,102 @@ SPLIT_SUBDIR = 2, }; -#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) -#define COLOR(mode) ("\000\043\043\043\042\000\043\043"\ - "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)]) -#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\ - "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)]) +/* "[-]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 */ +static const char ls_options[] ALIGN1 = + "Cadil1gnsxQAk" /* 13 opts, total 13 */ + USE_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ + USE_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ + USE_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ + USE_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ + USE_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ + USE_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ + USE_SELINUX("K") /* 1, 27 */ + USE_SELINUX("Z") /* 1, 28 */ + USE_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ + ; +enum { + //OPT_C = (1 << 0), + //OPT_a = (1 << 1), + //OPT_d = (1 << 2), + //OPT_i = (1 << 3), + //OPT_l = (1 << 4), + //OPT_1 = (1 << 5), + OPT_g = (1 << 6), + //OPT_n = (1 << 7), + //OPT_s = (1 << 8), + //OPT_x = (1 << 9), + OPT_Q = (1 << 10), + //OPT_A = (1 << 11), + //OPT_k = (1 << 12), +}; + +enum { + LIST_MASK_TRIGGER = 0, + STYLE_MASK_TRIGGER = STYLE_MASK, + DISP_MASK_TRIGGER = DISP_ROWS, + SORT_MASK_TRIGGER = SORT_MASK, +}; + +/* 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 group) - 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) */ +#if ENABLE_FEATURE_LS_TIMESTAMPS + TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ + LIST_FULLTIME, /* e */ + ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ + TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ +#endif +#if ENABLE_FEATURE_LS_SORTFILES + SORT_SIZE, /* S */ + SORT_EXT, /* X */ + SORT_REVERSE, /* r */ + SORT_VERSION, /* v */ +#endif +#if ENABLE_FEATURE_LS_FILETYPES + LIST_FILETYPE | LIST_EXEC, /* F */ + LIST_FILETYPE, /* p */ +#endif +#if ENABLE_FEATURE_LS_FOLLOWLINKS + FOLLOW_LINKS, /* L */ +#endif +#if ENABLE_FEATURE_LS_RECURSIVE + DISP_RECURSIVE, /* R */ +#endif +#if ENABLE_FEATURE_HUMAN_READABLE + LS_DISP_HR, /* h */ +#endif +#if ENABLE_SELINUX + LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ +#endif +#if ENABLE_SELINUX + LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ +#endif + (1U<<31) + /* options after Z are not processed through opt_flags: + * T, w - ignored + */ +}; + /* * a directory entry and its stat info are stored here @@ -230,18 +336,46 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f 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)]) +/* 036 black foreground 050 black background + 037 red foreground 051 red background + 040 green foreground 052 green background + 041 brown foreground 053 brown background + 042 blue foreground 054 blue background + 043 magenta (purple) foreground 055 magenta background + 044 cyan (light blue) foreground 056 cyan background + 045 gray foreground 057 white background +*/ +#define COLOR(mode) ( \ + /*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) + * (other attributes are 2:dim 4:underline 5:blink 7:reverse, + * let's use 7 for "impossible" types, just for fun) + * Note: coreutils 6.9 uses inverted red for setuid binaries. + */ +#define ATTR(mode) ( \ + /*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)]) + #if ENABLE_FEATURE_LS_COLOR +/* mode of zero is interpreted as "unknown" (stat failed) */ static char fgcolor(mode_t mode) { - /* Check wheter the file is existing (if so, color it red!) */ - if (errno == ENOENT) - return '\037'; if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return COLOR(0xF000); /* File is executable ... */ return COLOR(mode); } - -static char bgcolor(mode_t mode) +static char bold(mode_t mode) { if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return ATTR(0xF000); /* File is executable ... */ @@ -264,6 +398,7 @@ static char append_char(mode_t mode) } #endif + #define countdirs(A, B) count_dirs((A), (B), 1) #define countsubdirs(A, B) count_dirs((A), (B), 0) static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs) @@ -573,10 +708,41 @@ static struct dnode **list_dir(const char *path) } -static int list_single(const struct dnode *dn) +static int print_name(const char *name) { - int i, column = 0; + if (option_mask32 & OPT_Q) { +#if ENABLE_FEATURE_ASSUME_UNICODE + int len = 2 + mbstrlen(name); +#else + int len = 2; +#endif + putchar('"'); + while (*name) { + if (*name == '"') { + putchar('\\'); + len++; + } + putchar(*name++); + if (!ENABLE_FEATURE_ASSUME_UNICODE) + len++; + } + putchar('"'); + return len; + } + /* No -Q: */ +#if ENABLE_FEATURE_ASSUME_UNICODE + fputs(name, stdout); + return mbstrlen(name); +#else + return printf("%s", name); +#endif +} + +static int list_single(const struct dnode *dn) +{ + int column = 0; + char *lpath = lpath; /* for compiler */ #if ENABLE_FEATURE_LS_TIMESTAMPS char *filetime; time_t ttime, age; @@ -601,219 +767,128 @@ static int list_single(const struct dnode *dn) append = append_char(dn->dstat.st_mode); #endif - for (i = 0; i <= 31; i++) { - switch (all_fmt & (1 << i)) { - case LIST_INO: - column += printf("%7ld ", (long) dn->dstat.st_ino); - break; - case LIST_BLOCKS: - column += printf("%4"OFF_FMT"d ", (off_t) dn->dstat.st_blocks >> 1); - break; - case LIST_MODEBITS: - column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode)); - break; - case LIST_NLINKS: - column += printf("%4ld ", (long) dn->dstat.st_nlink); - break; - case LIST_ID_NAME: + /* Do readlink early, so that if it fails, error message + * does not appear *inside* of the "ls -l" line */ + if (all_fmt & LIST_SYMLINK) + if (S_ISLNK(dn->dstat.st_mode)) + lpath = xmalloc_readlink_or_warn(dn->fullname); + + if (all_fmt & LIST_INO) + column += printf("%7lu ", (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 ENABLE_FEATURE_LS_USERNAME - printf("%-8.8s %-8.8s", + if (all_fmt & LIST_ID_NAME) { + if (option_mask32 & OPT_g) { + column += printf("%-8.8s", + get_cached_username(dn->dstat.st_uid)); + } else { + column += printf("%-8.8s %-8.8s", get_cached_username(dn->dstat.st_uid), get_cached_groupname(dn->dstat.st_gid)); - column += 17; - break; -#endif - case LIST_ID_NUMERIC: - column += printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); - break; - case LIST_SIZE: - case LIST_DEV: - if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { - column += printf("%4d, %3d ", (int) major(dn->dstat.st_rdev), - (int) minor(dn->dstat.st_rdev)); + } + } +#endif + if (all_fmt & LIST_ID_NUMERIC) { + if (option_mask32 & OPT_g) + column += printf("%-8u", (int) dn->dstat.st_uid); + 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)) { + column += printf("%4u, %3u ", + (int) major(dn->dstat.st_rdev), + (int) minor(dn->dstat.st_rdev)); + } else { + if (all_fmt & LS_DISP_HR) { + column += printf("%9s ", + make_human_readable_str(dn->dstat.st_size, 1, 0)); } else { - if (all_fmt & LS_DISP_HR) { - column += printf("%9s ", - make_human_readable_str(dn->dstat.st_size, 1, 0)); - } else { - column += printf("%9"OFF_FMT"d ", (off_t) dn->dstat.st_size); - } + column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size); } - break; + } + } #if ENABLE_FEATURE_LS_TIMESTAMPS - case LIST_FULLTIME: - printf("%24.24s ", filetime); - column += 25; - break; - case LIST_DATE_TIME: - if ((all_fmt & LIST_FULLTIME) == 0) { - /* current_time_t ~== time(NULL) */ - age = current_time_t - ttime; - printf("%6.6s ", filetime + 4); - if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { - /* hh:mm if less than 6 months old */ - printf("%5.5s ", filetime + 11); - } else { - printf(" %4.4s ", filetime + 20); - } - column += 13; + if (all_fmt & LIST_FULLTIME) + column += printf("%24.24s ", filetime); + if (all_fmt & LIST_DATE_TIME) + if ((all_fmt & LIST_FULLTIME) == 0) { + /* current_time_t ~== time(NULL) */ + age = current_time_t - ttime; + printf("%6.6s ", filetime + 4); + if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { + /* hh:mm if less than 6 months old */ + printf("%5.5s ", filetime + 11); + } else { + printf(" %4.4s ", filetime + 20); } - break; + column += 13; + } #endif #if ENABLE_SELINUX - case LIST_CONTEXT: - { - char context[80]; - int len = 0; - - if (dn->sid) { - /* I assume sid initilized with NULL */ - len = strlen(dn->sid) + 1; - safe_strncpy(context, dn->sid, len); - freecon(dn->sid); - } else { - safe_strncpy(context, "unknown", 8); - } - printf("%-32s ", context); - column += MAX(33, len); - } - break; + if (all_fmt & LIST_CONTEXT) { + column += printf("%-32s ", dn->sid ? dn->sid : "unknown"); + freecon(dn->sid); + } #endif - case LIST_FILENAME: - errno = 0; + if (all_fmt & LIST_FILENAME) { #if ENABLE_FEATURE_LS_COLOR - if (show_color && !lstat(dn->fullname, &info)) { - printf("\033[%d;%dm", bgcolor(info.st_mode), - fgcolor(info.st_mode)); - } + 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)); + } #endif -#if ENABLE_FEATURE_ASSUME_UNICODE - printf("%s", dn->name); - column += mbstrlen(dn->name); -#else - column += printf("%s", dn->name); + column += print_name(dn->name); + if (show_color) { + printf("\033[0m"); + } + } + if (all_fmt & LIST_SYMLINK) { + if (S_ISLNK(dn->dstat.st_mode) && lpath) { + printf(" -> "); +#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR +#if ENABLE_FEATURE_LS_COLOR + info.st_mode = 0; /* for fgcolor() */ #endif - if (show_color) { - printf("\033[0m"); + if (stat(dn->fullname, &info) == 0) { + append = append_char(info.st_mode); } - break; - case LIST_SYMLINK: - if (S_ISLNK(dn->dstat.st_mode)) { - char *lpath = xmalloc_readlink_or_warn(dn->fullname); - if (!lpath) break; - printf(" -> "); -#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR - if (!stat(dn->fullname, &info)) { - append = append_char(info.st_mode); - } #endif #if ENABLE_FEATURE_LS_COLOR - if (show_color) { - errno = 0; - printf("\033[%d;%dm", bgcolor(info.st_mode), - fgcolor(info.st_mode)); - } + if (show_color) { + printf("\033[%u;%um", bold(info.st_mode), + fgcolor(info.st_mode)); + } #endif - column += printf("%s", lpath) + 4; - if (show_color) { - printf("\033[0m"); - } - free(lpath); + column += print_name(lpath) + 4; + if (show_color) { + printf("\033[0m"); } - break; + free(lpath); + } + } #if ENABLE_FEATURE_LS_FILETYPES - case LIST_FILETYPE: - if (append) { - putchar(append); - column++; - } - break; -#endif + if (all_fmt & LIST_FILETYPE) { + if (append) { + putchar(append); + column++; } } +#endif return column; } -/* "[-]Cadil1", POSIX mandated options, busybox always supports */ -/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ -/* "[-]Ak" GNU options, busybox always supports */ -/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */ -/* "[-]p", POSIX non-mandated options, busybox optionally supports */ -/* "[-]SXvThw", GNU options, busybox optionally supports */ -/* "[-]K", SELinux mandated options, busybox optionally supports */ -/* "[-]e", I think we made this one up */ -static const char ls_options[] ALIGN1 = - "Cadil1gnsxAk" - USE_FEATURE_LS_TIMESTAMPS("cetu") - USE_FEATURE_LS_SORTFILES("SXrv") - USE_FEATURE_LS_FILETYPES("Fp") - USE_FEATURE_LS_FOLLOWLINKS("L") - USE_FEATURE_LS_RECURSIVE("R") - USE_FEATURE_HUMAN_READABLE("h") - USE_SELINUX("K") - USE_FEATURE_AUTOWIDTH("T:w:") - USE_SELINUX("Z"); - -enum { - LIST_MASK_TRIGGER = 0, - STYLE_MASK_TRIGGER = STYLE_MASK, - DISP_MASK_TRIGGER = DISP_ROWS, - SORT_MASK_TRIGGER = SORT_MASK, -}; - -static const unsigned opt_flags[] = { - LIST_SHORT | STYLE_COLUMNS, /* C */ - DISP_HIDDEN | DISP_DOT, /* a */ - DISP_NOLIST, /* d */ - LIST_INO, /* i */ - LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ - LIST_SHORT | STYLE_SINGLE, /* 1 */ - 0, /* g - ingored */ - LIST_ID_NUMERIC, /* n */ - LIST_BLOCKS, /* s */ - DISP_ROWS, /* x */ - DISP_HIDDEN, /* A */ - ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ -#if ENABLE_FEATURE_LS_TIMESTAMPS - TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ - LIST_FULLTIME, /* e */ - ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ - TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ -#endif -#if ENABLE_FEATURE_LS_SORTFILES - SORT_SIZE, /* S */ - SORT_EXT, /* X */ - SORT_REVERSE, /* r */ - SORT_VERSION, /* v */ -#endif -#if ENABLE_FEATURE_LS_FILETYPES - LIST_FILETYPE | LIST_EXEC, /* F */ - LIST_FILETYPE, /* p */ -#endif -#if ENABLE_FEATURE_LS_FOLLOWLINKS - FOLLOW_LINKS, /* L */ -#endif -#if ENABLE_FEATURE_LS_RECURSIVE - DISP_RECURSIVE, /* R */ -#endif -#if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ -#endif -#if ENABLE_SELINUX - LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ -#endif -#if ENABLE_FEATURE_AUTOWIDTH - 0, 0, /* T, w - ignored */ -#endif -#if ENABLE_SELINUX - LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ -#endif - (1U<<31) -}; - - /* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */ #if ENABLE_FEATURE_LS_COLOR /* long option entry used only for --color, which has no short option @@ -824,7 +899,6 @@ static const char ls_color_opt[] ALIGN1 = #endif -int ls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ls_main(int argc UNUSED_PARAM, char **argv) { struct dnode **dnd; @@ -932,8 +1006,8 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dn = NULL; nfiles = 0; do { - /* ls w/o -l follows links on command line */ - cur = my_stat(*argv, *argv, !(all_fmt & STYLE_LONG)); + /* NB: follow links on command line unless -l or -s */ + cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS))); argv++; if (!cur) continue; diff --git a/release/src/router/busybox/coreutils/md5_sha1_sum.c b/release/src/router/busybox/coreutils/md5_sha1_sum.c index a5681589bd..a988b9cbfd 100644 --- a/release/src/router/busybox/coreutils/md5_sha1_sum.c +++ b/release/src/router/busybox/coreutils/md5_sha1_sum.c @@ -8,7 +8,13 @@ #include "libbb.h" -typedef enum { HASH_SHA1, HASH_MD5 } hash_algo_t; +typedef enum { + /* 4th letter of applet_name is... */ + HASH_MD5 = 's', /* "md5>s - * Copyright 2006 Bernhard Fischer + * Copyright 2006 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/coreutils/printenv.c b/release/src/router/busybox/coreutils/printenv.c index 6971f7258e..2430f3a1ae 100644 --- a/release/src/router/busybox/coreutils/printenv.c +++ b/release/src/router/busybox/coreutils/printenv.c @@ -13,6 +13,8 @@ int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int printenv_main(int argc UNUSED_PARAM, char **argv) { + int exit_code = EXIT_SUCCESS; + /* no variables specified, show whole env */ if (!argv[1]) { int e = 0; @@ -26,8 +28,10 @@ int printenv_main(int argc UNUSED_PARAM, char **argv) env = getenv(arg); if (env) puts(env); + else + exit_code = EXIT_FAILURE; } } - fflush_stdout_and_exit(EXIT_SUCCESS); + fflush_stdout_and_exit(exit_code); } diff --git a/release/src/router/busybox/coreutils/printf.c b/release/src/router/busybox/coreutils/printf.c index 76524f7064..0b004eaeb1 100644 --- a/release/src/router/busybox/coreutils/printf.c +++ b/release/src/router/busybox/coreutils/printf.c @@ -75,13 +75,13 @@ static int multiconvert(const char *arg, void *result, converter convert) return 0; } -static void FAST_FUNC conv_strtoul(const char *arg, void *result) +static void FAST_FUNC conv_strtoull(const char *arg, void *result) { - *(unsigned long*)result = bb_strtoul(arg, NULL, 0); + *(unsigned long long*)result = bb_strtoull(arg, NULL, 0); } -static void FAST_FUNC conv_strtol(const char *arg, void *result) +static void FAST_FUNC conv_strtoll(const char *arg, void *result) { - *(long*)result = bb_strtol(arg, NULL, 0); + *(long long*)result = bb_strtoll(arg, NULL, 0); } static void FAST_FUNC conv_strtod(const char *arg, void *result) { @@ -96,17 +96,17 @@ static void FAST_FUNC conv_strtod(const char *arg, void *result) } /* Callers should check errno to detect errors */ -static unsigned long my_xstrtoul(const char *arg) +static unsigned long long my_xstrtoull(const char *arg) { - unsigned long result; - if (multiconvert(arg, &result, conv_strtoul)) + unsigned long long result; + if (multiconvert(arg, &result, conv_strtoull)) result = 0; return result; } -static long my_xstrtol(const char *arg) +static long long my_xstrtoll(const char *arg) { - long result; - if (multiconvert(arg, &result, conv_strtol)) + long long result; + if (multiconvert(arg, &result, conv_strtoll)) result = 0; return result; } @@ -134,61 +134,63 @@ static void print_direc(char *format, unsigned fmt_length, int field_width, int precision, const char *argument) { - long lv; + long long llv; double dv; char saved; char *have_prec, *have_width; + saved = format[fmt_length]; + format[fmt_length] = '\0'; + have_prec = strstr(format, ".*"); have_width = strchr(format, '*'); if (have_width - 1 == have_prec) have_width = NULL; - saved = format[fmt_length]; - format[fmt_length] = '\0'; - switch (format[fmt_length - 1]) { case 'c': printf(format, *argument); break; case 'd': case 'i': - lv = my_xstrtol(argument); + llv = my_xstrtoll(argument); print_long: /* if (errno) return; - see comment at the top */ if (!have_width) { if (!have_prec) - printf(format, lv); + printf(format, llv); else - printf(format, precision, lv); + printf(format, precision, llv); } else { if (!have_prec) - printf(format, field_width, lv); + printf(format, field_width, llv); else - printf(format, field_width, precision, lv); + printf(format, field_width, precision, llv); } break; case 'o': case 'u': case 'x': case 'X': - lv = my_xstrtoul(argument); + llv = my_xstrtoull(argument); /* cheat: unsigned long and long have same width, so... */ goto print_long; case 's': - /* Are char* and long the same? (true for most arches) */ - if (sizeof(argument) == sizeof(lv)) { - lv = (long)(ptrdiff_t)argument; + /* Are char* and long long the same? */ + if (sizeof(argument) == sizeof(llv)) { + llv = (long long)(ptrdiff_t)argument; goto print_long; - } else { /* Hope compiler will optimize it out */ + } else { + /* Hope compiler will optimize it out by moving call + * instruction after the ifs... */ if (!have_width) { if (!have_prec) - printf(format, argument); + printf(format, argument, /*unused:*/ argument, argument); else - printf(format, precision, argument); + printf(format, precision, argument, /*unused:*/ argument); } else { if (!have_prec) - printf(format, field_width, argument); + printf(format, field_width, argument, /*unused:*/ argument); else printf(format, field_width, precision, argument); } @@ -286,38 +288,48 @@ static char **print_formatted(char *f, char **argv) } } } - /* Remove size modifiers - "%Ld" would try to printf - * long long, we pass long, and it spews garbage */ - if ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { + + /* Remove "lLhz" size modifiers, repeatedly. + * bash does not like "%lld", but coreutils + * would happily take even "%Llllhhzhhzd"! + * We will be permissive like coreutils */ + while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { overlapping_strcpy(f, f + 1); } -//FIXME: actually, the same happens with bare "%d": -//it printfs an int, but we pass long! -//What saves us is that on most arches stack slot -//is pointer-sized -> long-sized -> ints are promoted to longs -// for variadic functions -> printf("%d", int_v) is in reality -// indistinqushable from printf("%d", long_v) -> -// since printf("%d", int_v) works, printf("%d", long_v) has to work. -//But "clean" solution would be to add "l" to d,i,o,x,X. -//Probably makes sense to go all the way to "ll" then. -//Coreutils support long long-sized arguments. - - /* needed - try "printf %" without it */ - if (!strchr("diouxXfeEgGcs", *f)) { - bb_error_msg("%s: invalid format", direc_start); - /* causes main() to exit with error */ - return saved_argv - 1; - } - ++direc_length; - if (*argv) { - print_direc(direc_start, direc_length, field_width, - precision, *argv); - ++argv; - } else { - print_direc(direc_start, direc_length, field_width, - precision, ""); + /* Add "ll" if integer modifier, then print */ + { + static const char format_chars[] ALIGN1 = "diouxXfeEgGcs"; + char *p = strchr(format_chars, *f); + /* needed - try "printf %" without it */ + if (p == NULL) { + bb_error_msg("%s: invalid format", direc_start); + /* causes main() to exit with error */ + return saved_argv - 1; + } + ++direc_length; + if (p - format_chars <= 5) { + /* it is one of "diouxX" */ + p = xmalloc(direc_length + 3); + memcpy(p, direc_start, direc_length); + p[direc_length + 1] = p[direc_length - 1]; + p[direc_length - 1] = 'l'; + p[direc_length] = 'l'; + //bb_error_msg("<%s>", p); + direc_length += 2; + direc_start = p; + } else { + p = NULL; + } + if (*argv) { + print_direc(direc_start, direc_length, field_width, + precision, *argv); + ++argv; + } else { + print_direc(direc_start, direc_length, field_width, + precision, ""); + } + free(p); } - /* if (errno) return saved_argv - 1; */ break; case '\\': if (*++f == 'c') { @@ -359,8 +371,15 @@ int printf_main(int argc UNUSED_PARAM, char **argv) * We will mimic coreutils. */ if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2]) argv++; - if (!argv[1]) + if (!argv[1]) { + if (ENABLE_ASH_BUILTIN_PRINTF + && applet_name[0] != 'p' + ) { + bb_error_msg("usage: printf FORMAT [ARGUMENT...]"); + return 2; /* bash compat */ + } bb_show_usage(); + } format = argv[1]; argv2 = argv + 2; diff --git a/release/src/router/busybox/coreutils/rm.c b/release/src/router/busybox/coreutils/rm.c index 975f2267b1..6b3fbcf253 100644 --- a/release/src/router/busybox/coreutils/rm.c +++ b/release/src/router/busybox/coreutils/rm.c @@ -27,13 +27,14 @@ int rm_main(int argc UNUSED_PARAM, char **argv) unsigned opt; opt_complementary = "f-i:i-f"; - opt = getopt32(argv, "fiRr"); + /* -v (verbose) is ignored */ + opt = getopt32(argv, "fiRrv"); argv += optind; if (opt & 1) flags |= FILEUTILS_FORCE; if (opt & 2) flags |= FILEUTILS_INTERACTIVE; - if (opt & 12) + if (opt & (8|4)) flags |= FILEUTILS_RECUR; if (*argv != NULL) { diff --git a/release/src/router/busybox/coreutils/seq.c b/release/src/router/busybox/coreutils/seq.c index 01d71f256b..4b853c6986 100644 --- a/release/src/router/busybox/coreutils/seq.c +++ b/release/src/router/busybox/coreutils/seq.c @@ -15,26 +15,39 @@ int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int seq_main(int argc, char **argv) { + enum { + OPT_w = (1 << 0), + OPT_s = (1 << 1), + }; double last, increment, i; + const char *sep, *opt_s = "\n"; + unsigned opt = getopt32(argv, "+ws:", &opt_s); + unsigned width = 0; + argc -= optind; + argv += optind; i = increment = 1; switch (argc) { - case 4: - increment = atof(argv[2]); case 3: - i = atof(argv[1]); + increment = atof(argv[1]); case 2: + i = atof(*argv); + case 1: last = atof(argv[argc-1]); break; default: bb_show_usage(); } + if (opt & OPT_w) /* Pad to length of start or last */ + width = MAX(strlen(*argv), strlen(argv[argc-1])); /* You should note that this is pos-5.0.91 semantics, -- FK. */ + sep = ""; while ((increment > 0 && i <= last) || (increment < 0 && i >= last)) { - printf("%g\n", i); + printf("%s%0*g", sep, width, i); + sep = opt_s; i += increment; } - + bb_putchar('\n'); return fflush(stdout); } diff --git a/release/src/router/busybox/coreutils/split.c b/release/src/router/busybox/coreutils/split.c index 77cb66d536..f1ec64be02 100644 --- a/release/src/router/busybox/coreutils/split.c +++ b/release/src/router/busybox/coreutils/split.c @@ -1,7 +1,7 @@ /* vi: set sw=4 ts=4: */ /* * split - split a file into pieces - * Copyright (c) 2007 Bernhard Fischer + * Copyright (c) 2007 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/coreutils/stat.c b/release/src/router/busybox/coreutils/stat.c index c34c06acba..32e8b42f38 100644 --- a/release/src/router/busybox/coreutils/stat.c +++ b/release/src/router/busybox/coreutils/stat.c @@ -125,6 +125,20 @@ static const char *human_fstype(uint32_t f_type) return humantypes[i].fs; } +/* "man statfs" says that statfsbuf->f_fsid is a mess */ +/* coreutils treats it as an array of ints, most significant first */ +static unsigned long long get_f_fsid(const struct statfs *statfsbuf) +{ + const unsigned *p = (const void*) &statfsbuf->f_fsid; + unsigned sz = sizeof(statfsbuf->f_fsid) / sizeof(unsigned); + unsigned long long r = 0; + + do + r = (r << (sizeof(unsigned)*8)) | *p++; + while (--sz > 0); + return r; +} + #if ENABLE_FEATURE_STAT_FORMAT static void strcatc(char *str, char c) { @@ -148,11 +162,11 @@ static void print_statfs(char *pformat, const char m, if (m == 'n') { printfs(pformat, filename); } else if (m == 'i') { - strcat(pformat, "Lx"); - printf(pformat, statfsbuf->f_fsid); + strcat(pformat, "llx"); + printf(pformat, get_f_fsid(statfsbuf)); } else if (m == 'l') { strcat(pformat, "lu"); - printf(pformat, statfsbuf->f_namelen); + printf(pformat, (unsigned long) (statfsbuf->f_namelen)); } else if (m == 't') { strcat(pformat, "lx"); printf(pformat, (unsigned long) (statfsbuf->f_type)); /* no equiv */ @@ -349,10 +363,11 @@ static void print_it(const char *masterformat, const char *filename, #endif static bool do_statfs(const char *filename, const char *format) { + struct statfs statfsbuf; + #if !ENABLE_FEATURE_STAT_FORMAT const char *format; #endif - struct statfs statfsbuf; #if ENABLE_SELINUX security_context_t scontext = NULL; @@ -406,10 +421,10 @@ static bool do_statfs(const char *filename, const char *format) format = (option_mask32 & OPT_TERSE ? "%s %llx %lu " : " File: \"%s\"\n" - " ID: %-8Lx Namelen: %-7lu "); + " ID: %-8llx Namelen: %-7lu "); printf(format, filename, - statfsbuf.f_fsid, + get_f_fsid(&statfsbuf), statfsbuf.f_namelen); if (option_mask32 & OPT_TERSE) diff --git a/release/src/router/busybox/coreutils/tail.c b/release/src/router/busybox/coreutils/tail.c index 2505fc3a60..5dae2d35b1 100644 --- a/release/src/router/busybox/coreutils/tail.c +++ b/release/src/router/busybox/coreutils/tail.c @@ -104,7 +104,7 @@ int tail_main(int argc, char **argv) if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-') && isdigit(argv[1][1]) ) { - count = eat_num(&argv[1][1]); + count = eat_num(argv[1]); argv++; argc--; } diff --git a/release/src/router/busybox/coreutils/tee.c b/release/src/router/busybox/coreutils/tee.c index dc947c9358..0f24246708 100644 --- a/release/src/router/busybox/coreutils/tee.c +++ b/release/src/router/busybox/coreutils/tee.c @@ -11,7 +11,6 @@ /* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */ #include "libbb.h" -#include int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tee_main(int argc, char **argv) diff --git a/release/src/router/busybox/coreutils/test.c b/release/src/router/busybox/coreutils/test.c index dbfe4af693..ae40192a21 100644 --- a/release/src/router/busybox/coreutils/test.c +++ b/release/src/router/busybox/coreutils/test.c @@ -12,7 +12,7 @@ * modified by Herbert Xu to be used as built-in in ash. * modified by Erik Andersen to be used * in busybox. - * modified by Bernhard Fischer to be useable (i.e. a bit less bloaty). + * modified by Bernhard Reutner-Fischer to be useable (i.e. a bit less bloaty). * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * diff --git a/release/src/router/busybox/coreutils/touch.c b/release/src/router/busybox/coreutils/touch.c index 92f20235cd..20191546cd 100644 --- a/release/src/router/busybox/coreutils/touch.c +++ b/release/src/router/busybox/coreutils/touch.c @@ -41,6 +41,13 @@ int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int touch_main(int argc UNUSED_PARAM, char **argv) { #if ENABLE_DESKTOP +#if ENABLE_GETOPT_LONG + static const char longopts[] ALIGN1 = + /* name, has_arg, val */ + "no-create\0" No_argument "c" + "reference\0" Required_argument "r" + ; +#endif struct utimbuf timebuf; char *reference_file = NULL; #else @@ -49,11 +56,18 @@ int touch_main(int argc UNUSED_PARAM, char **argv) #endif int fd; int status = EXIT_SUCCESS; - int flags = getopt32(argv, "c" USE_DESKTOP("r:") + int opts; + +#if ENABLE_DESKTOP +#if ENABLE_GETOPT_LONG + applet_long_options = longopts; +#endif +#endif + opts = getopt32(argv, "c" USE_DESKTOP("r:") /*ignored:*/ "fma" USE_DESKTOP(, &reference_file)); - flags &= 1; /* only -c bit is left */ + opts &= 1; /* only -c bit is left */ argv += optind; if (!*argv) { bb_show_usage(); @@ -69,7 +83,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) do { if (utime(*argv, reference_file ? &timebuf : NULL)) { if (errno == ENOENT) { /* no such file */ - if (flags) { /* creation is disabled, so ignore */ + if (opts) { /* creation is disabled, so ignore */ continue; } /* Try to create the file. */ diff --git a/release/src/router/busybox/coreutils/tr.c b/release/src/router/busybox/coreutils/tr.c index c736c716b2..d89b80bec1 100644 --- a/release/src/router/busybox/coreutils/tr.c +++ b/release/src/router/busybox/coreutils/tr.c @@ -16,235 +16,284 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ /* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html - * TODO: xdigit, graph, print + * TODO: graph, print */ #include "libbb.h" -#define ASCII 0377 +enum { + ASCII = 256, + /* string buffer needs to be at least as big as the whole "alphabet". + * BUFSIZ == ASCII is ok, but we will realloc in expand + * even for smallest patterns, let's avoid that by using *2: + */ + TR_BUFSIZ = (BUFSIZ > ASCII*2) ? BUFSIZ : ASCII*2, +}; static void map(char *pvector, - unsigned char *string1, unsigned int string1_len, - unsigned char *string2, unsigned int string2_len) + char *string1, unsigned string1_len, + char *string2, unsigned string2_len) { char last = '0'; - unsigned int i, j; + unsigned i, j; for (j = 0, i = 0; i < string1_len; i++) { if (string2_len <= j) - pvector[string1[i]] = last; + pvector[(unsigned char)(string1[i])] = last; else - pvector[string1[i]] = last = string2[j++]; + pvector[(unsigned char)(string1[i])] = last = string2[j++]; } } /* supported constructs: * Ranges, e.g., 0-9 ==> 0123456789 - * Ranges, e.g., [0-9] ==> 0123456789 * Escapes, e.g., \a ==> Control-G * Character classes, e.g. [:upper:] ==> A...Z * Equiv classess, e.g. [=A=] ==> A (hmmmmmmm?) + * not supported: + * \ooo-\ooo - octal ranges + * [x*N] - repeat char x N times + * [x*] - repeat char x until it fills STRING2: + * # echo qwe123 | /usr/bin/tr 123456789 '[d]' + * qwe[d] + * # echo qwe123 | /usr/bin/tr 123456789 '[d*]' + * qweddd */ -static unsigned int expand(const char *arg, char *buffer) +static unsigned expand(const char *arg, char **buffer_p) { - char *buffer_start = buffer; + char *buffer = *buffer_p; + unsigned pos = 0; + unsigned size = TR_BUFSIZ; unsigned i; /* can't be unsigned char: must be able to hold 256 */ unsigned char ac; while (*arg) { + if (pos + ASCII > size) { + size += ASCII; + *buffer_p = buffer = xrealloc(buffer, size); + } if (*arg == '\\') { arg++; - *buffer++ = bb_process_escape_sequence(&arg); + buffer[pos++] = bb_process_escape_sequence(&arg); continue; } if (arg[1] == '-') { /* "0-9..." */ ac = arg[2]; if (ac == '\0') { /* "0-": copy verbatim */ - *buffer++ = *arg++; /* copy '0' */ + buffer[pos++] = *arg++; /* copy '0' */ continue; /* next iter will copy '-' and stop */ } - i = *arg; + i = (unsigned char) *arg; while (i <= ac) /* ok: i is unsigned _int_ */ - *buffer++ = i++; + buffer[pos++] = i++; arg += 3; /* skip 0-9 */ continue; } - if (*arg == '[') { /* "[xyz..." */ + if ((ENABLE_FEATURE_TR_CLASSES || ENABLE_FEATURE_TR_EQUIV) + && *arg == '[' + ) { arg++; - i = *arg++; - /* "[xyz...", i=x, arg points to y */ - if (ENABLE_FEATURE_TR_CLASSES && i == ':') { + i = (unsigned char) *arg++; + /* "[xyz...". i=x, arg points to y */ + if (ENABLE_FEATURE_TR_CLASSES && i == ':') { /* [:class:] */ #define CLO ":]\0" static const char classes[] ALIGN1 = "alpha"CLO "alnum"CLO "digit"CLO "lower"CLO "upper"CLO "space"CLO - "blank"CLO "punct"CLO "cntrl"CLO; -#define CLASS_invalid 0 /* we increment the retval */ -#define CLASS_alpha 1 -#define CLASS_alnum 2 -#define CLASS_digit 3 -#define CLASS_lower 4 -#define CLASS_upper 5 -#define CLASS_space 6 -#define CLASS_blank 7 -#define CLASS_punct 8 -#define CLASS_cntrl 9 -//#define CLASS_xdigit 10 -//#define CLASS_graph 11 -//#define CLASS_print 12 + "blank"CLO "punct"CLO "cntrl"CLO + "xdigit"CLO; + enum { + CLASS_invalid = 0, /* we increment the retval */ + CLASS_alpha = 1, + CLASS_alnum = 2, + CLASS_digit = 3, + CLASS_lower = 4, + CLASS_upper = 5, + CLASS_space = 6, + CLASS_blank = 7, + CLASS_punct = 8, + CLASS_cntrl = 9, + CLASS_xdigit = 10, + //CLASS_graph = 11, + //CLASS_print = 12, + }; smalluint j; - { /* not really pretty.. */ - char *tmp = xstrndup(arg, 7); // warning: xdigit would need 8, not 7 - j = index_in_strings(classes, tmp) + 1; - free(tmp); - } - if (j == CLASS_alnum || j == CLASS_digit) { + char *tmp; + + /* xdigit needs 8, not 7 */ + i = 7 + (arg[0] == 'x'); + tmp = xstrndup(arg, i); + j = index_in_strings(classes, tmp) + 1; + free(tmp); + + if (j == CLASS_invalid) + goto skip_bracket; + + arg += i; + if (j == CLASS_alnum || j == CLASS_digit || j == CLASS_xdigit) { for (i = '0'; i <= '9'; i++) - *buffer++ = i; + buffer[pos++] = i; } if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) { for (i = 'A'; i <= 'Z'; i++) - *buffer++ = i; + buffer[pos++] = i; } if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) { for (i = 'a'; i <= 'z'; i++) - *buffer++ = i; + buffer[pos++] = i; } if (j == CLASS_space || j == CLASS_blank) { - *buffer++ = '\t'; + buffer[pos++] = '\t'; if (j == CLASS_space) { - *buffer++ = '\n'; - *buffer++ = '\v'; - *buffer++ = '\f'; - *buffer++ = '\r'; + buffer[pos++] = '\n'; + buffer[pos++] = '\v'; + buffer[pos++] = '\f'; + buffer[pos++] = '\r'; } - *buffer++ = ' '; + buffer[pos++] = ' '; } if (j == CLASS_punct || j == CLASS_cntrl) { - for (i = '\0'; i <= ASCII; i++) + for (i = '\0'; i < ASCII; i++) { if ((j == CLASS_punct && isprint(i) && !isalnum(i) && !isspace(i)) - || (j == CLASS_cntrl && iscntrl(i))) - *buffer++ = i; + || (j == CLASS_cntrl && iscntrl(i)) + ) { + buffer[pos++] = i; + } + } } - if (j == CLASS_invalid) { - *buffer++ = '['; - *buffer++ = ':'; - continue; + if (j == CLASS_xdigit) { + for (i = 'A'; i <= 'F'; i++) { + buffer[pos + 6] = i | 0x20; + buffer[pos++] = i; + } + pos += 6; } - break; + continue; } /* "[xyz...", i=x, arg points to y */ if (ENABLE_FEATURE_TR_EQUIV && i == '=') { /* [=CHAR=] */ - *buffer++ = *arg; /* copy CHAR */ - if (!*arg || arg[1] != '=' || arg[2] != ']') + buffer[pos++] = *arg; /* copy CHAR */ + if (!arg[0] || arg[1] != '=' || arg[2] != ']') bb_show_usage(); arg += 3; /* skip CHAR=] */ continue; } - if (i == '\0' || *arg != '-') { /* not [x-...] - copy verbatim */ - *buffer++ = '['; - arg--; /* points to x */ - continue; /* copy all, including eventual ']' */ - } - /* [x-z] */ - arg++; /* skip - */ - if (arg[0] == '\0' || arg[1] != ']') - bb_show_usage(); - ac = *arg++; - while (i <= ac) - *buffer++ = i++; - arg++; /* skip ] */ - continue; + /* The rest of "[xyz..." cases is treated as normal + * string, "[" has no special meaning here: + * tr "[a-z]" "[A-Z]" can be written as tr "a-z" "A-Z", + * also try tr "[a-z]" "_A-Z+" and you'll see that + * [] is not special here. + */ + skip_bracket: + arg -= 2; /* points to "[" in "[xyz..." */ } - *buffer++ = *arg++; + buffer[pos++] = *arg++; } - return (buffer - buffer_start); + return pos; } +/* NB: buffer is guaranteed to be at least TR_BUFSIZE + * (which is >= ASCII) big. + */ static int complement(char *buffer, int buffer_len) { - int i, j, ix; - char conv[ASCII + 2]; + int len; + char conv[ASCII]; + unsigned char ch; - ix = 0; - for (i = '\0'; i <= ASCII; i++) { - for (j = 0; j < buffer_len; j++) - if (buffer[j] == i) - break; - if (j == buffer_len) - conv[ix++] = i & ASCII; + len = 0; + ch = '\0'; + while (1) { + if (memchr(buffer, ch, buffer_len) == NULL) + conv[len++] = ch; + if (++ch == '\0') + break; } - memcpy(buffer, conv, ix); - return ix; + memcpy(buffer, conv, len); + return len; } int tr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tr_main(int argc UNUSED_PARAM, char **argv) { - int output_length = 0, input_length; int i; - smalluint flags; - ssize_t read_chars = 0; - size_t in_index = 0, out_index = 0; + smalluint opts; + ssize_t read_chars; + size_t in_index, out_index; unsigned last = UCHAR_MAX + 1; /* not equal to any char */ unsigned char coded, c; - unsigned char *output = xmalloc(BUFSIZ); - char *vector = xzalloc((ASCII+1) * 3); - char *invec = vector + (ASCII+1); - char *outvec = vector + (ASCII+1) * 2; - -#define TR_OPT_complement (1 << 0) -#define TR_OPT_delete (1 << 1) -#define TR_OPT_squeeze_reps (1 << 2) + char *str1 = xmalloc(TR_BUFSIZ); + char *str2 = xmalloc(TR_BUFSIZ); + int str2_length; + int str1_length; + char *vector = xzalloc(ASCII * 3); + char *invec = vector + ASCII; + char *outvec = vector + ASCII * 2; - flags = getopt32(argv, "+cds"); /* '+': stop at first non-option */ - argv += optind; +#define TR_OPT_complement (3 << 0) +#define TR_OPT_delete (1 << 2) +#define TR_OPT_squeeze_reps (1 << 3) - for (i = 0; i <= ASCII; i++) { + for (i = 0; i < ASCII; i++) { vector[i] = i; /*invec[i] = outvec[i] = FALSE; - done by xzalloc */ } -#define tr_buf bb_common_bufsiz1 - if (*argv != NULL) { - input_length = expand(*argv++, tr_buf); - if (flags & TR_OPT_complement) - input_length = complement(tr_buf, input_length); - if (*argv) { - if (argv[0][0] == '\0') - bb_error_msg_and_die("STRING2 cannot be empty"); - output_length = expand(*argv, (char *)output); - map(vector, (unsigned char *)tr_buf, input_length, output, output_length); - } - for (i = 0; i < input_length; i++) - invec[(unsigned char)tr_buf[i]] = TRUE; - for (i = 0; i < output_length; i++) - outvec[output[i]] = TRUE; + /* -C/-c difference is that -C complements "characters", + * and -c complements "values" (binary bytes I guess). + * In POSIX locale, these are the same. + */ + + opt_complementary = "-1"; + opts = getopt32(argv, "+Ccds"); /* '+': stop at first non-option */ + argv += optind; + + str1_length = expand(*argv++, &str1); + str2_length = 0; + if (opts & TR_OPT_complement) + str1_length = complement(str1, str1_length); + if (*argv) { + if (argv[0][0] == '\0') + bb_error_msg_and_die("STRING2 cannot be empty"); + str2_length = expand(*argv, &str2); + map(vector, str1, str1_length, + str2, str2_length); } + for (i = 0; i < str1_length; i++) + invec[(unsigned char)(str1[i])] = TRUE; + for (i = 0; i < str2_length; i++) + outvec[(unsigned char)(str2[i])] = TRUE; + goto start_from; + + /* In this loop, str1 space is reused as input buffer, + * str2 - as output one. */ for (;;) { /* If we're out of input, flush output and read more input. */ if ((ssize_t)in_index == read_chars) { if (out_index) { - xwrite(STDOUT_FILENO, (char *)output, out_index); + xwrite(STDOUT_FILENO, str2, out_index); + start_from: out_index = 0; } - read_chars = safe_read(STDIN_FILENO, tr_buf, BUFSIZ); + read_chars = safe_read(STDIN_FILENO, str1, TR_BUFSIZ); if (read_chars <= 0) { if (read_chars < 0) bb_perror_msg_and_die(bb_msg_read_error); - exit(EXIT_SUCCESS); + break; } in_index = 0; } - c = tr_buf[in_index++]; - coded = vector[c]; - if ((flags & TR_OPT_delete) && invec[c]) + c = str1[in_index++]; + if ((opts & TR_OPT_delete) && invec[c]) continue; - if ((flags & TR_OPT_squeeze_reps) && last == coded - && (invec[c] || outvec[coded])) + coded = vector[c]; + if ((opts & TR_OPT_squeeze_reps) && last == coded + && (invec[c] || outvec[coded]) + ) { continue; - output[out_index++] = last = coded; + } + str2[out_index++] = last = coded; } - /* NOTREACHED */ + return EXIT_SUCCESS; } diff --git a/release/src/router/busybox/coreutils/tty.c b/release/src/router/busybox/coreutils/tty.c index e83289440b..d49fb50b6e 100644 --- a/release/src/router/busybox/coreutils/tty.c +++ b/release/src/router/busybox/coreutils/tty.c @@ -30,7 +30,7 @@ int tty_main(int argc, char **argv SKIP_INCLUDE_SUSv2(UNUSED_PARAM)) retval = 0; - s = ttyname(0); + s = xmalloc_ttyname(0); if (s == NULL) { /* According to SUSv3, ttyname can fail with EBADF or ENOTTY. * We know the file descriptor is good, so failure means not a tty. */ diff --git a/release/src/router/busybox/coreutils/uname.c b/release/src/router/busybox/coreutils/uname.c index e28285c441..33d026f186 100644 --- a/release/src/router/busybox/coreutils/uname.c +++ b/release/src/router/busybox/coreutils/uname.c @@ -9,25 +9,43 @@ /* http://www.opengroup.org/onlinepubs/007904975/utilities/uname.html */ /* Option Example + * -s, --sysname SunOS + * -n, --nodename rocky8 + * -r, --release 4.0 + * -v, --version + * -m, --machine sun + * -a, --all SunOS rocky8 4.0 sun + * + * The default behavior is equivalent to '-s'. + * + * David MacKenzie + * + * GNU coreutils 6.10: + * Option: struct Example(s): + * utsname + * field: + * -s, --kernel-name sysname Linux + * -n, --nodename nodename localhost.localdomain + * -r, --kernel-release release 2.6.29 + * -v, --kernel-version version #1 SMP Sun Jan 11 20:52:37 EST 2009 + * -m, --machine machine x86_64 i686 + * -p, --processor (none) x86_64 i686 + * -i, --hardware-platform (none) x86_64 i386 + * NB: vanilla coreutils reports "unknown" -p and -i, + * x86_64 and i686/i386 shown above are Fedora's inventions. + * -o, --operating-system (none) GNU/Linux + * -a, --all: all of the above, in the order shown. + * If -p or -i is not known, don't show them + */ - -s, --sysname SunOS - -n, --nodename rocky8 - -r, --release 4.0 - -v, --version - -m, --machine sun - -a, --all SunOS rocky8 4.0 sun - - The default behavior is equivalent to '-s'. - - David MacKenzie */ - -/* Busyboxed by Erik Andersen */ - -/* Further size reductions by Glenn McGrath and Manuel Novoa III. */ - -/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) +/* Busyboxed by Erik Andersen * - * Now does proper error checking on i/o. Plus some further space savings. + * Before 2003: Glenn McGrath and Manuel Novoa III + * Further size reductions. + * Mar 16, 2003: Manuel Novoa III (mjn3@codepoet.org) + * Now does proper error checking on i/o. Plus some further space savings. + * Jan 2009: + * Fix handling of -a to not print "unknown", add -o and -i support. */ #include @@ -35,37 +53,60 @@ typedef struct { struct utsname name; - char processor[8]; /* for "unknown" */ + char processor[sizeof(((struct utsname*)NULL)->machine)]; + char platform[sizeof(((struct utsname*)NULL)->machine)]; + char os[sizeof("GNU/Linux")]; } uname_info_t; -static const char options[] ALIGN1 = "snrvmpa"; +static const char options[] ALIGN1 = "snrvmpioa"; static const unsigned short utsname_offset[] = { - offsetof(uname_info_t, name.sysname), - offsetof(uname_info_t, name.nodename), - offsetof(uname_info_t, name.release), - offsetof(uname_info_t, name.version), - offsetof(uname_info_t, name.machine), - offsetof(uname_info_t, processor) + offsetof(uname_info_t, name.sysname), /* -s */ + offsetof(uname_info_t, name.nodename), /* -n */ + offsetof(uname_info_t, name.release), /* -r */ + offsetof(uname_info_t, name.version), /* -v */ + offsetof(uname_info_t, name.machine), /* -m */ + offsetof(uname_info_t, processor), /* -p */ + offsetof(uname_info_t, platform), /* -i */ + offsetof(uname_info_t, os), /* -o */ }; int uname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uname_main(int argc UNUSED_PARAM, char **argv) { +#if ENABLE_GETOPT_LONG + static const char longopts[] ALIGN1 = + /* name, has_arg, val */ + "all\0" No_argument "a" + "kernel-name\0" No_argument "s" + "nodename\0" No_argument "n" + "kernel-release\0" No_argument "r" + "release\0" No_argument "r" + "kernel-version\0" No_argument "v" + "machine\0" No_argument "m" + "processor\0" No_argument "p" + "hardware-platform\0" No_argument "i" + "operating-system\0" No_argument "o" + ; +#endif uname_info_t uname_info; #if defined(__sparc__) && defined(__linux__) char *fake_sparc = getenv("FAKE_SPARC"); #endif + const char *unknown_str = "unknown"; + const char *fmt; const unsigned short *delta; - char toprint; + unsigned toprint; + USE_GETOPT_LONG(applet_long_options = longopts); toprint = getopt32(argv, options); if (argv[optind]) { /* coreutils-6.9 compat */ bb_show_usage(); } - if (toprint & (1 << 6)) { /* -a => all opts on */ - toprint = 0x3f; + if (toprint & (1 << 8)) { /* -a => all opts on */ + toprint = (1 << 8) - 1; + unknown_str = ""; /* -a does not print unknown fields */ } if (toprint == 0) { /* no opts => -s (sysname) */ @@ -79,16 +120,30 @@ int uname_main(int argc UNUSED_PARAM, char **argv) strcpy(uname_info.name.machine, "sparc"); } #endif - - strcpy(uname_info.processor, "unknown"); + strcpy(uname_info.processor, unknown_str); + strcpy(uname_info.platform, unknown_str); + strcpy(uname_info.os, "GNU/Linux"); +#if 0 + /* Fedora does something like this */ + strcpy(uname_info.processor, uname_info.name.machine); + strcpy(uname_info.platform, uname_info.name.machine); + if (uname_info.platform[0] == 'i' + && uname_info.platform[1] + && uname_info.platform[2] == '8' + && uname_info.platform[3] == '6' + ) { + uname_info.platform[1] = '3'; + } +#endif delta = utsname_offset; + fmt = " %s" + 1; do { if (toprint & 1) { - /* printf would not be safe here */ - fputs((char *)(&uname_info) + *delta, stdout); - if (toprint > 1) { - bb_putchar(' '); + const char *p = (char *)(&uname_info) + *delta; + if (p[0]) { + printf(fmt, p); + fmt = " %s"; } } ++delta; diff --git a/release/src/router/busybox/coreutils/uniq.c b/release/src/router/busybox/coreutils/uniq.c index 0918621186..126eaeef99 100644 --- a/release/src/router/busybox/coreutils/uniq.c +++ b/release/src/router/busybox/coreutils/uniq.c @@ -45,7 +45,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) }; skip_fields = skip_chars = 0; - max_chars = -1; + max_chars = INT_MAX; opt_complementary = "f+:s+:w+"; opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars); diff --git a/release/src/router/busybox/coreutils/who.c b/release/src/router/busybox/coreutils/who.c index baf526b01e..85a0025c33 100644 --- a/release/src/router/busybox/coreutils/who.c +++ b/release/src/router/busybox/coreutils/who.c @@ -20,7 +20,6 @@ #include "libbb.h" #include -#include static void idle_string(char *str6, time_t t) { diff --git a/release/src/router/busybox/coreutils/whoami.c b/release/src/router/busybox/coreutils/whoami.c index 6756d4ba9f..0dbcba9553 100644 --- a/release/src/router/busybox/coreutils/whoami.c +++ b/release/src/router/busybox/coreutils/whoami.c @@ -20,7 +20,7 @@ int whoami_main(int argc, char **argv UNUSED_PARAM) bb_show_usage(); /* Will complain and die if username not found */ - puts(bb_getpwuid(NULL, -1, geteuid())); + puts(xuid2uname(geteuid())); return fflush(stdout); } diff --git a/release/src/router/busybox/debianutils/Config.in b/release/src/router/busybox/debianutils/Config.in index 4ed00ddfa0..8deb38f373 100644 --- a/release/src/router/busybox/debianutils/Config.in +++ b/release/src/router/busybox/debianutils/Config.in @@ -64,6 +64,7 @@ config FEATURE_START_STOP_DAEMON_FANCY Support additional arguments. -o|--oknodo ignored since we exit with 0 anyway -v|--verbose + -N|--nicelevel N config FEATURE_START_STOP_DAEMON_LONG_OPTIONS bool "Enable long options" diff --git a/release/src/router/busybox/debianutils/run_parts.c b/release/src/router/busybox/debianutils/run_parts.c index a58fab3a55..7c38fa11f9 100644 --- a/release/src/router/busybox/debianutils/run_parts.c +++ b/release/src/router/busybox/debianutils/run_parts.c @@ -2,7 +2,7 @@ /* * Mini run-parts implementation for busybox * - * Copyright (C) 2007 Bernhard Fischer + * Copyright (C) 2007 Bernhard Reutner-Fischer * * Based on a older version that was in busybox which was 1k big.. * Copyright (C) 2001 by Emanuele Aina diff --git a/release/src/router/busybox/debianutils/start_stop_daemon.c b/release/src/router/busybox/debianutils/start_stop_daemon.c index 875eca511e..ab607bde0b 100644 --- a/release/src/router/busybox/debianutils/start_stop_daemon.c +++ b/release/src/router/busybox/debianutils/start_stop_daemon.c @@ -349,11 +349,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa" USE_FEATURE_START_STOP_DAEMON_FANCY("q-v"); opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:" - USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:"), -// USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"), + USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"), &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) -// USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg) + /* We accept and ignore -R / --retry */ + USE_FEATURE_START_STOP_DAEMON_FANCY(,NULL) ); if (opt & OPT_s) { @@ -428,7 +428,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) write_pidfile(pidfile); } if (opt & OPT_c) { - struct bb_uidgid_t ugid; + 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); diff --git a/release/src/router/busybox/docs/Serial-Programming-HOWTO.txt b/release/src/router/busybox/docs/Serial-Programming-HOWTO.txt new file mode 100644 index 0000000000..0dfc8aa31b --- /dev/null +++ b/release/src/router/busybox/docs/Serial-Programming-HOWTO.txt @@ -0,0 +1,424 @@ +Downloaded from http://www.lafn.org/~dave/linux/Serial-Programming-HOWTO.txt +Seems to be somewhat old, but contains useful bits for getty.c hacking +============================================================================ + + The Linux Serial Programming HOWTO, Part 1 of 2 + By Vernon C. Hoxie + v2.0 10 September 1999 + + This document describes how to program communications with devices + over a serial port on a Linux box. + ______________________________________________________________________ + + Table of Contents + + 1. Copyright + + 2. Introduction + + 3. Opening + + 4. Commands + + 5. Changing Baud Rates + + 6. Additional Control Calls + + 6.1 Sending a "break". + 6.2 Hardware flow control. + 6.3 Flushing I/O buffers. + + 7. Modem control + + 8. Process Groups + + 8.1 Sessions + 8.2 Process Groups + 8.3 Controlling Terminal + 8.3.1 Get the foreground group process id. + 8.3.2 Set the foreground process group id of a terminal. + 8.3.3 Get process group id. + + 9. Lockfiles + + 10. Additional Information + + 11. Feedback + + ______________________________________________________________________ + + 1. Copyright + + The Linux Serial-Programming-HOWTO is copyright (C) 1997 by Vernon + Hoxie. Linux HOWTO documents may be reproduced and distributed in + whole or in part, in any medium physical or electronic, as long as + this copyright notice is retained on all copies. Commercial + redistribution is allowed and encouraged; however, the author would + like to be notified of any such distributions. + + All translations, derivative works, or aggregate works incorporating + this Linux HOWTO document must be covered under this copyright notice. + That is, you may not produce a derivative work from this HOWTO and + impose additional restrictions on its distribution. + + This version is a complete rewrite of the previous Serial-Programming- + HOWTO by Peter H. Baumann, + + 2. Introduction + + This HOWTO will attempt to give hints about how to write a program + which needs to access a serial port. Its principal focus will be on + the Linux implementation and what the meaning of the various library + functions available. + + Someone asked about which of several sequences of operations was + right. There is no absolute right way to accomplish an outcome. The + options available are too numerous. If your sequences produces the + desired results, then that is the right way for you. Another + programmer may select another set of options and get the same results. + His method is right for him. + + Neither of these methods may operate properly with some other + implementation of UNIX. It is strange that many of the concepts which + were implemented in the SYSV version have been dumped. Because UNIX + was developed by AT&T and much code has been generated on those + concepts, the AT&T version should be the standard to which others + should emulate. + + Now the standard is POSIX. + + It was once stated that the popularity of UNIX and C was that they + were created by programmers for programmers. Not by scholars who + insist on purity of style in deference to results and simplicity of + use. Not by committees with people who have diverse personal or + proprietary agenda. Now ANSI and POSIX have strayed from those + original clear and simply concepts. + + 3. Opening + + The various serial devices are opened just as any other file. + Although, the fopen(3) command may be used, the plain open(2) is + preferred. This call returns the file descriptor which is required + for the various commands that configure the interface. + + Open(2) has the format: + + #include + int open(char *path, int flags, [int mode]); + + In addition to the obvious O_RDWR, O_WRONLY and O_RDONLY, two + additional flags are available. These are O_NONBLOCK and O_NOCTTY. + Other flags listed in the open(2) manual page are not applicable to + serial devices. + + Normally, a serial device opens in "blocking" mode. This means that + the open() will not return until the Carrier Detect line from the port + is active, e.g. modem, is active. When opened with the O_NONBLOCK + flag set, the open() will return immediately regardless of the status + of the DCD line. The "blocking" mode also affects the read() call. + + The fcntl(2) command can be used to change the O_NONBLOCK flag anytime + after the device has been opened. + + The device driver and the data passing through it are controlled + according to settings in the struct termios. This structure is + defined in "/usr/include/termios.h". In the Linux tree, further + reference is made to "/usr/include/asm/termbits.h". + In blocking mode, a read(2) will block until data is available or a + signal is received. It is still subject to state of the ICANON flag. + + When the termios.c_lflag ICANON bit is set, input data is collected + into strings until a NL, EOF or EOL character is received. You can + define these in the termios.c_cc[] array. Also, ERASE and KILL + characters will operate on the incoming data before it is delivered to + the user. + + In non-canonical mode, incoming data is quanitified by use of the + c_cc[VMIN and c_cc[VTIME] values in termios.c_cc[]. + + Some programmers use the select() call to detect the completion of a + read(). This is not the best way of checking for incoming data. + Select() is part of the SOCKETS scheme and too complex for most + applications. + + A full explanation of the fields of the termios structure is contained + in termios(7) of the Users Manual. A version is included in Part 2 of + this HOWTO document. + + 4. Commands + + Changes to the struct termios are made by retrieving the current + settings, making the desired changes and transmitting the modified + structure back to the kernel. + + The historic means of communicating with the kernel was by use of the + ioctl(fd, COMMAND, arg) system call. Then the purists in the + computer industry decided that this was not genetically consistent. + Their argument was that the argument changed its stripes. Sometimes + it was an int, sometimes it was a pointer to int and other times it + was a pointer to struct termios. Then there were those times it was + empty or NULL. These variations are dependent upon the COMMAND. + + As a alternative, the tc* series of functions were concocted. + + These are: + + int tcgetattr(int filedes, struct termios *termios_p); + int tcsetattr(int filedes, int optional_actions, + const struct termios *termios_p); + + instead of: + + int ioctl(int filedes, int command, + struct termios *termios_p); + + where command is TCGETS or one of TCSETS, TCSETSW or TCSETSF. + + The TCSETS command is comparable to the TCSANOW optional_action for + the tc* version. These direct the kernel to adopt the changes + immediately. Other pairs are: + + command optional_action Meaning + TCSETSW TCSADRAIN Change after all output has drained. + TCSETSF TCSAFLUSH Change after all output has drained + then discard any input characters + not read. + + Since the return code from either the ioctl(2) or the tcsetattr(2) + commands only indicate that the command was processed by the kernel. + These do not indicate whether or not the changes were actually + accomplished. Either of these commands should be followed by a call + to: + + ioctl(fd, TCGETS, &new_termios); + + or: + + tcgetattr(fd, &new_termios); + + A user function which makes changes to the termios structure should + define two struct termios variables. One of these variables should + contain the desired configuration. The other should contain a copy of + the kernels version. Then after the desired configuration has been + sent to the kernel, another call should be made to retrieve the + kernels version. Then the two compared. + + Here is an example of how to add RTS/CTS flow control: + + struct termios my_termios; + struct termios new_termios; + + tcgetattr(fd, &my_termios); + my_termios.c_flag |= CRTSCTS; + tcsetattr(fd, TCSANOW, &my_termios); + tcgetattr(fd, &new_termios); + if (memcmp(my_termios, new_termios, + sizeof(my_termios)) != 0) { + /* do some error handling */ + } + + 5. Changing Baud Rates + + With Linux, the baud rate can be changed using a technique similar to + add/delete RTS/CTS. + + struct termios my_termios; + struct termios new_termios; + + tcgetattr(fd, &my_termios); + my_termios.c_flag &= ~CBAUD; + my_termios.c_flag |= B19200; + tcsetattr(fd, TCSANOW, &my_termios); + tcgetattr(fd, &new_termios); + if (memcmp(my_termios, new_termios, + sizeof(my_termios)) != 0) { + /* do some error handling */ + } + + POSIX adds another method. They define: + + speed_t cfgetispeed(const struct termios *termios_p); + speed_t cfgetospeed(const struct termios *termios_p); + + library calls to extract the current input or output speed from the + struct termios pointed to with *termio_p. This is a variable defined + in the calling process. In practice, the data contained in this + termios, should be obtained by the tcgetattr() call or an ioctl() call + using the TCGETS command. + + The companion library calls are: + + int cfsetispeed(struct termios *termios_p, speed_t speed); + int cfsetospeed(struct termios *termios_p, speed_t speed); + + which are used to change the value of the baud rate in the locally + defined *termios_p. Following either of these calls, either a call to + tcsetattr() or ioctl() with one of TCSETS, TCSETSW or TCSETSF as the + command to transmit the change to the kernel. + + The cf* commands are preferred for portability. Some weird Unices use + a considerably different format of termios. + + Most implementations of Linux use only the input speed for both input + and output. These functions are defined in the application program by + reference to . In reality, they are in + /usr/include/asm/termbits.h. + + 6. Additional Control Calls + + 6.1. Sending a "break". + + int ioctl(fd, TCSBRK, int arg); + int tcsendbreak(fd, int arg); + + Send a break: Here the action differs between the conventional + ioctl() call and the POSIX call. For the conventional call, an arg of + '0' sets the break control line of the UART for 0.25 seconds. For the + POSIX command, the break line is set for arg times 0.1 seconds. + + 6.2. Hardware flow control. + + int ioctl(fd, TCXONC, int action); + int tcflow(fd, int action); + + The action flags are: + + o TCOOFF 0 suspend output + + o TCOON 1 restart output + + o TCIOFF 2 transmit STOP character to suspend input + + o TCION 3 transmit START character to restart input + + 6.3. Flushing I/O buffers. + + int ioctl(fd, TCFLSH, queue_selector); + int tcflush(fd, queue_selector); + + The queue_selector flags are: + + o TCIFLUSH 0 flush any data not yet read from the input buffer + + o TCOFLUSH 1 flush any data written to the output buffer but not + yet transmitted + + o TCIOFLUSH 2 flush both buffers + + 7. Modem control + + The hardware modem control lines can be monitored or modified by the + ioctl(2) system call. A set of comparable tc* calls apparently do not + exist. The form of this call is: + + int ioctl(fd, COMMAND, (int *)flags); + + The COMMANDS and their action are: + + o TIOCMBIS turn on control lines depending upon which bits are set + in flags. + + o TIOCMBIC turn off control lines depending upon which bits are + unset in flags. + o TIOCMGET the appropriate bits are set in flags according to the + current status + + o TIOCMSET the state of the UART is changed according to which bits + are set/unset in 'flags' + + The bit pattern of flags refer to the following control lines: + + o TIOCM_LE Line enable + + o TIOCM_DTR Data Terminal Ready + + o TIOCM_RTS Request to send + + o TIOCM_ST Secondary transmit + + o TIOCM_SR Secondary receive + + o TIOCM_CTS Clear to send + + o TIOCM_CAR Carrier detect + + o TIOCM_RNG Ring + + o TIOCM_DSR Data set ready + + It should be noted that some of these bits are controlled by the modem + and the UART cannot change them but their status can be sensed by + TIOCMGET. Also, most Personal Computers do not provide hardware for + secondary transmit and receive. + + There are also a pair of ioctl() to monitor these lines. They are + undocumented as far as I have learned. The commands are TIOCMIWAIT + and TCIOGICOUNT. They also differ between versions of the Linux + kernel. + + See the lines.c file in my "serial_suite" for an example of how these + can be used see + + 8. Process Groups + + 8.1. Sessions + + 8.2. Process Groups + + Any newly created process inherits the Process Group of its creator. + The Process Group leader has the same PID as PGID. + + 8.3. Controlling Terminal + + There are a series of ioctl(2) and tc*(2) calls which can be used to + monitor or to change the process group to which the device is + attached. + + 8.3.1. Get the foreground group process id. + + If there is no foreground group, a number not representing an existing + process group is returned. On error, a -1 is returned and errno is + set. + + int ioctl(fd, TIOCGPGRP, (pid_t *)pid); + int tcgetpgrp(fd, (pid_t *)pid); + + 8.3.2. Set the foreground process group id of a terminal. + + The fd must be the controlling terminal and be associated with the + session of the calling process. + + int ioctl(fd, TIOCSPGRP, (pid_t *)pid); + int tcsetpgrp(fd, (pid_t *)pid); + + 8.3.3. Get process group id. + + int ioctl(fd, TIOCGPGRP, &(pid_t)pid); + int tcgetpgrp(fd, &(pid_t)pid); + + 9. Lockfiles + + Any process which accesses a serial device should first check for the + existence of lock file for the desired device. If such a lock lock + file exists, this means that the device may be in use by another + process. + + Check my "libdevlocks-x.x.tgz" at + for an example of how these lock + files should be utilized. + + 10. Additional Information + + Check out my "serial_suite.tgz" for more information about programming + the serial ports at . There some + examples and some blurbs about setting up modems and comments about + some general considerations. + + 11. Feedback + + Please send me any corrections, questions, comments, suggestions, or + additional material. I would like to improve this HOWTO! Tell me + exactly what you don't understand, or what could be clearer. You can + reach me at via email. Please + include the version number of the Serial-Programming-HOWTO when + writing. diff --git a/release/src/router/busybox/docs/autodocifier.pl b/release/src/router/busybox/docs/autodocifier.pl index 68b6f3c058..576e31281c 100755 --- a/release/src/router/busybox/docs/autodocifier.pl +++ b/release/src/router/busybox/docs/autodocifier.pl @@ -1,4 +1,5 @@ #!/usr/bin/perl -w +# vi: set sw=4 ts=4: use strict; use Getopt::Long; @@ -36,6 +37,7 @@ sub beautify { s/"\s*$//; s/%/%%/g; s/\$/\\\$/g; + s/\@/\\\@/g; eval qq[ sprintf(qq{$_}) ] } @line ); @@ -48,11 +50,13 @@ sub pod_for_usage { my $usage = shift; # Sigh. Fixup the known odd-name applets. +# Perhaps we can use some of APPLET_ODDNAME from include/applets.h ? $name =~ s/dpkg_deb/dpkg-deb/g; $name =~ s/fsck_minix/fsck.minix/g; $name =~ s/mkfs_minix/mkfs.minix/g; $name =~ s/run_parts/run-parts/g; $name =~ s/start_stop_daemon/start-stop-daemon/g; + $name =~ s/ether_wake/ether-wake/g; # make options bold my $trivial = $usage->{trivial}; diff --git a/release/src/router/busybox/docs/busybox.net/FAQ.html b/release/src/router/busybox/docs/busybox.net/FAQ.html index e0a7597813..7ed1394ce3 100644 --- a/release/src/router/busybox/docs/busybox.net/FAQ.html +++ b/release/src/router/busybox/docs/busybox.net/FAQ.html @@ -16,7 +16,7 @@ have additions to this FAQ document, we would love to add them,
  • Which architectures does BusyBox run on?
  • Which C libraries are supported?
  • Can I include BusyBox as part of the software on my device?
  • -
  • Where can I find other small utilities since busybox does not include the features I want?
  • +
  • Where can I find other small utilities since busybox does not include the features I want?
  • I demand that you to add <favorite feature> right now! How come you don't answer all my questions on the mailing list instantly? I demand that you help me with all of my problems Right Now!
  • I need help with BusyBox! What should I do?
  • I need you to add <favorite feature>! Are the BusyBox developers willing to be paid in order to fix bugs or add in <favorite feature>? Are you willing to provide support contracts?
  • @@ -40,25 +40,26 @@ have additions to this FAQ document, we would love to add them,
    1. What are the goals of busybox?
    2. What is the design of busybox?
    3. -
    4. How is the source code organized?
    5. - +
    6. I want to make busybox even smaller, how do I go about it?
    7. Adding an applet to busybox
    8. What standards does busybox adhere to?
    9. Portability.
    10. -
    11. Tips and tricks.
    12. - + + +
    13. Who are the BusyBox developers?
    @@ -179,12 +180,19 @@ within each applet. More build coverage testing.

    during compilation. Only gcc and related binutils executables are prefixed with $(CROSS_COMPILE) in the makefiles. CROSS_COMPILE can be set on the command line: +

        make CROSS_COMPILE=arm-linux-uclibcgnueabi-
     
    +

    Alternatively CROSS_COMPILE can be set in the environment. Default value for CROSS_COMPILE is not to prefix executables.

    +

    + To store the cross-compiler in your .config, set the variable + CONFIG_CROSS_COMPILER_PREFIX accordingly in menuconfig or by + editing the .config file. +


    How do I build a BusyBox-based system?

    @@ -207,7 +215,7 @@ within each applet. More build coverage testing.

    To learn how to build a working Linux system entirely from source code, - the place to go is the Linux + the place to go is the Linux From Scratch project. They have an entire book of step-by-step instructions you can read online @@ -222,7 +230,7 @@ within each applet. More build coverage testing.

    If you want an automated yet customizable system builder which produces a BusyBox and uClibc based system, try - buildroot, which is + buildroot, which is another project by the maintainer of the uClibc (Erik Andersen). Download the tarball, extract it, unset CC, make. For more instructions, see the website. @@ -308,9 +316,10 @@ within each applet. More build coverage testing.

    BusyBox mailing list at busybox@busybox.net.

    In addition to the mailing list, Erik Andersen (andersee), Manuel Nova - (mjn3), Rob Landley (landley), Mike Frysinger (SpanKY), Bernhard Fischer - (blindvt), and other long-time BusyBox developers are known to hang out - on the uClibc IRC channel: #uclibc on irc.freenode.net. There is a + (mjn3), Rob Landley (landley), Mike Frysinger (SpanKY), + Bernhard Reutner-Fischer (blindvt), and other long-time BusyBox developers + are known to hang out on the uClibc IRC channel: #uclibc on + irc.freenode.net. There is a web archive of daily logs of the #uclibc IRC channel going back to 2002.

    @@ -339,16 +348,6 @@ within each applet. More build coverage testing.

    maintainer and ask them to recommend someone.

    -

    If you prefer to deal with an organization rather than an individual, Rob - Landley (the current BusyBox maintainer) works for - TimeSys, and Eric Andersen (the previous - busybox maintainer and current uClibc maintainer) owns - CodePoet Consulting. Both - companies offer support contracts and handle new development, and there - are plenty of other companies that do the same. -

    - -

    Troubleshooting

    @@ -358,7 +357,7 @@ within each applet. More build coverage testing.

    If you simply need help with using or configuring BusyBox, please submit a detailed description of your problem to the BusyBox mailing list at busybox@busybox.net. + href="mailto:busybox@busybox.net">busybox@busybox.net. Please do not send email to individual developers asking for private help unless you are planning on paying for consulting services. When we answer questions on the BusyBox mailing list, it helps everyone, @@ -371,7 +370,7 @@ within each applet. More build coverage testing.

    only so much they can keep in their brains at a time. You can post a polite reminder after 2-3 days without offending anybody. If that doesn't result in a solution, please use the - BusyBox Bug + BusyBox Bug and Patch Tracking System to submit a detailed explanation and we'll get to it as soon as we can.

    @@ -386,7 +385,7 @@ within each applet. More build coverage testing.


    -

    I'm using an ancient version from the dawn of time and something's broken. Can you backport fixes for free?

    +

    I'm using an ancient version from the dawn of time and something's broken. Can you backport fixes for free?

    Variants of this one get asked a lot.

    @@ -395,7 +394,7 @@ and we're happy to respond to our users' needs. But if you're coming to the list for free tech support we're going to ask you to upgrade to a current version before we try to diagnose your problem.

    -

    If you're building BusyBox 0.50 with uClibc 0.9.19 and gcc 0.9.26 there's a +

    If you're building BusyBox 0.50 with uClibc 0.9.19 and gcc 1.27 there's a fairly large chance that whatever problem you're seeing has already been fixed. To get that fix, all you have to do is upgrade to a newer version. If you don't at least _try_ that, you're wasting our time.

    @@ -509,7 +508,7 @@ int main(int argc, char *argv)

    How do I change the time zone in busybox?

    Busybox has nothing to do with the timezone. Please consult your libc -documentation. (http://google.com/search?q=uclibc+glibc+timezone).

    +documentation. (http://google.com/search?q=uclibc+glibc+timezone).


    Development

    @@ -785,9 +784,9 @@ successor to ibcs2: the 86open project. That project disbanded in 1999 with the endorsement of an existing standard: Linux ELF binaries. Since then, the major players at the time (such as AIX, Solaris, and -FreeBSD) +href="http://www-03.ibm.com/servers/aix/products/aixos/linux/index.html">AIX, Solaris, and +FreeBSD) have all either grown Linux support or folded.

    The major exceptions are newcomer MacOS X, some embedded environments @@ -810,7 +809,7 @@ file is at least worth a look. Special-case code in the body of an applet is something we're trying to avoid.


    -

    Programming tips and tricks.

    +

    Programming tips and tricks.

    Various things busybox uses that aren't particularly well documented elsewhere.

    @@ -1048,7 +1047,8 @@ to measure).


    Including kernel headers

    -

    The "linux" or "asm" directories of /usr/include contain Linux kernel +

    The "linux" or "asm" directories of /usr/include +contain Linux kernel headers, so that the C library can talk directly to the Linux kernel. In a perfect world, applications shouldn't include these headers directly, but we don't live in a perfect world.

    @@ -1058,7 +1058,7 @@ we don't live in a perfect world.

    Attempts to cut and paste the information into a local busybox header file proved incredibly painful, because portions of the loop_info structure vary by architecture, namely the type __kernel_dev_t has different sizes on alpha, -arm, x86, and so on. Meaning we either #include or +arm, x86, and so on. Meaning we either #include <linux/posix_types.h> or we hardwire #ifdefs to check what platform we're building on and define this type appropriately for every single hardware architecture supported by Linux, which is simply unworkable.

    @@ -1066,7 +1066,8 @@ Linux, which is simply unworkable.

    This is aside from the fact that the relevant type defined in posix_types.h was renamed to __kernel_old_dev_t during the 2.5 series, so to cut and paste the structure into our header we have to #include - to figure out which name to use. (What we actually do is +<linux/version.h> to figure out which name to use. (What we actually +do is check if we're building on 2.6, and if so just use the new 64 bit structure instead to avoid the rename entirely.) But we still need the version check, since 2.4 didn't have the 64 bit structure.

    @@ -1075,8 +1076,9 @@ check, since 2.4 didn't have the 64 bit structure.

    out a clean way to do all this. There isn't one. The losetup in the util-linux package from kernel.org isn't doing it cleanly either, they just hide the ugliness by nesting #include files. Their mount/loop.h -#includes "my_dev_t.h", which #includes and - just like we do. There simply is no alternative.

    +#includes "my_dev_t.h", which #includes <linux/posix_types.h> +and <linux/version.h> just like we do. There simply is no alternative. +

    Just because directly #including kernel headers is sometimes unavoidable doesn't me we should include them when there's a better @@ -1087,18 +1089,18 @@ is not a better way.

    Who are the BusyBox developers?

    The following login accounts currently exist on busybox.net. (I.E. these -people can commit patches +people can commit patches into subversion for the BusyBox, uClibc, and buildroot projects.)

    -aldot     :Bernhard Fischer
    +aldot     :Bernhard Reutner-Fischer
     andersen  :Erik Andersen      - uClibc and BuildRoot maintainer.
     bug1      :Glenn McGrath
     davidm    :David McCullough
     gkajmowi  :Garrett Kajmowicz  - uClibc++ maintainer
     jbglaw    :Jan-Benedict Glaw
     jocke     :Joakim Tjernlund
    -landley   :Rob Landley        - BusyBox maintainer
    +landley   :Rob Landley
     lethal    :Paul Mundt
     mjn3      :Manuel Novoa III
     osuadmin  :osuadmin
    @@ -1113,11 +1115,12 @@ solar     :Ned Ludd
     timr      :Tim Riker
     tobiasa   :Tobias Anderberg
     vapier    :Mike Frysinger
    +vda       :Denys Vlasenko     - BusyBox maintainer
     

    The following accounts used to exist on busybox.net, but don't anymore so -I can't ask /etc/passwd for their names. Rob Wentworth -asked Google and recovered the names:

    +I can't ask /etc/passwd for their names. Rob Wentworth +<robwen at gmail.com> asked Google and recovered the names:

     aaronl   :Aaron Lehmann
    diff --git a/release/src/router/busybox/docs/busybox.net/about.html b/release/src/router/busybox/docs/busybox.net/about.html
    index 7b79afce9f..35809c3154 100644
    --- a/release/src/router/busybox/docs/busybox.net/about.html
    +++ b/release/src/router/busybox/docs/busybox.net/about.html
    @@ -18,7 +18,7 @@ nodes in /dev, a few configuration files in /etc, and a Linux kernel.

    BusyBox is maintained by Denys Vlasenko, -and licensed under the GNU GENERAL PUBLIC LICENSE +and licensed under the GNU GENERAL PUBLIC LICENSE version 2.

    diff --git a/release/src/router/busybox/docs/busybox.net/download.html b/release/src/router/busybox/docs/busybox.net/download.html index b0bd6e3715..34195b6f16 100644 --- a/release/src/router/busybox/docs/busybox.net/download.html +++ b/release/src/router/busybox/docs/busybox.net/download.html @@ -14,29 +14,29 @@ Also there are patches on top of latest bug fix release.

    Latest releases and patch directories for each branch:
    -1.10.1, -patches, +1.10.1, +patches,
    -1.9.2, -patches, +1.9.2, +patches,
    -1.8.3, -patches, +1.8.3, +patches,
    -1.7.5, -patches, +1.7.5, +patches,
    -1.6.2, -patches, +1.6.2, +patches,
    -1.5.2, -patches, +1.5.2, +patches,
    -1.4.2, -patches, +1.4.2, +patches,
    -1.3.2, -patches. +1.3.2, +patches.

    You can also obtain Daily Snapshots of @@ -44,7 +44,7 @@ the latest development source tree for those wishing to follow BusyBox developme but cannot or do not wish to use Subversion (svn).

      -
    • Click here to browse the source tree. +
    • Click here to browse the source tree.
    • Anonymous Subversion access is available. diff --git a/release/src/router/busybox/docs/busybox.net/fix.html b/release/src/router/busybox/docs/busybox.net/fix.html index 45621cde7f..7bd7fe0f47 100644 --- a/release/src/router/busybox/docs/busybox.net/fix.html +++ b/release/src/router/busybox/docs/busybox.net/fix.html @@ -5,7 +5,7 @@

      If you found a regression or severe bug in busybox, and you have a patch for it, and you want to see it added to "hot fixes", please rediff your patch against corresponding unmodified busybox source and send it to - the mailing list. + the mailing list.


      diff --git a/release/src/router/busybox/docs/busybox.net/footer.html b/release/src/router/busybox/docs/busybox.net/footer.html index 7f39ccb01a..0667092370 100644 --- a/release/src/router/busybox/docs/busybox.net/footer.html +++ b/release/src/router/busybox/docs/busybox.net/footer.html @@ -11,35 +11,39 @@ - +
      - - Copyright © 1999-2005 Erik Andersen + + + Copyright © 1999-2008 Erik Andersen
      Mail all comments, insults, suggestions and bribes to
      Denys Vlasenko vda.linux@googlemail.com
      +
      - This site created with the vi editor + alt="This site created with the vi editor" /> - This site is kindly hosted by OSL + alt="This site is kindly hosted by OSL" />
      diff --git a/release/src/router/busybox/docs/busybox.net/header.html b/release/src/router/busybox/docs/busybox.net/header.html index b83fdcb6a7..9641d8c1fb 100644 --- a/release/src/router/busybox/docs/busybox.net/header.html +++ b/release/src/router/busybox/docs/busybox.net/header.html @@ -8,6 +8,8 @@ body { background-color: #DEE2DE; color: #000000; + font-family: lucida, helvetica, arial; + font-size: 100%; } :link { color: #660000 } :visited { color: #660000 } @@ -18,14 +20,9 @@ - - - - + - -
      @@ -36,13 +33,13 @@
      - BusyBox
      + BusyBox
      - + About Development

      Links

        @@ -77,26 +74,18 @@

      Developer Pages

      - - - - - + diff --git a/release/src/router/busybox/docs/busybox.net/license.html b/release/src/router/busybox/docs/busybox.net/license.html index 76358bc65b..2a4c51d103 100644 --- a/release/src/router/busybox/docs/busybox.net/license.html +++ b/release/src/router/busybox/docs/busybox.net/license.html @@ -1,7 +1,7 @@

      -

      BusyBox is licensed under the GNU General Public License, version 2

      +

      BusyBox is licensed under the GNU General Public License, version 2

      BusyBox is licensed under the GNU General Public License version 2, which is often abbreviated as GPLv2. @@ -11,7 +11,7 @@ familiar with it by now.)

      A complete copy of the license text is included in the file LICENSE in the BusyBox source code.

      -

      Anyone thinking of shipping BusyBox as part of a +

      Anyone thinking of shipping BusyBox as part of a product should be familiar with the licensing terms under which they are allowed to use and distribute BusyBox. Read the full test of the GPL (either through the above link, or in the file LICENSE in the busybox tarball), and @@ -25,17 +25,18 @@ you violate the license terms, and thus infringe on the copyrights of BusyBox. (This requirement applies whether or not you modified BusyBox; either way the license terms still apply to you.) Read the license text for the details.

      -

      A note on GPL versions

      +

      A note on GPL versions

      Version 2 of the GPL is the only version of the GPL which current versions of BusyBox may be distributed under. New code added to the tree is licensed GPL version 2, and the project's license is GPL version 2.

      Older versions of BusyBox (versions 1.2.2 and earlier, up through about svn -16112) included variants of the recommended "GPL version 2 or (at your option) -later versions" boilerplate permission grant. Ancient versions of BusyBox +16112) included variants of the recommended +"GPL version 2 or (at your option) later versions" boilerplate +permission grant. Ancient versions of BusyBox (before svn 49) did not specify any version at all, and section 9 of GPLv2 -(the most recent version at the time) says those old versions may be +(the most recent version at that time) says those old versions may be redistributed under any version of GPL (including the obsolete V1). This was conceptually similar to a dual license, except that the different licenses were different versions of the GPL.

      @@ -43,7 +44,8 @@ different versions of the GPL.

      However, BusyBox has apparently always contained chunks of code that were licensed under GPL version 2 only. Examples include applets written by Linus Torvalds (util-linux/mkfs_minix.c and util_linux/mkswap.c) which stated they -"may be redistributed as per the Linux copyright" (which Linus clarified in the +"may be redistributed as per the Linux copyright" (which Linus +clarified in the 2.4.0-pre8 release announcement in 2000 was GPLv2 only), and Linux kernel code copied into libbb/loop.c (after Linus's announcement). There are probably more, because all we used to check was that the code was GPL, not which @@ -59,18 +61,18 @@ versions such as release 1.2.2 or SVN 16112, and do your own homework to identify and remove any code that can't be licensed under the GPL version you want to use. New development is all GPLv2.

      -

      License enforcement

      +

      License enforcement

      BusyBox's copyrights are enforced by the Software Freedom Law Center +href="http://www.softwarefreedom.org/">Software Freedom Law Center (you can contact them at gpl@busybox.net), which -"accepts primary responsibility for enforcement of US copyrights on the +"accepts primary responsibility for enforcement of US copyrights on the software... and coordinates international copyright enforcement efforts for -such works as necessary." If you distribute BusyBox in a way that doesn't +such works as necessary." If you distribute BusyBox in a way that doesn't comply with the terms of the license BusyBox is distributed under, expect to hear from these guys. Their entire reason for existing is to do pro-bono legal work for free/open source software projects. (We used to list people who -violate the BusyBox license in The Hall of Shame, +violate the BusyBox license in The Hall of Shame, but these days we find it much more effective to hand them over to the lawyers.)

      @@ -82,13 +84,13 @@ don't want monetary awards, injunctions, or to generate bad PR for a company, unless that's the only way to get somebody that repeatedly ignores us to comply with the license on our code.

      -

      A Good Example

      +

      A Good Example

      These days, Linksys is doing a good job at complying with the GPL, they get to be an example of how to do things right. Please take a moment and check out what they do with - + distributing the firmware for their WRT54G Router. Following their example would be a fine way to ensure that you have also fulfilled your licensing obligations.

      diff --git a/release/src/router/busybox/docs/busybox.net/links.html b/release/src/router/busybox/docs/busybox.net/links.html index 9cdbd7c8ce..14ad8d12ab 100644 --- a/release/src/router/busybox/docs/busybox.net/links.html +++ b/release/src/router/busybox/docs/busybox.net/links.html @@ -4,12 +4,12 @@
      uClibc.org
      uClibc++ -
      udhcp +
      buildroot
      Scratchbox
      OpenEmbedded
      uCdot -
      LinuxDevices +
      LinuxDevices
      Slashdot
      Freshmeat
      Linux Today diff --git a/release/src/router/busybox/docs/busybox.net/lists.html b/release/src/router/busybox/docs/busybox.net/lists.html index 3a28cc07e7..29c2f7472d 100644 --- a/release/src/router/busybox/docs/busybox.net/lists.html +++ b/release/src/router/busybox/docs/busybox.net/lists.html @@ -6,7 +6,7 @@

      Mailing List Information

      BusyBox has a mailing list for discussion and development. You can subscribe by visiting -this page. +this page. Only subscribers to the BusyBox mailing list are allowed to post to this list. @@ -14,7 +14,7 @@ to this list. There is also a mailing list for active developers wishing to read the complete diff of each and every change to busybox -- not for the faint of heart. Active developers can subscribe by visiting -this page. +this page. The Subversion server is the only one permtted to post to this list. And yes, this list name uses the word 'cvs' even though we don't use that anymore... diff --git a/release/src/router/busybox/docs/busybox.net/news.html b/release/src/router/busybox/docs/busybox.net/news.html dissimilarity index 93% index 74b0eb3381..8f756f088e 100644 --- a/release/src/router/busybox/docs/busybox.net/news.html +++ b/release/src/router/busybox/docs/busybox.net/news.html @@ -1,303 +1,517 @@ - - -
        -
      • 12 July 2008 -- BusyBox 1.11.1 (stable) -

        BusyBox 1.11.1. - (svn, - patches, - how to add a patch)

        -

        - Bugfix-only release for 1.11.x branch. It contains fixes for awk, - bunzip2, cpio, ifupdown, ip, man, start-stop-daemon, uname and vi. -

        - -
      • 11 July 2008 -- HOWTO is updated -

        - - "How to build static busybox for i486-linux-uclibc" is updated - and tested on a fresh Fedora 9 install. Please report if it doesn't - work for you. -

        - -
      • 25 June 2008 -- BusyBox 1.11.0 (unstable), BusyBox 1.10.4 (stable) -

        BusyBox 1.11.0. - (svn, - patches, - how to add a patch)

        -

        BusyBox 1.10.4. - (svn, - patches, - how to add a patch)

        -

        Sizes of busybox-1.10.4 and busybox-1.11.0 (with equivalent config, static uclibc build):

        -   text    data     bss     dec     hex filename
        - 800675     636    7080  808391   c55c7 busybox-1.10.4
        - 798392     611    6900  805903   c4c0f busybox-1.11.0
        -
        - -

        New applets: inotify (Vladimir Dronnikov), man (Ivana Varekova), - fbsplash (Michele Sanges), depmod (Bernhard Fischer) - -

        Changes since previous release: -

          -
        • build system: reinstate CONFIG_CROSS_COMPILE_PREFIX -
        • ash: optional bash compatibility features added; other fixes -
        • hush: lots and lots of fixes -
        • msh: fix the case where the file has exec bit but can't be run directly (runs "$SHELL file" instead) -
        • msh: fix exit codes when command is not found or can't be execed -
        • udhcpc: added workaround for buggy kernels -
        • mount: fix mishandling of proto=tcp/udp -
        • diff: make it work on non-seekable streams -
        • openvt: made more compatible with "standard" one -
        • mdev: fix block/char device detection -
        • ping: add -w, -W support (James Simmons) -
        • crond: add handling of "MAILTO=user" lines -
        • start-stop-daemon: make --exec follow symlinks (Joakim Tjernlund) -
        • date: make it accept ISO date format -
        • echo: fix echo -e -n "msg\n\0" (David Pinedo) -
        • httpd: fix several bugs triggered by relative path in -h DIR -
        • printf: fix printf -%s- foo, printf -- -%s- foo -
        • syslogd: do not error out on missing files to rotate -
        • ls: support Unicode in names -
        • ip: support for the LOWER_UP flag (Natanael Copa) -
        • mktemp: make argument optional (coreutil 6.12 compat) -
        • libiproute: fix option parsing, so that "ip -o link" works again -
        • other fixes and code size reductions in many applets -
        -

        - The email address gpl@busybox.net is the recommended way to contact - the Software Freedom Law Center to report BusyBox license violations. -

        - -
      • 12 June 2008 -- Sponsors! -

        We want to thank the following companies which are providing support - for BusyBox project: -

        -

        - -
      • 5 June 2008 -- BusyBox 1.10.3 (stable) -

        BusyBox 1.10.3. - (svn, - patches, - how to add a patch)

        -

        - Bugfix-only release for 1.10.x branch. It contains fixes for dnsd, fuser, hush, - ip, mdev and syslogd. -

        - -
      • 8 May 2008 -- BusyBox 1.10.2 (stable) -

        BusyBox 1.10.2. - (svn, - patches, - how to add a patch)

        -

        - Bugfix-only release for 1.10.x branch. It contains fixes for echo, httpd, pidof, - start-stop-daemon, tar, taskset, tab completion in shells, build system. -

        Please note that mdev was backported from current svn trunk. Please - report if you encounter any problems with it. -

        - -
      • 19 April 2008 -- BusyBox 1.10.1 (stable) -

        BusyBox 1.10.1. - (svn, - patches, - how to add a patch)

        -

        - Bugfix-only release for 1.10.x branch. It contains fixes for - fuser, init, less, nameif, tail, taskset, tcpudp, top, udhcp. - -

      • 21 March 2008 -- BusyBox 1.10.0 (unstable) -

        BusyBox 1.10.0. - (svn, - patches, - how to add a patch)

        - -

        Sizes of busybox-1.9.2 and busybox-1.10.0 (with almost full config, static uclibc build):

        -   text    data     bss     dec     hex filename
        - 781405     679    7500  789584   c0c50 busybox-1.9.2
        - 773551     640    7372  781563   becfb busybox-1.10.0
        -
        -

        Top 10 stack users:

        -busybox-1.9.2:               busybox-1.10.0:
        -echo_dg                 4116 bb_full_fd_action       4112
        -bb_full_fd_action       4112 find_list_entry2        4096
        -discard_dg              4108 readlink_main           4096
        -discard_dg              4096 ipaddr_list_or_flush    3900
        -echo_stream             4096 iproute_list_or_flush   3680
        -discard_stream          4096 insmod_main             3152
        -find_list_entry2        4096 fallbackSort            2952
        -readlink_main           4096 do_iproute              2492
        -ipaddr_list_or_flush    3900 cal_main                2464
        -iproute_list_or_flush   3680 readhere                2308
        -
        - -

        New applets: brctl, chat (by Vladimir Dronnikov <dronnikov AT gmail.com>), - findfs, ifenslave (closes bug 115), lpd (by Vladimir Dronnikov <dronnikov AT gmail.com>), - lpr+lpq (by Walter Harms), script (by Pascal Bellard <pascal.bellard AT ads-lu.com>), - sendmail (Vladimir Dronnikov <dronnikov AT gmail.com>), tac, tftpd. - -

        Made NOMMU-compatible: crond, crontab, ifupdown, inetd, init, runsv, svlogd, tcpsvd, udpsvd. - -

        Changes since previous release: -

          -
        • globally: add -Wunused-parameter -
        • globally: add optimization barrier to all "G trick" locations -
        • adduser/addgroup: check username for invalid chars (by Tito <farmatito AT tiscali.it>) -
        • adduser: optional support for long options. Closes bug 2134 -
        • ash: handle "A=1 A=2 B=$A; echo $B". Closes bug 947 -
        • ash: make ash -c "if set -o barfoo 2>/dev/null; then echo foo; else echo bar; fi" work. Closes bug 1142 -
        • build system: don't use "gcc -o /dev/null", old gcc can delete /dev/null in this case -
        • build system: fixes for cross-compiling on an OS X host -
        • build system: make it do without "od -t" -
        • build system: pass CFLAGS to link stage too. Closes bug 1376 -
        • build system: add CONFIG_NOMMU -
        • cp: add ENABLE_FEATURE_VERBOSE_CP_MESSAGE. Closes bug 1470 -
        • crontab: almost complete rewrite -
        • dnsd: properly set _src_ IP:port on outgoing UDP packets -
        • dpkg: fix bug where existence check was reversed -
        • eject: add -s for SCSI- and USB-devices (Nico Erfurth) -
        • fdisk: fix a case where break was reached only for DOS labels -
        • fsck: don't kill pid -1! (Roy Marples <roy at marples.name>) -
        • fsck_minix: fix bug in map_block2: s/(blknr >= 256 * 256)/(blknr < 256 * 256)/ -
        • fuser: substantial rewrite -
        • getopt: add support for "a+" specifier for nonnegative int parameters. By Vladimir Dronnikov <dronnikov at gmail.com> -
        • getty: don't try to detect parity on local lines (Joakim Tjernlund <Joakim.Tjernlund at transmode.se>) -
        • halt: write wtmp entry if wtmp support is enabled -
        • httpd: "HEAD" support. Closes bug 1530 -
        • httpd: fix bug 2004: wrong argv when interpreter is invoked -
        • httpd: fix bug where we did chdir("") if CGI path had only one "/" -
        • httpd: fix for POST upload -
        • httpd: support for "I:index.xml" syntax (Peter Korsgaard <jacmet AT uclibc.org>) -
        • hush: fix a case where none of pipe members could be started because of fork failure -
        • hush: more correct handling of piping -
        • hush: reinstate `cmd` handling for NOMMU -
        • hush: report [v]fork failures -
        • hush: set CLOEXEC on script file being executed -
        • hush: try to add a bit more of vfork-friendliness -
        • inetd: make "udp nowait" work -
        • inetd: make inetd IPv6-capable -
        • init: add FEATURE_KILL_REMOVED (Eugene Bordenkircher <eugebo AT gmail.com>) -
        • init: allow last line of config file to be not terminated by "\n" -
        • init: do not die if "/dev/null" is missing -
        • init: fix bug 1111: restart actions were not splitting words -
        • init: wait for orphaned children too while waiting for sysinit-like processes (harald-tuxbox AT arcor.de) -
        • ip route: "ip route" was misbehaving (extra argv+1 ate 1st env var) -
        • last: do not go into endless loop on read error -
        • less,klogd,syslogd,nc,tcpudp: exit on signal by killing itself, not exit(1) -
        • less: "examine" command will not bomb out on bad file name now -
        • less: fix bug where backspace wasn't actually deleting chars -
        • less: make it a bit more resistant against status line corruption -
        • less: improve search when data is not supplied fast enough by stdin - now will try reading for 1-2 seconds before declaring that there is no match. This fixes a very common annoyance with long manpages -
        • less: update line input so that it doesn't interfere with screen update. Makes "man bash", [enter], [/], <enter search pattern>, [enter] more usable - manpage now draws even as you enter the pattern! -
        • libbb: filename completion matches dangling symlinks too -
        • libbb: fix getopt state corruption for NOFORK applets -
        • libbb: full_read/write now will report partial data counts prior to error -
        • libbb: intrduce and use safe_gethostname. By Tito <farmatito AT tiscali.it> -
        • libbb: introduce and use nonblock_safe_read(). Yay! Our shells are immune from this nasty O_NONBLOCK now! -
        • login,su: avoid clearing environment with some options, as was intended -
        • microcom: read more than 1 byte from device, if possible -
        • microcom: split -d (delay) option away from -t -
        • mktemp: support -p DIR (Timo Teras <timo.teras at iki.fi>) -
        • mount: #ifdef out MOUNT_LABEL code parts if it is not selected -
        • mount: add another mount helper call method -
        • mount: allow and ignore _netdev option -
        • mount: make -f work even without mtab support (Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn at axis.com>) -
        • mount: optional support for -vv verbosity -
        • mount: plug a hole where FEATURE_MOUNT_HELPERS could allow execution of arbitrary command -
        • mount: recognize "dirsync" (closes bug 835) -
        • mount: sanitize environment if called by non-root -
        • mount: support for mount by label. Closes bug 1143 -
        • mount: with -vv -f, say what mount() calls we were going to make -
        • msh: create testsuite (based on hush one) -
        • msh: don't use floating point in "times" builtin -
        • msh: fix Ctrl-C handling with line editing -
        • msh: fix for bug 846 ("break" didn't work second time) -
        • msh: glob0/glob1/glob2/glob3 were just a sorting routine, removed -
        • msh: instead of fixing "ls | cd", "cd | ls" etc disallow builtins in pipes. They make no sense there anyway -
        • msh: stop trying to parse variables in "msh SCRIPT VAR=val param". They are passed as ordinary parameters -
        • netstat: print control chars as "^C" etc -
        • nmeter: fix bug where %[mf] behaves as %[mt] -
        • nohup: compat patch by Christoph Gysin <mailinglist.cache at gmail.com> -
        • od: handle /proc files (which have filesize 0) correctly -
        • patch: don't trash permissions of patched file -
        • ps: add conditional support for -o [e]time -
        • ps: fix COMMAND column adjustment; overflow in USER and VSZ columns -
        • reset: call "stty sane". Closes bug 1414 -
        • rmdir: optional long options support for Debian users. By Roberto Gordo Saez <roberto.gordo AT gmail.com> -
        • run-parts: add --reverse -
        • script: correctly handle buffered "tail" of output -
        • sed: "n" command must reset "we had successful subst" flag. Closes bug 1214 -
        • sort: -z outputs NUL terminated lines. Closes bug 1591 -
        • stty: fix mishandling of control keywords (Ralf Friedl <Ralf.Friedl AT online.de>) -
        • switch_root: stop at first non-option. Closes bug 1425 -
        • syslogd: avoid excessive time() system calls -
        • syslogd: don't die if remote host's IP cannot be resolved. Retry resolutions every two minutes instead -
        • syslogd: fix shmat error check -
        • syslogd: optional support for dropping dups. Closes bug 436 -
        • syslogd: send "\n"-terminated messages over the network. Fully closes bug 1574 -
        • syslogd: tighten up hostname handling -
        • tail: fix "tail -c 20 /dev/huge_disk" (was taking ages) -
        • tar: compat: handle tarballs with only one zero block at the end -
        • tar: autodetection of gz/bz2 compressed tarballs. Closes bug 992 -
        • tar: real support for -p. By Natanael Copa <natanael.copa at gmail.com> -
        • tcpudp: narrow down time window where we have no wildcard socket -
        • telnetd: use login always, not "sometimes login, sometimes shell" -
        • test: fix mishandling of "test ! arg1 op arg2 more args" -
        • trylink: instead of build error, disable --gc-sections if GLIBC and STATIC are selected -
        • udhcp: make file paths configurable -
        • udhcp: optional support for non-standard DHCP ports -
        • udhcp: set correct op byte in the packet for DHCPDECLINE -
        • udhcpc: filter unwanted packets in kernel (Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn AT axis.com>) -
        • udhcpc: fix wrong options in decline and release packets (Jonas Danielsson <jonas.danielsson AT axis.com>) -
        • umount: do not complain several times about the same mountpoint -
        • umount: do not try to free loop device or erase mtab if remounted ro -
        • umount: instead of non-standard -D, use -d with opposite meaning. Closes bug 1604 -
        • unlzma: shrink by Pascal Bellard <pascal.bellard AT ads-lu.com> -
        • unzip: do not try to read entire compressed stream at once (it can be huge) -
        • unzip: handle short reads correctly -
        • vi: many fixes -
        • zcip: don't chdir to root -
        • zcip: open ARP socket before openlog (else we can trash syslog socket) -
        -

        - -
      • 21 March 2008 -- BusyBox old stable releases -

        - Bugfix-only releases for four past branches. Links to locations - for future hot patches are in parentheses. -

        - 1.9.2 - (patches), - 1.8.3 - (patches), - 1.7.5 - (patches), - 1.5.2 - (patches). -

        - How to add a patch. -

        - -
      • Old News

        - Click here to read older news -

        -
      • - - -
      - - - + + +
        + +
      • +

        We want to thank the following companies which are providing support for the BusyBox project: +

        +

        +
      • + +
      • 15 April 2009 -- BusyBox 1.14.0 (unstable), BusyBox 1.13.4 (stable) +

        BusyBox 1.14.0. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.13.4. + (svn, + patches, + how to add a patch)

        + +

        Sizes of busybox-1.13.4 and busybox-1.14.0 (with equivalent config, static uclibc build):

        +   text    data     bss     dec     hex filename
        + 785501     483    7036  793020   c19bc busybox.1.13.4/busybox
        + 788380     467    6960  795807   c249f busybox.1.14.0/busybox
        +  15361       0       0   15361    3c01 busybox.1.13.4/shell/hush.o
        +  20724       0       0   20724    50f4 busybox.1.14.0/shell/hush.o
        +
        +

        Most of growth is in hush. The rest shrank a bit. + +

        New applets: +

          +
        • flash_eraseall: by Sebastian Andrzej Siewior (bigeasy AT linutronix.de)
        • +
        • acpid,mkdosfs (aka mkfs.vfat),tunctl: by Vladimir
        • +
        • ftpd: by Adam Tkac
        • +
        • timeout: by Roberto Foglietta
        • +
        • ionice: adapted from Linux kernel' example by Walter Harms
        • +
        • mkpasswd: synonym to cryptpw. mkpasswd is in Debian, OTOH cryptpw was added to busybox earlier. Trying to make both camps happy by making those two applets just aliases. They are command-line compatible
        • +
        + +

        Changes since previous release: + +

        lash and msh are deprecated, please migrate to hush. + +

        hush had many, many fixes and features added: here documents, arithmetic evaluation, function support, and all this works on NOMMU too, safely: 100kb-sized `command` and heredocs. Here document support, arithmetic evaluation, improved ${var} ops, other fixes are by Mike Frysinger (vapier AT gentoo.org). + +

        Other changes: +

          +
        • libbb: unify concurrent-safe update of /etc/{passwd,group,[g]shadow}. By Tito (farmatito AT tiscali.it)
        • +
        • libbb/sha1/256/512: major code shrink
        • +
        • libbb/lineedit: make history saving/loading concurrent-safe
        • +
        • libbb: shrink linked list ops. By xmaks AT email.cz
        • +
        • libbb: str2sockaddr shuld accept [IPv6] addr without port - wget 'ftp://[::1]/file' needs that to work
        • +
        • libbb: make bb_info_msg do atomic, unbuffered writes
        • +
        • adduser: allow adding to group 0; don't _create_ /etc/shadow, only append data if it exists
        • +
        • ash: fix mishandled ^C
        • +
        • ash: fix "ash -c 'exec 1>&0'" complaining that fd 0 is busy
        • +
        • ash: fix $IFS handling in read. Closes bug 235
        • +
        • ash: fix a case where we close wrong descriptor
        • +
        • ash: fix bad interaction between ash -c '....&' and bash compat
        • +
        • ash: fix miscalculation of memory needed for eval tree. Found by Timo Teras (timo.teras AT iki.fi)
        • +
        • ash: in dotrap(), do not clear gotsig[] for SIGINT if there is no handler for it, otherwise raise interrupt gets confused later
        • +
        • ash: make dot command search current directory first, as bash does
        • +
        • ash: make evaltree save/restore int suppression depth. Hopefully this fixes bug 189
        • +
        • ash: printf builtin with no arguments should not exit
        • +
        • awk: fix long field separators case. By Ian Wienand (ianw AT vmware.com)
        • +
        • awk: in BEGIN section $0 should be "", not "0"
        • +
        • awk: make "struct global" hack more robust wrt alignment. Closes bug 131
        • +
        • brctl: fix compilation on 2.4.x kernels
        • +
        • chat: treat timeout more correctly
        • +
        • chat: recognize RECORD directive
        • +
        • cksum, printenv: report errors via exitcode
        • +
        • cpio: add -p, -0 and -L options
        • +
        • crond,crontab: make cron directory location configurable
        • +
        • crond: correct more of logfile to 0666 (as usual, umask allows user to remove unwanted bits)
        • +
        • crond: put tasks in separate process groups
        • +
        • dc: fix the "base 2" patch omission of base not being set
        • +
        • depmod: accept and ignore -r. Linux kernel build needs this
        • +
        • depmod: fix -b option. By timo.teras AT iki.fi
        • +
        • udhcpd,dumpleases: write and use 64-bit current time in lease file. without it, determination of remaining lease time is unreliable
        • +
        • udhcpd: remember and record hostnames
        • +
        • dhcprelay: fix usage text. Simplify and make code more readable
        • +
        • dumpleases: fix -a option; show hostnames
        • +
        • udhcpc: fix a problem where we don't open listening socket fast enough
        • +
        • udhcpc: stop filtering environment passed to the script
        • +
        • udhcpd: add code which rejects lease files with suspicious or old timestamp
        • +
        • udhcpd: disable opton to have absolute lease times in lease file (that does not work with dumpleases)
        • +
        • dnsd: fix a number of bugs. Ideas by Ming-Ching Tiew (mctiew AT yahoo.com)
        • +
        • dpkg: better and shorter code to compare versions. Taken from "official" dpkg by Eugene T. Bordenkircher (eugebo AT gmail.com)
        • +
        • du: fix "du /dir /dir" case
        • +
        • env: support -uVAR=VAL
        • +
        • expand: fix incorrect expansion exactly on tab boundary; shrink the code
        • +
        • expr: a bit more robust handling of regexps with groups. Closes bug 87
        • +
        • find: support --mindepth
        • +
        • getty: fix handling of speed 0; stop using non-portable way of setting speeds
        • +
        • grep: support -z
        • +
        • gzip: fix gzip -dc bug caused by using stale getopt state
        • +
        • head: report file open errors with exitcode 1 (was happily returning 0)
        • +
        • httpd: set $HOST to Host: header value. By Tobias Poschwatta (tp AT fonz.de)
        • +
        • ifupdown: allow options to udhcpc to be configurable from .config
        • +
        • init: do not eat last char in messages; do not print duplicate "init:" prefix to syslog
        • +
        • init: fix a bug where on reload order of entries might be wrong
        • +
        • init: major improvement in documentation and signal handling. Lots of nasty, but hard to trip, races are fixed
        • +
        • init: reinstate proper handling of !ENABLE_FEATURE_USE_INITTAB
        • +
        • init: remove wait loop on restart, it may be dangerous
        • +
        • init: test for vt terminal with VT_OPENQRY, assume that anything else is TERM=vt102, not TERM=linux. Closes bug 195
        • +
        • inotifyd: add x, o, and u events
        • +
        • inotifyd: fix buffer overflow and "unreaped zombies" problem
        • +
        • inotifyd: exit if x event happened for all files
        • +
        • inotifyd: conserve resourses by closing unused inotify descriptors
        • +
        • insmod/modprobe: do not pass NULL to kernel as module parameter
        • +
        • ip: in "ip rule add from all table 1", "all" is taken as 0.0.0.0/32, whereas "any" and "default" would be 0.0.0.0/0. They must be all 0.0.0.0/0. Closes bug 57
        • +
        • iproute: fix ipXXX utilities trying to parse their applet name as their 1st parameter
        • +
        • klogctl: fix a problem where we don't terminate read data with '\0' and then misinterpret it
        • +
        • ls: do not follow links with -s. Closes bug 33
        • +
        • ls: implement -Q and -g (-g was accepted but ignored)
        • +
        • ls: make readlink error to not disrupt output (try ls -l /proc/self/fd)
        • +
        • man: better check for duplicated MANPATH
        • +
        • mdev: add support for - ("dont stop here") char
        • +
        • mdev: if /sys/class/block exists, don't scan /sys/block
        • +
        • mdev: ignore events with "$SUBSYSTEM" == "firmware" && "$ACTION" == "remove"
        • +
        • mdev: provide $SUBSYSTEM. By Vladimir
        • +
        • modprobe/insmod for 2.4: support compressed modules. By Guenter (lists AT gknw.net)
        • +
        • modprobe: emit "can't open 'modules.dep': (errno)" instead of "module not found"
        • +
        • modprobe: rework/speedup by Timo Teras (timo.teras AT iki.fi)
        • +
        • modutils-24: fix bad interaction of xzalloc with xrealloc_vector
        • +
        • mount: support "-O option"
        • +
        • mount: stop trying to mount swap partitions
        • +
        • mount: fix CIFS support
        • +
        • mountpoint: add -n option. By Vladimir
        • +
        • nslookup: allow usage of IPv6 addresses or hostnames for DNS server name; allow for port specification. Tested to work: "nslookup google.com [::1]:5353". glibc + IPv6 address of DNS server still does not work
        • +
        • popmaildir: fix several grave bugs with using memory past end of malloc block
        • +
        • printf: fix 1.12.0 breakage (from %*d fix), it was misinterpreting "*"
        • +
        • printf: make integer format strings print long long-sized values
        • +
        • rmmod: fix bug 263 "modutils/rmmod can't remove modules with dash in name on 2.4 kernels"
        • +
        • sendmail: document and fix usage of fd #4, fix check for helper failure
        • +
        • sendmail: update by Vladimir
        • +
        • seq: add -w support. By Natanael Copa
        • +
        • seq: add support for "-s separator"
        • +
        • stat: make stat -f show filesystem "ID:" as coreutils does
        • +
        • sysctl: fix another corner case with "dots and slashes"
        • +
        • sysctl: fix broken -p [file]. Closes bug 231
        • +
        • sysctl: support recursing if name is a directory: "sysctl net.ipv4.conf". Patch by xmaks AT email.cz
        • +
        • syslogd: comment out file locking; make signal handling syncronous
        • +
        • syslogd: create logfile with 0666 (affected by umask as usual), not 0600
        • +
        • tail: fix tail +N syntax not working. Closes bug 221
        • +
        • tar: do not change new tarfile's mode, GNU tar doesn't do it
        • +
        • tar: support GNU tar's "base256" encoding
        • +
        • telnetd: correctly output 0xff char
        • +
        • telnetd: do not advertise TELNET_LFLOW, we do not support it properly
        • +
        • tftp: when we infer local name from remote (-r [/]path/path/file), strip path. This mimics wget and is generally more intuitive
        • +
        • timeout: fix parsing of -t NUM on MMU
        • +
        • top: make it work again on 2.4 kernels. Closes bug 125
        • +
        • tr: fix overflow in expand and complement, fix stop after [:class:]
        • +
        • tr: support -C as synonym to -c
        • +
        • tr: support [:xdigit:], fix handling of ranges and [x]'s
        • +
        • traceroute: rewrite. Do not emit raw IP packets, instead send UDP or ICMP packets and rely on the kernel to form IP headers, select source IP and interface
        • +
        • uname: add support for -i and -o, fix printing of unknown -p value with -a option
        • +
        • uname: support long options
        • +
        • unexpand: fix incorrect expansion
        • +
        • unzip: fix thinko with le/be conv and size. Closes bug 129
        • +
        • vi: fix several instances of major goof: when text grows, text[] might get reallocated! We were keeping around pointers to old place
        • +
        • vi: speedup and code shrink. By Walter Harms
        • +
        • volume_id: abort early on read failures. Should help with probing missing fdd's
        • +
        • volumeid: fix bug 249 "findfs finds the wrong partition"
        • +
        • wget: --post-data support. By Harald Kuthe (harald-tuxbox AT arcor.de)
        • +
        • wget: fix --header handling
        • +
        • wget: more robust EINTR detection
        • +
        +

        + +
      • 8 March 2009 -- BusyBox 1.13.3 (stable) +

        BusyBox 1.13.3. + (svn, + patches, + how to add a patch)

        + +

        1.13.3 is a bug fix release. It has fixes for awk, depmod, init, killall, mdev, + modprobe, printf, syslogd, tar, top, unzip, wget. +

        +
      • + +
      • 31 December 2008 -- BusyBox 1.13.2 (stable), BusyBox 1.12.4 (stable) +

        BusyBox 1.13.2. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.12.4. + (svn, + patches, + how to add a patch)

        + +

        Bug fix releases. 1.13.2 has fixes for crond, dc, init, ip, printf. + 1.12.4 has fixes for ip and printf. +

        +
      • + +
      • 29 November 2008 -- BusyBox 1.13.1 (stable), BusyBox 1.12.3 (stable) +

        BusyBox 1.13.1. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.12.3. + (svn, + patches, + how to add a patch)

        + +

        Bug fix releases. 1.13.1 has fixes for ash, option parsing, id, init, + inotifyd, klogd, line editing and modprobe. 1.12.3 has fixes + for option parsing and line editing. +

        +
      • + +
      • 10 November 2008 -- BusyBox 1.13.0 (unstable), BusyBox 1.12.2 (stable) +

        BusyBox 1.13.0. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.12.2. + (svn, + patches, + how to add a patch)

        + +

        Sizes of busybox-1.12.2 and busybox-1.13.0 (with equivalent config, static uclibc build):

        +   text    data     bss     dec     hex filename
        + 778291     551    7856  786698   c010a busybox-1.12.2/busybox
        + 778981     551    7852  787384   c03b8 busybox-1.13.0/busybox
        +
        + +

        New applets: blkid, devmem + +

        Changes since previous release: +

          +
        • mail applets: total overhaul. Vladimir as usual
        • +
        • ash: fix "while kill -0 $child; do true; done" looping forever
        • +
        • ash: fix NOEXEC mode - we were forgetting to pass environment
        • +
        • ash: fix a bug in standalone mode (corrupted getopt state)
        • +
        • ash: optionally support ">&file" and "&>file" redirections
        • +
        • awk: bitwise ops cast oprands and results to unsigned long, not signed. closes bug 4774
        • +
        • awk: fix typo in atan2 code. closes bug 5594
        • +
        • awk: improve handling of negative numbers in bitwise ops; fix handling of octal costants
        • +
        • awk: support hex constants
        • +
        • basename: fix error code (again)
        • +
        • cpio: emit TRAILER even when hard links were found. By Pascal Bellard (pascal.bellard AT ads-lu.com)
        • +
        • crontab: do not destroy STDIN_FILENO, editor may need it (crontab -e)
        • +
        • dc: support for bases 2 and 8, by Nate Case (ncase AT xes-inc.com)
        • +
        • dhcpc: treat "discover...select...discover..." loop the same way as "discover...discover...discover..."
        • +
        • dpkg: add dpkg -l PACKAGE_PATTERN. By Peter Korsgaard
        • +
        • fbset: fix mode matching code: original code may trigger false positive.
        • +
        • findfs: fix LUKS and FAT detection routines; do not exit if corrupted FAT fs makes us try to seek past the end
        • +
        • grep: fix 'echo aaa | grep -o a' + ENABLE_EXTRA_COMPAT case. By Natanael Copa
        • +
        • grep: fix EXTRA_COMPAT grep to honor -E and -i
        • +
        • gunzip: restore mtime
        • +
        • halt: reinstate -w even if !FEATURE_WTMP
        • +
        • hexdump: fix SEGV in hexdump -e ""
        • +
        • httpd: pass "Accept:" and "Accept-Language:" header to CGI scripts (Alina Friedrichsen)
        • +
        • hush: fix environment and memory leaks
        • +
        • hush: fix trashing of environment by local env vars: a=a; a=b cmd; - a was unset
        • +
        • id: improve compatibility with coreutils. By Tito Ragusa
        • +
        • inetd: fix a case when we have zero services
        • +
        • inetd: use config parser. by Vladimir
        • +
        • init: set stderr to NONBLOCK
        • +
        • insmod: fix detection of open failure
        • +
        • install: support -D
        • +
        • ip: fix ip route rejecting dotted quads as prefix
        • +
        • ip: route metric support (Natanael Copa)
        • +
        • iplink: accept shorthands for "address" keyword: "ip link set address 00:11:22:33:44:55"
        • +
        • kbd_mode: support -C TTY
        • +
        • kill[all[5]]: accept -s SIG too. By Steve Bennett (steveb AT workware.net.au)
        • +
        • klogd: handle many lines at once. By Steve Bennett (steveb AT workware.net.au)
        • +
        • less: support -I to be able to search case-insensitively
        • +
        • less: add optional line number toggle and resizing on window resize
        • +
        • libbb: do not reject floating point strings like ".15"
        • +
        • lineedit: fix bug 5824 "since rev 23530 fdisk and ed don't work any more"
        • +
        • lineedit: fix problems with empty commands in history
        • +
        • login: fix /etc/nologin handling
        • +
        • man: fix inconsistencies in handling $MANPATH
        • +
        • mdev: support match by major,minor. See bug 4714
        • +
        • modprobe-small: make insmod command line compatible
        • +
        • modprobe-small: support "blacklist" keyword in /etc/modules/MODULE_NAME
        • +
        • modprobe: fix a segfault when modprobe is called with no arguments at all
        • +
        • modutils/*: rewrite by Timo Teras (timo.teras AT iki.fi)
        • +
        • mount: fix "-o parm1 -o parm2" not accumulating
        • +
        • nmeter: 4k buffers are too small for /proc files, make them dynamically sized with 16k upper limit
        • +
        • ping: SO_RCVBUF must be bigger than packet size, otherwise large ping packets might fail to be received
        • +
        • route: fix for 64-bit BE machines by Seonghun Lim (wariua AT gmail.com)
        • +
        • rpm: fix incompatibilities which prevented rpm -i foo.src.rpm
        • +
        • runsvdir: support runsvdir-as-init
        • +
        • setarch: do not try to use non-existent data in argv[]
        • +
        • setfont: support -m and -C, support -m TEXTUAL_MAP (by Vladimir)
        • +
        • setup_environment: cd $HOME regardless of clear_env value
        • +
        • slattach: preserve speed in non-raw mode. By Matthieu Castet (matthieu.castet AT parrot.com)
        • +
        • start_stop_daemon: accept (and ignore) -R PARAM
        • +
        • sv: make default service dir configurable (Vladimir wants it)
        • +
        • sysctl: fix bug 3894 (by Kryzhanovskyy Maksym)
        • +
        • tar: fix bug 3844: non-root tar does not preserve perms
        • +
        • telnetd: handle emacs M-DEL and IAC-NOP. by Jim Cathey (jcathey AT ciena.com)
        • +
        • top: fix "top -d 1" (bug 5144)
        • +
        • top: optional SMP support by Vineet Gupta (vineetg76 AT gmail.com)
        • +
        • trylink: make messages less confusing
        • +
        • unzip: handle "central directory". needed for OpenOffice, gmail attachment .zips etc
        • +
        • vi: Rob's algorithm of reading and matching ESC sequences (nice work btw!)
        • +
        • vi: deal with EOF/error on stdin and with input NULs
        • +
        • vi: fix uninitialized last_search_pattern (bug 5794)
        • +
        • vi: handle chars 0x80, 0x81 etc correctly
        • +
        • volume identification: abolish /proc/partitions and /proc/cdroms scanning. It does not catch volume managers and such. Simply scan /dev/* for any block devices
        • +
        • watchdog: WDIOC_SETTIMEOUT accepts seconds, not milliseconds
        • +
        • watchdog: add -T option
        • +
        +

        + The email address gpl@busybox.net is the recommended way to contact + the Software Freedom Law Center to report BusyBox license violations. +

        +
      • + +
      • 28 September 2008 -- BusyBox 1.12.1 (stable), BusyBox 1.11.3 (stable) +

        BusyBox 1.12.1. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.11.3. + (svn, + patches, + how to add a patch)

        +

        + Bugfix-only releases for 1.11.x and 1.12.x branches. +

        +
      • + +
      • 21 August 2008 -- BusyBox 1.12.0 (unstable), BusyBox 1.11.2 (stable) +

        BusyBox 1.12.0. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.11.2. + (svn, + patches, + how to add a patch)

        + +

        Sizes of busybox-1.11.2 and busybox-1.12.0 (with equivalent config, static uclibc build):

        +   text    data     bss     dec     hex filename
        + 829687     617    7052  837356   cc6ec busybox-1.11.2/busybox
        + 822961     594    6832  830387   cabb3 busybox-1.12.0/busybox
        +
        + +

        New applets: rdev (Grant Erickson), setfont, showkey (both by Vladimir) + +

        Most significant changes since previous release (please report any regression): +

          +
        • ash: bash compat: "shift $BIGNUM" is equivalent to "shift 1"
        • +
        • ash: dont allow e.g. exec <&10 to attach to script's fd!
        • +
        • ash: fix a bug where redirection fds were not closed afterwards. optimize close+fcntl(DUPFD) into dup2
        • +
        • ash: fix segfault in "command -v"
        • +
        • ash: fix very weak $RANDOM generator
        • +
        • ash: prevent exec NN>&- from closing fd used for script reading
        • +
        • ash: teach ash about 123>file. It could take only 0..9 before
        • +
        • hush: fix a case where "$@" must expand to no word at all
        • +
        • hush: fix mishandling of a'b'c=fff as assignments. They are not
        • +
        • hush: fix non-detection of builtins and applets in "v=break; ...; $v; ..." case
        • +
        • hush: fix "while false; ..." exitcode; add testsuites
        • +
        • hush: support "case...esac" statements (~350 bytes of code)
        • +
        • hush: support "break [N]" and "continue [N]" statements
        • +
        • hush: support "for if in do done then; do echo $if; done" case
        • +
        • hush: support "for v; do ... done" syntax (implied 'in "$@"')
        • +
        • hush: support $_NUMBERS variable names
        • +
        • libbb: unified config parser (by Vladimir). This change affected many applets
        • +
        + +

        Other changes: +

          +
        • libbb: dump: do not use uninitialized memory (closes bug 4364)
        • +
        • libbb: fix bb_strtol[l]'s check for "-" (closes bug 4174)
        • +
        • libbb: fix --help to not affect "test --help"
        • +
        • libbb: fix mishandling of "all argv are opts" in getopt32()
        • +
        • libbb: getopt32() should not ever touch argv[0] (even read)
        • +
        • libbb: introduce and use xrealloc_vector
        • +
        • libbb: [x]fopen_for_{read,write} introduced and used (by Vladimir)
        • +
        • lineedit: fix use-after-free
        • +
        • libunarchive: refactor handling of archived files. "tar f file.tar.lzma" now works too
        • +
        • bb_strtoXXX: close bug 4174 (potential use of buf[-1])
        • +
        • open_transformer: don't leak file descriptor
        • +
        • open_transformer: fix bug of calling exit instead of _exit
        • +
        • arp: without -H type, assume "ether" (closes bug 4564)
        • +
        • ar: reuse existing ar unpacking code
        • +
        • awk: fix a case with multiple -f options. Simplify -f file reading.
        • +
        • build system: introduce and use FAST_FUNC: regparm on i386, otherwise no-op
        • +
        • bunzip2: fix an uncompression error (by Rob Landley rob AT landley.net)
        • +
        • b[un]zip2, g[un]zip: unlink destination if -f is given (closes bug 3854)
        • +
        • comm: almost total rewrite
        • +
        • cpio: fix -m to actually work as expected (by Pascal Bellard)
        • +
        • cpio: internalize archive_xread_all_eof, add a few paranoia checks for corrupted cpio files
        • +
        • cpio: make long opts depend only on ENABLE_GETOPT_LONG
        • +
        • cpio: on unpack, limit filename length to 8k
        • +
        • cpio: support some long options
        • +
        • crond: use execlp instead of execl
        • +
        • cut: fix buffer overflow (closes bug 4544)
        • +
        • envdir: fix "envdir" (no params at all) and "envdir dir" cases
        • +
        • findfs: make it use setuid-ness of busybox binary
        • +
        • fsck: use getmntent_r instead of open-coded parsing (by Vladimir)
        • +
        • fuser: a bit of safety in scanf
        • +
        • grep: option to use GNU regex matching instead of POSIX one. This fixes problems with NULs in files being scanned, but costs +800 bytes
        • +
        • halt: signal init regardless of ENABLE_INIT
        • +
        • httpd: add homedir directive specially for (and by) Walter Harms wharms AT bfs.de
        • +
        • ifupdown: /etc/network/interfaces can have comments with leading blanks
        • +
        • ifupdown: fixes for custom MAC address (by Wade Berrier wberrier AT gmail.com)
        • +
        • ifupdown: fixes for shutdown of DHCP-managed interfaces (by Wade Berrier wberrier AT gmail.com)
        • +
        • inetd: do not trash errno in signal handlers; in CHLD handler, stop looping through services when pid is found
        • +
        • insmod: users report that "|| defined(__powerpc__)" is missing
        • +
        • install: do not chown intermediate directories with install -d (by Natanael Copa)
        • +
        • install: fix long option not taking params (closes bug 4584)
        • +
        • lpd,lpr: send/receive ACKs after filenames, not only after file bodies
        • +
        • ls: fix a bug where we may use uninintialized variable
        • +
        • man: add handling of "man links", by Ivana Varekova varekova AT redhat.com
        • +
        • man: fix a case when a full pathname to manpage is given
        • +
        • man: fix inverted cat/man bool variable
        • +
        • man: fix missed NULL termination of an array
        • +
        • man: mimic "no manual entry for 'bogus'" message and exitcode
        • +
        • man: support cat pages too (by Jason Curl jcurlnews AT arcor.de)
        • +
        • man: teach it to use .lzma if requested by .config
        • +
        • mdev: check for "/block/" substring for block dev detection
        • +
        • mdev: do not complain if mdev.conf does not exist
        • +
        • mdev: if device was moved at creation, at removal correctly remove it from moved location and also remove symlinks to it
        • +
        • mdev: support for serializing hotplug
        • +
        • mdev, init: use shared code for fd sanitization
        • +
        • mkdir: fix "uname 0222; mkdir -p foo/bar" case (by Doug Graham dgraham AT nortel.com)
        • +
        • modprobe: support for /etc/modprobe.d (by Timo Teras)
        • +
        • modprobe: use buffering line reads (fgets()) instead of reads()
        • +
        • modutils: optional modprobe-small (by Vladimir), 15kb smaller than standard one
        • +
        • mount: support for "-o mand" and "[no]relatime"
        • +
        • mount: support nfs mount option "nordiplus" (by Octavian Purdila opurdila AT ixiacom.com)
        • +
        • mount: support "relatime" / "norelatime"
        • +
        • mount: testsuite for "-o mand"
        • +
        • msh: fix "while... continue; ..." (closes bug 3884)
        • +
        • mv: fix a case when we move dangling symlink across mountpoints
        • +
        • netstat: optional -p support (by L. Gabriel Somlo somlo AT cmu.edu)
        • +
        • nmeter: fix read past the end of a buffer (closes bug 4594)
        • +
        • od, hexdump: fix bug where xrealloc may move pointer, leaving other pointers dangling (closes bug 4104)
        • +
        • pidof/killall: allow find_pid_by_name to find running processes started as scripts_with_name_longer_than_15_bytes.sh (closes bug 4054)
        • +
        • printf: do not print garbage on "%Ld" (closes bug 4214)
        • +
        • printf: fix %b, fix several bugs in %*.*, fix compat issues with aborting too early, support %zd; expand testsuite
        • +
        • printf: protect against bogus format specifiers (closes bug 4184)
        • +
        • sendmail: updates from Vladimir:
        • +
        • sendmail: do not discard all headers
        • +
        • sendmail: do not ignore CC; accept to: and cc: case-insensitively. +20 bytes
        • +
        • sendmail: fixed mail recipient address
        • +
        • sendmail: fixed SEGV if sender address is missed
        • +
        • sendmail: use HOSTNAME instead of HOST when no server is explicitly specified
        • +
        • sleep: if FANCY && DESKTOP, support fractional seconds, minutes, hours and so on (coreutils compat)
        • +
        • ssd: CLOSE_EXTRA_FDS in MMU case too
        • +
        • ssd: do not stat -x EXECUTABLE, it is not needed anymore
        • +
        • ssd: fix -a without -x case
        • +
        • ssd: use $PATH
        • +
        • tar: fix handling of tarballs with symlinks with size field != 0
        • +
        • tar: handle autodetection for tiny .tar.gz files too, simplify autodetection
        • +
        • taskset: fix some careless code in both fancy and non-fancy cases. -5 bytes for fancy, +5 for non-fancy
        • +
        • tee: fix infinite looping on open error (echo asd | tee "")
        • +
        • tee: "-" is a name for stdout, handle it that way
        • +
        • telnetd: fix issue file printing
        • +
        • test: fix parser to prefer binop over unop, as coreutils does
        • +
        • testsuite: uniformly use $ECHO with -n -e
        • +
        • time: don't segfault with no arguments
        • +
        • touch: support -r REF_FILE if ENABLE_DESKTOP (needed for blackfin compile)
        • +
        • tr: fix "access past the end of a string" bug 4354
        • +
        • tr: fix "tr [=" case (closes bug 4374)
        • +
        • tr: fix yet another access past the end of a string (closes bug 4374)
        • +
        • unlzma: fix memory leak (by Pascal Bellard)
        • +
        • vi: fix reversed checks for underflow
        • +
        • vi: using array data after it fell out of scope is stupid
        • +
        • xargs: fix -e default to match newer GNU xargs, add SUS mandated -E (closes bug 4414)
        • +
        • other fixes and code size reductions in many applets
        • +
        +

        + +
      • 12 July 2008 -- BusyBox 1.11.1 (stable) +

        BusyBox 1.11.1. + (svn, + patches, + how to add a patch)

        +

        + Bugfix-only release for 1.11.x branch. It contains fixes for awk, + bunzip2, cpio, ifupdown, ip, man, start-stop-daemon, uname and vi. +

        +
      • + +
      • 11 July 2008 -- HOWTO is updated +

        + + "How to build static busybox for i486-linux-uclibc" is updated + and tested on a fresh Fedora 9 install. Please report if it doesn't + work for you. +

        +
      • + + + +
      • Old News

        + Click here to read older news +

        +
      • + +
      + + + diff --git a/release/src/router/busybox/docs/busybox.net/oldnews.html b/release/src/router/busybox/docs/busybox.net/oldnews.html index d6bd581f71..444af74a44 100644 --- a/release/src/router/busybox/docs/busybox.net/oldnews.html +++ b/release/src/router/busybox/docs/busybox.net/oldnews.html @@ -1,12 +1,293 @@ +

      News archive

        + +
      • 25 June 2008 -- BusyBox 1.11.0 (unstable), BusyBox 1.10.4 (stable) +

        BusyBox 1.11.0. + (svn, + patches, + how to add a patch)

        +

        BusyBox 1.10.4. + (svn, + patches, + how to add a patch)

        +

        Sizes of busybox-1.10.4 and busybox-1.11.0 (with equivalent config, static uclibc build):

        +   text    data     bss     dec     hex filename
        + 800675     636    7080  808391   c55c7 busybox-1.10.4
        + 798392     611    6900  805903   c4c0f busybox-1.11.0
        +
        + +

        New applets: inotify (Vladimir Dronnikov), man (Ivana Varekova), + fbsplash (Michele Sanges), depmod (Bernhard Reutner-Fischer) + +

        Changes since previous release: +

          +
        • build system: reinstate CONFIG_CROSS_COMPILE_PREFIX
        • +
        • ash: optional bash compatibility features added; other fixes
        • +
        • hush: lots and lots of fixes
        • +
        • msh: fix the case where the file has exec bit but can't be run directly (runs "$SHELL file" instead)
        • +
        • msh: fix exit codes when command is not found or can't be execed
        • +
        • udhcpc: added workaround for buggy kernels
        • +
        • mount: fix mishandling of proto=tcp/udp
        • +
        • diff: make it work on non-seekable streams
        • +
        • openvt: made more compatible with "standard" one
        • +
        • mdev: fix block/char device detection
        • +
        • ping: add -w, -W support (James Simmons)
        • +
        • crond: add handling of "MAILTO=user" lines
        • +
        • start-stop-daemon: make --exec follow symlinks (Joakim Tjernlund)
        • +
        • date: make it accept ISO date format
        • +
        • echo: fix echo -e -n "msg\n\0" (David Pinedo)
        • +
        • httpd: fix several bugs triggered by relative path in -h DIR
        • +
        • printf: fix printf -%s- foo, printf -- -%s- foo
        • +
        • syslogd: do not error out on missing files to rotate
        • +
        • ls: support Unicode in names
        • +
        • ip: support for the LOWER_UP flag (Natanael Copa)
        • +
        • mktemp: make argument optional (coreutil 6.12 compat)
        • +
        • libiproute: fix option parsing, so that "ip -o link" works again
        • +
        • other fixes and code size reductions in many applets
        • +
        +

        + The email address gpl@busybox.net is the recommended way to contact + the Software Freedom Law Center to report BusyBox license violations. +

        +
      • + +
      • 12 June 2008 -- Sponsors! +

        We want to thank the following companies which are providing support + for the BusyBox project: +

        + +
      • + +
      • 5 June 2008 -- BusyBox 1.10.3 (stable) +

        BusyBox 1.10.3. + (svn, + patches, + how to add a patch)

        +

        + Bugfix-only release for 1.10.x branch. It contains fixes for dnsd, fuser, hush, + ip, mdev and syslogd. +

        +
      • + +
      • 8 May 2008 -- BusyBox 1.10.2 (stable) +

        BusyBox 1.10.2. + (svn, + patches, + how to add a patch)

        +

        + Bugfix-only release for 1.10.x branch. It contains fixes for echo, httpd, pidof, + start-stop-daemon, tar, taskset, tab completion in shells, build system. +

        Please note that mdev was backported from current svn trunk. Please + report if you encounter any problems with it. +

        +
      • + +
      • 19 April 2008 -- BusyBox 1.10.1 (stable) +

        BusyBox 1.10.1. + (svn, + patches, + how to add a patch)

        +

        + Bugfix-only release for 1.10.x branch. It contains fixes for + fuser, init, less, nameif, tail, taskset, tcpudp, top, udhcp. +

      • + +
      • 21 March 2008 -- BusyBox 1.10.0 (unstable) +

        BusyBox 1.10.0. + (svn, + patches, + how to add a patch)

        + +

        Sizes of busybox-1.9.2 and busybox-1.10.0 (with almost full config, static uclibc build):

        +   text    data     bss     dec     hex filename
        + 781405     679    7500  789584   c0c50 busybox-1.9.2
        + 773551     640    7372  781563   becfb busybox-1.10.0
        +
        +

        Top 10 stack users:

        +busybox-1.9.2:               busybox-1.10.0:
        +echo_dg                 4116 bb_full_fd_action       4112
        +bb_full_fd_action       4112 find_list_entry2        4096
        +discard_dg              4108 readlink_main           4096
        +discard_dg              4096 ipaddr_list_or_flush    3900
        +echo_stream             4096 iproute_list_or_flush   3680
        +discard_stream          4096 insmod_main             3152
        +find_list_entry2        4096 fallbackSort            2952
        +readlink_main           4096 do_iproute              2492
        +ipaddr_list_or_flush    3900 cal_main                2464
        +iproute_list_or_flush   3680 readhere                2308
        +
        + +

        New applets: brctl, chat (by Vladimir Dronnikov <dronnikov AT gmail.com>), + findfs, ifenslave (closes bug 115), lpd (by Vladimir Dronnikov <dronnikov AT gmail.com>), + lpr+lpq (by Walter Harms), script (by Pascal Bellard <pascal.bellard AT ads-lu.com>), + sendmail (Vladimir Dronnikov <dronnikov AT gmail.com>), tac, tftpd. +

        +

        Made NOMMU-compatible: crond, crontab, ifupdown, inetd, init, runsv, svlogd, tcpsvd, udpsvd. +

        +

        Changes since previous release: +

        +
          +
        • globally: add -Wunused-parameter
        • +
        • globally: add optimization barrier to all "G trick" locations
        • +
        • adduser/addgroup: check username for invalid chars (by Tito <farmatito AT tiscali.it>)
        • +
        • adduser: optional support for long options. Closes bug 2134
        • +
        • ash: handle "A=1 A=2 B=$A; echo $B". Closes bug 947
        • +
        • ash: make ash -c "if set -o barfoo 2>/dev/null; then echo foo; else echo bar; fi" work. Closes bug 1142
        • +
        • build system: don't use "gcc -o /dev/null", old gcc can delete /dev/null in this case
        • +
        • build system: fixes for cross-compiling on an OS X host
        • +
        • build system: make it do without "od -t"
        • +
        • build system: pass CFLAGS to link stage too. Closes bug 1376
        • +
        • build system: add CONFIG_NOMMU
        • +
        • cp: add ENABLE_FEATURE_VERBOSE_CP_MESSAGE. Closes bug 1470
        • +
        • crontab: almost complete rewrite
        • +
        • dnsd: properly set _src_ IP:port on outgoing UDP packets
        • +
        • dpkg: fix bug where existence check was reversed
        • +
        • eject: add -s for SCSI- and USB-devices (Nico Erfurth)
        • +
        • fdisk: fix a case where break was reached only for DOS labels
        • +
        • fsck: don't kill pid -1! (Roy Marples <roy at marples.name>)
        • +
        • fsck_minix: fix bug in map_block2: s/(blknr >= 256 * 256)/(blknr < 256 * 256)/
        • +
        • fuser: substantial rewrite
        • +
        • getopt: add support for "a+" specifier for nonnegative int parameters. By Vladimir Dronnikov <dronnikov at gmail.com>
        • +
        • getty: don't try to detect parity on local lines (Joakim Tjernlund <Joakim.Tjernlund at transmode.se>)
        • +
        • halt: write wtmp entry if wtmp support is enabled
        • +
        • httpd: "HEAD" support. Closes bug 1530
        • +
        • httpd: fix bug 2004: wrong argv when interpreter is invoked
        • +
        • httpd: fix bug where we did chdir("") if CGI path had only one "/"
        • +
        • httpd: fix for POST upload
        • +
        • httpd: support for "I:index.xml" syntax (Peter Korsgaard <jacmet AT uclibc.org>)
        • +
        • hush: fix a case where none of pipe members could be started because of fork failure
        • +
        • hush: more correct handling of piping
        • +
        • hush: reinstate `cmd` handling for NOMMU
        • +
        • hush: report [v]fork failures
        • +
        • hush: set CLOEXEC on script file being executed
        • +
        • hush: try to add a bit more of vfork-friendliness
        • +
        • inetd: make "udp nowait" work
        • +
        • inetd: make inetd IPv6-capable
        • +
        • init: add FEATURE_KILL_REMOVED (Eugene Bordenkircher <eugebo AT gmail.com>)
        • +
        • init: allow last line of config file to be not terminated by "\n"
        • +
        • init: do not die if "/dev/null" is missing
        • +
        • init: fix bug 1111: restart actions were not splitting words
        • +
        • init: wait for orphaned children too while waiting for sysinit-like processes (harald-tuxbox AT arcor.de)
        • +
        • ip route: "ip route" was misbehaving (extra argv+1 ate 1st env var)
        • +
        • last: do not go into endless loop on read error
        • +
        • less,klogd,syslogd,nc,tcpudp: exit on signal by killing itself, not exit(1)
        • +
        • less: "examine" command will not bomb out on bad file name now
        • +
        • less: fix bug where backspace wasn't actually deleting chars
        • +
        • less: make it a bit more resistant against status line corruption
        • +
        • less: improve search when data is not supplied fast enough by stdin - now will try reading for 1-2 seconds before declaring that there is no match. This fixes a very common annoyance with long manpages
        • +
        • less: update line input so that it doesn't interfere with screen update. Makes "man bash", [enter], [/], <enter search pattern>, [enter] more usable - manpage now draws even as you enter the pattern!
        • +
        • libbb: filename completion matches dangling symlinks too
        • +
        • libbb: fix getopt state corruption for NOFORK applets
        • +
        • libbb: full_read/write now will report partial data counts prior to error
        • +
        • libbb: intrduce and use safe_gethostname. By Tito <farmatito AT tiscali.it>
        • +
        • libbb: introduce and use nonblock_safe_read(). Yay! Our shells are immune from this nasty O_NONBLOCK now!
        • +
        • login,su: avoid clearing environment with some options, as was intended
        • +
        • microcom: read more than 1 byte from device, if possible
        • +
        • microcom: split -d (delay) option away from -t
        • +
        • mktemp: support -p DIR (Timo Teras <timo.teras at iki.fi>)
        • +
        • mount: #ifdef out MOUNT_LABEL code parts if it is not selected
        • +
        • mount: add another mount helper call method
        • +
        • mount: allow and ignore _netdev option
        • +
        • mount: make -f work even without mtab support (Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn at axis.com>)
        • +
        • mount: optional support for -vv verbosity
        • +
        • mount: plug a hole where FEATURE_MOUNT_HELPERS could allow execution of arbitrary command
        • +
        • mount: recognize "dirsync" (closes bug 835)
        • +
        • mount: sanitize environment if called by non-root
        • +
        • mount: support for mount by label. Closes bug 1143
        • +
        • mount: with -vv -f, say what mount() calls we were going to make
        • +
        • msh: create testsuite (based on hush one)
        • +
        • msh: don't use floating point in "times" builtin
        • +
        • msh: fix Ctrl-C handling with line editing
        • +
        • msh: fix for bug 846 ("break" didn't work second time)
        • +
        • msh: glob0/glob1/glob2/glob3 were just a sorting routine, removed
        • +
        • msh: instead of fixing "ls | cd", "cd | ls" etc disallow builtins in pipes. They make no sense there anyway
        • +
        • msh: stop trying to parse variables in "msh SCRIPT VAR=val param". They are passed as ordinary parameters
        • +
        • netstat: print control chars as "^C" etc
        • +
        • nmeter: fix bug where %[mf] behaves as %[mt]
        • +
        • nohup: compat patch by Christoph Gysin <mailinglist.cache at gmail.com>
        • +
        • od: handle /proc files (which have filesize 0) correctly
        • +
        • patch: don't trash permissions of patched file
        • +
        • ps: add conditional support for -o [e]time
        • +
        • ps: fix COMMAND column adjustment; overflow in USER and VSZ columns
        • +
        • reset: call "stty sane". Closes bug 1414
        • +
        • rmdir: optional long options support for Debian users. By Roberto Gordo Saez <roberto.gordo AT gmail.com>
        • +
        • run-parts: add --reverse
        • +
        • script: correctly handle buffered "tail" of output
        • +
        • sed: "n" command must reset "we had successful subst" flag. Closes bug 1214
        • +
        • sort: -z outputs NUL terminated lines. Closes bug 1591
        • +
        • stty: fix mishandling of control keywords (Ralf Friedl <Ralf.Friedl AT online.de>)
        • +
        • switch_root: stop at first non-option. Closes bug 1425
        • +
        • syslogd: avoid excessive time() system calls
        • +
        • syslogd: don't die if remote host's IP cannot be resolved. Retry resolutions every two minutes instead
        • +
        • syslogd: fix shmat error check
        • +
        • syslogd: optional support for dropping dups. Closes bug 436
        • +
        • syslogd: send "\n"-terminated messages over the network. Fully closes bug 1574
        • +
        • syslogd: tighten up hostname handling
        • +
        • tail: fix "tail -c 20 /dev/huge_disk" (was taking ages)
        • +
        • tar: compat: handle tarballs with only one zero block at the end
        • +
        • tar: autodetection of gz/bz2 compressed tarballs. Closes bug 992
        • +
        • tar: real support for -p. By Natanael Copa <natanael.copa at gmail.com>
        • +
        • tcpudp: narrow down time window where we have no wildcard socket
        • +
        • telnetd: use login always, not "sometimes login, sometimes shell"
        • +
        • test: fix mishandling of "test ! arg1 op arg2 more args"
        • +
        • trylink: instead of build error, disable --gc-sections if GLIBC and STATIC are selected
        • +
        • udhcp: make file paths configurable
        • +
        • udhcp: optional support for non-standard DHCP ports
        • +
        • udhcp: set correct op byte in the packet for DHCPDECLINE
        • +
        • udhcpc: filter unwanted packets in kernel (Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn AT axis.com>)
        • +
        • udhcpc: fix wrong options in decline and release packets (Jonas Danielsson <jonas.danielsson AT axis.com>)
        • +
        • umount: do not complain several times about the same mountpoint
        • +
        • umount: do not try to free loop device or erase mtab if remounted ro
        • +
        • umount: instead of non-standard -D, use -d with opposite meaning. Closes bug 1604
        • +
        • unlzma: shrink by Pascal Bellard <pascal.bellard AT ads-lu.com>
        • +
        • unzip: do not try to read entire compressed stream at once (it can be huge)
        • +
        • unzip: handle short reads correctly
        • +
        • vi: many fixes
        • +
        • zcip: don't chdir to root
        • +
        • zcip: open ARP socket before openlog (else we can trash syslog socket)
        • +
        +
      • + +
      • 21 March 2008 -- BusyBox old stable releases +

        + Bugfix-only releases for four past branches. Links to locations + for future hot patches are in parentheses. +

        + 1.9.2 + (patches), + 1.8.3 + (patches), + 1.7.5 + (patches), + 1.5.2 + (patches). +

        + How to add a patch. +

        + +
      • 12 February 2008 -- BusyBox 1.9.1 (stable) -

        BusyBox 1.9.1. - (svn, - patches, - how to add a patch)

        +

        BusyBox 1.9.1. + (svn, + patches, + how to add a patch)

        This is a bugfix-only release, with fixes to fsck, iproute, mdev, mkswap, msh, nameif, stty, test, zcip.

        @@ -16,10 +297,10 @@
      • 24 December 2007 -- BusyBox 1.9.0 (unstable) -

        BusyBox 1.9.0. - (svn, - patches, - how to add a patch)

        +

        BusyBox 1.9.0. + (svn, + patches, + how to add a patch)

        Sizes of busybox-1.8.2 and busybox-1.9.0 (with almost full config, static uclibc build):

            text    data     bss     dec     hex filename
        @@ -81,17 +362,17 @@ parse_prompt           4132  insmod_main            3152
         	
      • df: -i option (show inode info) (Pascal Bellard <pascal.bellard at ads-lu.com>)
      • hexdump: -R option (Pascal Bellard <pascal.bellard at ads-lu.com>)
      -

      +
    • 23 November 2007 -- BusyBox 1.8.2 (stable), BusyBox 1.7.4 (stable) -

      BusyBox 1.8.2. - (svn, - patches, - how to add a patch)

      -

      BusyBox 1.7.4. - (svn, - patches, - how to add a patch)

      +

      BusyBox 1.8.2. + (svn, + patches, + how to add a patch)

      +

      BusyBox 1.7.4. + (svn, + patches, + how to add a patch)

      These are bugfix-only releases. 1.8.2 contains fixes for inetd, lash, tar, tr, and build system. @@ -99,19 +380,19 @@ parse_prompt 4132 insmod_main 3152

    • 9 November 2007 -- BusyBox 1.8.1 (stable) -

      BusyBox 1.8.1. - (svn, - patches, - how to add a patch)

      +

      BusyBox 1.8.1. + (svn, + patches, + how to add a patch)

      This is a bugfix-only release, with fixes to login (PAM), modprobe, syslogd, telnetd, unzip.

    • 4 November 2007 -- BusyBox 1.8.0 (unstable) -

      BusyBox 1.8.0. - (svn, - patches, - how to add a patch)

      +

      BusyBox 1.8.0. + (svn, + patches, + how to add a patch)

      Note: this is probably the very last release with lash. It will be dropped. Please migrate to hush. @@ -212,42 +493,40 @@ Equivalent .config, i386 uclibc static builds:

    • watchdog: allow millisecond spec (-t 250ms)
    • zcip: fix unaligned trap on ARM
    -

    -
  • 4 November 2007 -- BusyBox 1.7.3 (stable) -

    BusyBox 1.7.3. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.7.3. + (svn, + patches, + how to add a patch)

    This is a bugfix-only release, with fixes to ash, httpd, inetd, iptun, logger, login, tail.

  • 30 September 2007 -- BusyBox 1.7.2 (stable) -

    BusyBox 1.7.2. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.7.2. + (svn, + patches, + how to add a patch)

    This is a bugfix-only release, with fixes to install, find, login, httpd, runsvdir, chcon, setfiles, fdisk and line editing.

  • 16 September 2007 -- BusyBox 1.7.1 (stable) -

    BusyBox 1.7.1. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.7.1. + (svn, + patches, + how to add a patch)

    This is a bugfix-only release, with fixes to cp, runsv, tar, busybox --install and build system.

  • 24 August 2007 -- BusyBox 1.7.0 (unstable) -

    BusyBox 1.7.0. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.7.0. + (svn, + patches, + how to add a patch)

    Applets which had many changes since 1.6.x:

    httpd: @@ -388,23 +667,22 @@ Same .config built against static uclibc:

  • wget: lift 256 chars limitation on terminal width
  • wget, zcip: use monotonic_sec instead of gettimeofday -

  • 30 June 2007 -- BusyBox 1.6.1 (stable) -

    BusyBox 1.6.1. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.6.1. + (svn, + patches, + how to add a patch)

    This is a bugfix-only release, with fixes to echo, hush, and wget.

  • 1 June 2007 -- BusyBox 1.6.0 (unstable) -

    BusyBox 1.6.0. - (svn, - patches, - how to add a patch)

    +

    BusyBox 1.6.0. + (svn, + patches, + how to add a patch)

    Since this is a x.x.0 release, it probably does not deserve "stable" label. Please help making 1.6.1 stable by testing 1.6.0.

    @@ -413,7 +691,7 @@ Same .config built against static uclibc: report any such cases.

    lash users please note: lash is going to be deprecated in busybox 1.7.0 and removed in the more distant future. Please migrate to hush.

    -

    Memory usage has decreased, but we can do better still

    +

    Memory usage has decreased, but we can do better still

    Other changes since previous release:

    • NOFORK: audit small applets and mark some of them as NOFORK. Put big scary warnings in relevant places @@ -511,22 +789,21 @@ Same .config built against static uclibc:
    • xargs: shrink code, ~80 bytes; simplify word list management
    • zcip: make it work on NOMMU (+ improve NOMMU support machinery)
    -

  • 20 May 2007 -- BusyBox 1.5.1 (stable) -

    BusyBox 1.5.1. - (patches, - how to add a patch)

    +

    BusyBox 1.5.1. + (patches, + how to add a patch)

    This is a bugfix-only release, with fixes to hdparm, hush, ifupdown, ps and sed.

  • 23 March 2007 -- BusyBox 1.5.0 (unstable) -

    BusyBox 1.5.0. - (patches, - how to add a patch)

    +

    BusyBox 1.5.0. + (patches, + how to add a patch)

    Since this is a x.x.0 release, it probably does not deserve "stable" label. Please help making 1.5.1 stable by testing 1.5.0.

    @@ -560,11 +837,10 @@ Same .config built against static uclibc:
  • Applets with code cleaned up: telnet, fdisk, fsck_minix, mkfs_minix, syslogd, swapon, runsv, svlogd, klogd -

  • 18 March 2007 -- BusyBox 1.4.2 (stable) -

    BusyBox 1.4.2. +

    BusyBox 1.4.2.

    This release includes only trivial fixes accumulated since 1.4.1. @@ -572,16 +848,16 @@ Same .config built against static uclibc:

  • 25 January 2007 -- BusyBox 1.4.1 (stable) -

    BusyBox 1.4.1. - (patches)

    +

    BusyBox 1.4.1. + (patches)

    This release includes only trivial fixes accumulated since 1.4.0.

  • 20 January 2007 -- BusyBox 1.4.0 (stable) -

    BusyBox 1.4.0. - (patches)

    +

    BusyBox 1.4.0. + (patches)

    Since this is a x.x.0 release, it probably is a bit less "stable" than usual.

    @@ -611,27 +887,26 @@ Same .config built against static uclibc:
  • minor bugfixes to: passwd, date, tftp, start_stop_daemon, tar, ps, ifupdown, time, su, stty, awk, ping[6], sort,... -

  • 20 January 2007 -- BusyBox 1.3.2 (stable) -

    BusyBox 1.3.2.

    +

    BusyBox 1.3.2.

    This release includes only one trivial fix accumulated since 1.3.1

  • 27 December 2006 -- BusyBox 1.3.1 (stable) -

    BusyBox 1.3.1. - (patches)

    +

    BusyBox 1.3.1. + (patches)

    Closing 2006 with new release. It includes only trivial fixes accumulated since 1.3.0

  • 14 December 2006 -- BusyBox 1.3.0 (stable) -

    BusyBox 1.3.0. - (patches)

    +

    BusyBox 1.3.0. + (patches)

    This release has CONFIG_DESKTOP option which enables features needed for busybox usage on desktop machine. For example, find, chmod @@ -666,7 +941,7 @@ Same .config built against static uclibc:

  • 29 October 2006 -- BusyBox 1.2.2.1 (fix) -

    BusyBox 1.2.2.1.

    +

    BusyBox 1.2.2.1.

    Added compile-time warning that static linking against glibc produces buggy executables. @@ -674,7 +949,7 @@ Same .config built against static uclibc:

  • 24 October 2006 -- BusyBox 1.2.2 (stable)

    It's a bit overdue, but - here is + here is BusyBox 1.2.2.

    This release has dozens of fixes backported from the ongoing development @@ -693,9 +968,9 @@ Same .config built against static uclibc: gzip to save memory, fix sulogin -tNNN, a help text tweak, several warning fixes and build fixes, fixup dnsd a bit, and a partridge in a pear tree.

    -

    As Linux Weekly News noted, +

    As Linux Weekly News noted, this is my (Rob's) last release of BusyBox. The new maintainer is Denis - Vlasenko, I'm off to do other things. + Vlasenko, I'm off to do other things.

  • @@ -811,7 +1086,7 @@ Same .config built against static uclibc: several existing applets. This prerelease should be noticeably more standards compliant than earlier versions of busybox, although we're - still working out the bugs.

    + still working out the bugs.

  • 16 August 2005 -- 1.01 is out @@ -827,7 +1102,7 @@ Same .config built against static uclibc: in their brains at a time. In my case, I'm lucky if I can remember my own name, much less a bug report posted last week... To prevent your bug report from getting lost, if you find a bug in BusyBox, please use the - shiny new Bug and Patch Tracking System + shiny new Bug and Patch Tracking System to post all the gory details.

    @@ -1058,7 +1333,7 @@ Same .config built against static uclibc:

    - People who rely on the daily BusyBox snapshots + People who rely on the daily BusyBox snapshots should be aware that snapshots of the old busybox 0.60.x series are no longer available. Daily snapshots are now only available for the BusyBox 1.0.0 series and now use @@ -1260,7 +1535,7 @@ Same .config built against static uclibc: If you have submitted patches, and they are not in this release and I have not emailed you explaining why your patch was rejected, it is safe to say that I have lost your patch. That - happens sometimes. Please do NOT send all your patches, + happens sometimes. Please do NOT send all your patches, support questions, etc, directly to Erik. I get hundreds of emails every day (which is why I end up losing patches sometimes in the flood)... The busybox mailing list is the @@ -1348,12 +1623,12 @@ Same .config built against static uclibc:

  • 6 March 2002 -- busybox.net now has mirrors!

    Busybox.net is now much more available, thanks to - the fine folks at http://i-netinnovations.com/ + the fine folks at http://i-netinnovations.com/ who are providing hosting for busybox.net and uclibc.org. In addition, we now have two mirrors: - http://busybox.linuxmagic.com/ + http://busybox.linuxmagic.com/ in Canada and - http://busybox.csservers.de/ + http://busybox.csservers.de/ in Germany. I hope this makes things much more accessible for everyone! @@ -1461,7 +1736,7 @@ Click here to help buy busybox.net! - + @@ -1595,7 +1870,7 @@ would be wonderful!
    The illustrious Larry Doolittle has made a PostScript chart of the growth of the Busybox tarball size over time. It is available for downloading / -viewing right here. +viewing right here.

    (Note that while the number of applets in Busybox has increased, you can still configure Busybox to be as small as you want by selectively @@ -1641,7 +1916,7 @@ image. Here's how you use it:

      -
    1. +
    2. Download the image
    3. dd it onto a floppy like so: dd if=busybox.floppy.img @@ -1767,7 +2042,7 @@ image. Here's how you use it: Also, some exciting infrastructure news! Busybox now has its own mailing list, publically browsable - CVS tree, + CVS tree, anonymous CVS access, and for those that are actively contributing there is even diff --git a/release/src/router/busybox/docs/busybox.net/products.html b/release/src/router/busybox/docs/busybox.net/products.html dissimilarity index 72% index a727d9f9a1..7bb07f71d8 100644 --- a/release/src/router/busybox/docs/busybox.net/products.html +++ b/release/src/router/busybox/docs/busybox.net/products.html @@ -1,170 +1,165 @@ - - - -

      Products/Projects Using BusyBox

      - -Do you use BusyBox? I'd love to know about it and -I'd be happy to link to you. - -

      -I know of the following products and/or projects that use BusyBox -- -listed in the order I happen to add them to the web page: - -

      - - - - + + + +

      Products/Projects Using BusyBox

      + +Do you use BusyBox? I'd love to know about it and +I'd be happy to link to you. + +

      +I know of the following projects that use BusyBox -- +listed in the order I happen to add them to the web page: + +

      + +

      +And here are products that use BusyBox -- + +

      + + diff --git a/release/src/router/busybox/docs/busybox.net/sponsors.html b/release/src/router/busybox/docs/busybox.net/sponsors.html index efbfd45d62..e52adfc8ed 100644 --- a/release/src/router/busybox/docs/busybox.net/sponsors.html +++ b/release/src/router/busybox/docs/busybox.net/sponsors.html @@ -12,35 +12,35 @@ project, consider these fine companies!

      OSU OSL kindly provides hosting for BusyBox and uClibc.
    4. -
    5. Codepoet Consulting
      +
    6. Codepoet Consulting
      Custom Linux, embedded Linux, BusyBox, and uClibc development.
    7. -
    8. Laptop Computers contributes +
    9. Laptop Computers contributes financially.
    10. -
    11. AOE media, a +
    12. AOE media, a TYPO3 development agency contributes financially.
    13. -
    14. Analog Devices, Inc. provided - a +
    15. Analog Devices, Inc. provided + a Blackfin development board free of charge. - Blackfin + Blackfin is a NOMMU processor, and its availability for testing is invaluable. If you are an embedded device developer, please note that Analog Devices has entire Linux distribution available for download for this board. Visit - http://blackfin.uclinux.org/ + http://blackfin.uclinux.org/ for more information.
    16. -
    17. TimeSys
      +
    18. TimeSys
      Embedded Linux development, cross-compilers, real-time, KGDB, tsrpm and cygwin.
    19. -
    20. Penguru Consulting
      +
    21. Penguru Consulting
      Custom development for embedded Linux systems and multimedia platforms.
    22. diff --git a/release/src/router/busybox/docs/busybox.net/subversion.html b/release/src/router/busybox/docs/busybox.net/subversion.html index 561a5b80b7..2c4517a35f 100644 --- a/release/src/router/busybox/docs/busybox.net/subversion.html +++ b/release/src/router/busybox/docs/busybox.net/subversion.html @@ -6,7 +6,7 @@

      Patches

      -

      You can download fixes for particular releases +

      You can download fixes for particular releases of busybox, e.g. downloads/fixes-major-minor-patch/

      Anonymous Subversion Access

      @@ -18,9 +18,9 @@ grab a copy of the latest version of BusyBox using anonymous svn access: svn co svn://busybox.net/trunk/busybox
  • -The current stable branch can be obtained with +The stable branches can be obtained with

    -svn co svn://busybox.net/branches/busybox_1_9_stable
    +svn co svn://busybox.net/branches/busybox_1_NN_stable
     

    diff --git a/release/src/router/busybox/docs/busybox.net/svnindex.css b/release/src/router/busybox/docs/busybox.net/svnindex.css new file mode 100644 index 0000000000..b1ca24a054 --- /dev/null +++ b/release/src/router/busybox/docs/busybox.net/svnindex.css @@ -0,0 +1,92 @@ +/* A sample style sheet for displaying the Subversion directory listing + that is generated by mod_dav_svn and "svnindex.xsl". */ + +body{ + margin: 0; + padding: 0; +} + +a { + color: navy; +} + +.header { + padding-top: 5px; + text-align: center; +} + +.footer { + margin-top: 8em; + padding: 0.5em 1em 0.5em; + border: 1px solid; + border-width: 1px 0; + clear: both; + border-color: rgb(30%,30%,50%) navy rgb(75%,80%,85%) navy; + background: rgb(88%,90%,92%); + font-size: 80%; +} + +.svn { + margin: 3em; +} + +.rev { + margin-right: 3px; + padding-left: 3px; + text-align: left; + font-size: 120%; +} + +.dir a { + text-decoration: none; + color: black; +} + +.file a { + text-decoration: none; + color: black; +} + +.path { + margin: 3px; + padding: 3px; + background: #FFCC66; + font-size: 120%; +} + +.updir { + margin: 3px; + padding: 3px; + margin-left: 3em; + background: #FFEEAA; +} + +.file { + margin: 3px; + padding: 3px; + margin-left: 3em; + background: rgb(95%,95%,95%); +} + +.file:hover { + margin: 3px; + padding: 3px; + margin-left: 3em; + background: rgb(100%,100%,90%); +/* border: 1px black solid; */ +} + +.dir { + margin: 3px; + padding: 3px; + margin-left: 3em; + background: rgb(90%,90%,90%); +} + +.dir:hover { + margin: 3px; + padding: 3px; + margin-left: 3em; + background: rgb(100%,100%,80%); +/* border: 1px black solid; */ +} diff --git a/release/src/router/busybox/docs/busybox.net/svnindex.xsl b/release/src/router/busybox/docs/busybox.net/svnindex.xsl new file mode 100644 index 0000000000..2d3297c4c9 --- /dev/null +++ b/release/src/router/busybox/docs/busybox.net/svnindex.xsl @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + <xsl:if test="string-length(index/@name) != 0"> + <xsl:value-of select="index/@name"/> + <xsl:text>: </xsl:text> + </xsl:if> + <xsl:value-of select="index/@path"/> + + + + +

    + BUSYBOX +
    +
    + +
    +
    + +
    + + + + + + +
    + + + + + + + + + + + + Revision + + +
    +
    + +
    + + + +
    + + +
    + [ + + .. + Parent Directory + + ] +
    +
    + + +
    + + + + + + / + +
    +
    + + +
    + + + + + + +
    +
    + + diff --git a/release/src/router/busybox/docs/busybox.net/tinyutils.html b/release/src/router/busybox/docs/busybox.net/tinyutils.html index 9122d6e352..18313460ce 100644 --- a/release/src/router/busybox/docs/busybox.net/tinyutils.html +++ b/release/src/router/busybox/docs/busybox.net/tinyutils.html @@ -9,7 +9,7 @@ dev mailing list.

    - +
    @@ -44,42 +44,42 @@ version of links.

    SCRIPTING LANGUAGES

    Although busybox has built-in support for shell scripts, plenty of other small scripting languages are available on the net. A few examples:

    -
    Feature Utilities
    +
    - - + + - + - - + - + - +
    languagedescription
    microperl microperl A small standalone perl interpreter that can be built from the perl source s via "make -f Makefile.micro". If you really feel the need for perl on an embe dded system, this is where to start.
    LuaIf you just want a small embedded scripting language to write new +LuaIf you just want a small embedded scripting language to write new code in, this Brazilian import is lightweight, fairly popular, and has a complete book about it online.
    rcrc The PLAN9 shell. Not compatible with conventional bourne shell syntax, but fairly lightweight and small.
    forthforth A well known language for fast and small programs, decades old but still in use for everything from OpenBIOS to computer controlled engine timing.

    For more information, you probably want to look at -buildroot and -TinyGentoo, which +buildroot and +TinyGentoo, which build and use tiny utilities for all sorts of things.

    diff --git a/release/src/router/busybox/docs/busybox_header.pod b/release/src/router/busybox/docs/busybox_header.pod index 804b839703..9f2ffc48dc 100644 --- a/release/src/router/busybox/docs/busybox_header.pod +++ b/release/src/router/busybox/docs/busybox_header.pod @@ -6,9 +6,9 @@ BusyBox - The Swiss Army Knife of Embedded Linux =head1 SYNTAX - BusyBox [arguments...] # or + busybox [arguments...] # or - [arguments...] # if symlinked + [arguments...] # if symlinked =head1 DESCRIPTION @@ -45,7 +45,8 @@ BusyBox is a multi-call binary. A multi-call binary is an executable program that performs the same job as more than one utility program. That means there is just a single BusyBox binary, but that single binary acts like a large number of utilities. This allows BusyBox to be smaller since all the built-in -utility programs (we call them applets) can share code for many common operations. +utility programs (we call them applets) can share code for many common +operations. You can also invoke BusyBox by issuing a command as an argument on the command line. For example, entering @@ -72,11 +73,11 @@ applets that have been compiled into your BusyBox binary. =head1 COMMON OPTIONS -Most BusyBox commands support the B<--help> argument to provide a terse runtime +Most BusyBox applets support the B<--help> argument to provide a terse runtime description of their behavior. If the CONFIG_FEATURE_VERBOSE_USAGE option has been enabled, more detailed usage information will also be available. =head1 COMMANDS -Currently defined functions include: +Currently available applets include: diff --git a/release/src/router/busybox/docs/logging_and_backgrounding.txt b/release/src/router/busybox/docs/logging_and_backgrounding.txt new file mode 100644 index 0000000000..62a6d15503 --- /dev/null +++ b/release/src/router/busybox/docs/logging_and_backgrounding.txt @@ -0,0 +1,96 @@ + Logging and backgrounding + +By default, bb_[p]error_msg[_and_die] messages go to stderr, +and of course, usually applets do not auto-background. :) + +Historically, daemons and inetd services are different. + +Busybox is trying to provide compatible behavior, thus if an applet +is emulating an existing utility, it should mimic it. If utility +auto-backgrounds itself, busybox applet should do the same. +If utility normally logs to syslog, busybox applet should do +the same too. + +However, busybox should not needlessly restrict the freedom +of the users. And users have different needs and different preferences. +Some might like logging everything from daemons to syslog. +Others prefer running stuff under runsv/svlogd and thus would like +logging to stderr and no daemonization. + +To help with that, busybox applets should have options to override +default behavior, whatever that is for a given applet. + + +Current sutiation is a bit of a mess: + +acpid - auto-backgrounds unless -d +crond - auto-backgrounds unless -f, logs to syslog unless -d or -L. + option -d logs to stderr, -L FILE logs to FILE +devfsd - (obsolete) +dnsd - option -d makes it background and log to syslog +fakeidentd - inetd service. Auto-backgrounds and logs to syslog + if no -f and no -i and no -w (-i is "inetd service" flag, + -w is "inetd-wait service" flag) +ftpd - inetd service. Logs to syslog with -S, with -v logs to strerr too +httpd - auto-backgrounds unless -f or -i (-i is "inetd service" flag) +inetd - auto-backgrounds unless -f, logs to syslog unless -e +klogd - auto-backgrounds unless -n +syslogd - auto-backgrounds unless -n +telnetd - auto-backgrounds unless -f or -i (-i is "inetd service" flag) +udhcpc - auto-backgrounds unless -f after lease is obtained, + option -b makes it background sooner (when lease attempt + fails and retries start), + after backgrounding it stops logging to stderr; + logs to stderr, but option -S makes it log *also* to syslog +udhcpd - auto-backgrounds and do not log to stderr unless -f, + otherwise logs to stderr, but option -S makes it log *also* to syslog +zcip - auto-backgrounds and logs *also* to syslog unless -f + +Total: 13 applets (+1 obsolete), + 4 log to syslog by default (crond fakeidentd inetd zcip), + 5 never log to syslog (acpid httpd telnetd klogd syslogd, last two + - for obviously correct reasons), + there are no daemons which always log to syslog, + 12 auto-background if not run as inetd servies (all except dnsd. + Note that there is no "standard" dnsd AFAIKS). But see below + for daemons (tcpsvd etc) which don't auto-background. + +miscutils/crond.c: logmode = LOGMODE_SYSLOG; +networking/dnsd.c: logmode = LOGMODE_SYSLOG; +networking/ftpd.c: logmode = LOGMODE_NONE; +networking/ftpd.c: logmode |= LOGMODE_SYSLOG; +networking/inetd.c: logmode = LOGMODE_SYSLOG; +networking/isrv_identd.c: logmode = LOGMODE_SYSLOG; +networking/telnetd.c: logmode = LOGMODE_SYSLOG; +networking/udhcp/dhcpc.c: logmode = LOGMODE_NONE; +networking/udhcp/dhcpc.c: logmode |= LOGMODE_SYSLOG; +networking/udhcp/dhcpc.c: logmode &= ~LOGMODE_STDIO; +networking/udhcp/dhcpd.c: logmode = LOGMODE_NONE; +networking/udhcp/dhcpd.c: logmode |= LOGMODE_SYSLOG; +networking/zcip.c: logmode |= LOGMODE_SYSLOG; + + +These daemons never auto-background and never log to syslog: + +lpd - inetd service. Has nothing to log so far, though +dhcprelay - standard behavior +inotifyd - standard behavior +runsv - standard behavior +runsvdir - standard behavior +svlogd - standard behavior +tcpsvd, udpsvd - standard behavior +tftpd - standard behavior + + +Non-daemons (seems to be use syslog for a good reason): + +networking/nameif.c: logmode |= LOGMODE_SYSLOG; +loginutils/chpasswd.c: logmode = LOGMODE_BOTH; +loginutils/chpasswd.c: logmode = LOGMODE_STDIO; +loginutils/getty.c: logmode = LOGMODE_BOTH; +loginutils/getty.c: logmode = LOGMODE_NONE; +loginutils/passwd.c: logmode = LOGMODE_STDIO; +loginutils/passwd.c: logmode = LOGMODE_BOTH; +loginutils/sulogin.c: logmode = LOGMODE_SYSLOG; (used if stdio isn't a tty) +loginutils/sulogin.c: logmode = LOGMODE_BOTH; +util-linux/mount.c: logmode = LOGMODE_SYSLOG; (used in a backgrounded NFS mount helper) diff --git a/release/src/router/busybox/docs/mdev.txt b/release/src/router/busybox/docs/mdev.txt index 63ad406021..a8a816ce9d 100644 --- a/release/src/router/busybox/docs/mdev.txt +++ b/release/src/router/busybox/docs/mdev.txt @@ -51,9 +51,11 @@ device nodes if your system needs something more than the default root/root 660 permissions. The file has the format: - : + : + or @ : + 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 diff --git a/release/src/router/busybox/e2fsprogs/e2fs_defs.h b/release/src/router/busybox/e2fsprogs/e2fs_defs.h index b3ea3ae344..379640eb88 100644 --- a/release/src/router/busybox/e2fsprogs/e2fs_defs.h +++ b/release/src/router/busybox/e2fsprogs/e2fs_defs.h @@ -10,8 +10,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT2_FS_H -#define _LINUX_EXT2_FS_H +#ifndef LINUX_EXT2_FS_H +#define LINUX_EXT2_FS_H 1 /* * Special inode numbers @@ -558,4 +558,4 @@ struct ext2_dir_entry_2 { #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) -#endif /* _LINUX_EXT2_FS_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/e2fs_lib.c b/release/src/router/busybox/e2fsprogs/e2fs_lib.c index 839109e3f7..3e8d956872 100644 --- a/release/src/router/busybox/e2fsprogs/e2fs_lib.c +++ b/release/src/router/busybox/e2fsprogs/e2fs_lib.c @@ -2,8 +2,7 @@ /* * See README for additional information * - * This file can be redistributed under the terms of the GNU Library General - * Public License + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" diff --git a/release/src/router/busybox/e2fsprogs/e2fs_lib.h b/release/src/router/busybox/e2fsprogs/e2fs_lib.h index e21a0f917e..25b26d3824 100644 --- a/release/src/router/busybox/e2fsprogs/e2fs_lib.h +++ b/release/src/router/busybox/e2fsprogs/e2fs_lib.h @@ -9,9 +9,7 @@ /* Constants and structures */ #include "e2fs_defs.h" -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* Iterate a function on each entry of a directory */ int iterate_on_dir(const char *dir_name, @@ -46,6 +44,4 @@ extern const char e2attr_flags_sname[]; #define e2attr_flags_sname_chattr (&e2attr_flags_sname[1]) #endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY diff --git a/release/src/router/busybox/e2fsprogs/fsck.c b/release/src/router/busybox/e2fsprogs/fsck.c index 3c4dabc489..3c6cafbd3f 100644 --- a/release/src/router/busybox/e2fsprogs/fsck.c +++ b/release/src/router/busybox/e2fsprogs/fsck.c @@ -20,10 +20,7 @@ * 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% + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ /* All filesystem specific hooks have been removed. @@ -313,10 +310,10 @@ static void load_fs_info(const char *filename) // 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_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_type, mte.mnt_opts, mte.mnt_passno); } endmntent(fstab); diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkid.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkid.h index 4fa9f6fdf8..9a3c2afdbd 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkid.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkid.h @@ -10,9 +10,8 @@ * GNU Lesser General Public License. * %End-Header% */ - -#ifndef _BLKID_BLKID_H -#define _BLKID_BLKID_H +#ifndef BLKID_BLKID_H +#define BLKID_BLKID_H 1 #include #include @@ -102,4 +101,4 @@ extern int blkid_parse_tag_string(const char *token, char **ret_type, } #endif -#endif /* _BLKID_BLKID_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkidP.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkidP.h index c7cb8abe94..d6b2b42cc5 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkidP.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/blkidP.h @@ -10,9 +10,8 @@ * GNU Lesser General Public License. * %End-Header% */ - -#ifndef _BLKID_BLKIDP_H -#define _BLKID_BLKIDP_H +#ifndef BLKID_BLKIDP_H +#define BLKID_BLKIDP_H 1 #include #include @@ -184,4 +183,4 @@ extern void blkid_free_dev(blkid_dev dev); } #endif -#endif /* _BLKID_BLKIDP_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/devname.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/devname.c index 5b9e48f13b..348e5d42e5 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/devname.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/devname.c @@ -273,7 +273,7 @@ int blkid_probe_all(blkid_cache cache) return -BLKID_ERR_PARAM; if (cache->bic_flags & BLKID_BIC_FL_PROBED && - time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) + time(NULL) - cache->bic_time < BLKID_PROBE_INTERVAL) return 0; blkid_read_cache(cache); @@ -335,7 +335,7 @@ int blkid_probe_all(blkid_cache cache) fclose(proc); - cache->bic_time = time(0); + cache->bic_time = time(NULL); cache->bic_flags |= BLKID_BIC_FL_PROBED; blkid_flush_cache(cache); return 0; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/list.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/list.h index 8b06d853bb..a24baaa912 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/list.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/list.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ #if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD) -#define _BLKID_LIST_H +#define BLKID_LIST_H 1 #ifdef __cplusplus extern "C" { @@ -70,4 +70,4 @@ void list_splice(struct list_head *list, struct list_head *head); } #endif -#endif /* _BLKID_LIST_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c index 48b240e98e..1f7188e6d6 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c @@ -562,7 +562,7 @@ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) if (!dev) return NULL; - now = time(0); + now = time(NULL); diff = now - dev->bid_time; if ((now < dev->bid_time) || @@ -659,7 +659,7 @@ try_again: found_type: if (dev && type) { dev->bid_devno = st.st_rdev; - dev->bid_time = time(0); + dev->bid_time = time(NULL); dev->bid_flags |= BLKID_BID_FL_VERIFIED; cache->bic_flags |= BLKID_BIC_FL_CHANGED; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h index 0fd16a7716..b6d8f8e7dd 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h @@ -11,9 +11,8 @@ * GNU Lesser General Public License. * %End-Header% */ - -#ifndef _BLKID_PROBE_H -#define _BLKID_PROBE_H +#ifndef BLKID_PROBE_H +#define BLKID_PROBE_H 1 #include @@ -308,9 +307,9 @@ _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 */ + __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 @@ -319,9 +318,9 @@ _INLINE_ __u32 blkid_swab32(__u32 val) _INLINE_ __u16 blkid_swab16(__u16 val) { - __asm__("xchgb %b0,%h0" /* swap bytes */ \ - : "=q" (val) \ - : "0" (val)); \ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (val) + : "0" (val)); return val; } diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsbb.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsbb.h index 78e7cbd04c..d31c319556 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsbb.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsbb.h @@ -6,8 +6,8 @@ * instead. This makes upgrade between e2fsprogs versions easy. */ -#ifndef __E2FSBB_H__ -#define __E2FSBB_H__ 1 +#ifndef E2FSBB_H +#define E2FSBB_H 1 #include "libbb.h" @@ -40,4 +40,4 @@ typedef long errcode_t; #define WORDS_BIGENDIAN 1 #endif -#endif /* __E2FSBB_H__ */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsck.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsck.c index 7cb1227db3..d1f8d1ecb9 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsck.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/e2fsck.c @@ -192,10 +192,10 @@ struct buffer_head { #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 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) +#define do_readahead(journal, start) do {} while (0) static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ @@ -2270,7 +2270,7 @@ static void e2fsck_move_ext3_journal(e2fsck_t ctx) ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; inode.i_links_count = 0; - inode.i_dtime = time(0); + inode.i_dtime = time(NULL); if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) goto err_out; @@ -3381,7 +3381,7 @@ static void e2fsck_pass1(e2fsck_t ctx) */ if (!LINUX_S_ISDIR(inode->i_mode)) { if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) { - inode->i_dtime = time(0); + inode->i_dtime = time(NULL); inode->i_links_count = 0; ext2fs_icount_store(ctx->inode_link_info, ino, 0); @@ -3475,7 +3475,7 @@ static void e2fsck_pass1(e2fsck_t ctx) inode->i_dtime < ctx->fs->super->s_inodes_count) { if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { inode->i_dtime = inode->i_links_count ? - 0 : time(0); + 0 : time(NULL); e2fsck_write_inode(ctx, ino, inode, "pass1"); } @@ -3489,7 +3489,7 @@ static void e2fsck_pass1(e2fsck_t ctx) if (!inode->i_dtime && inode->i_mode) { if (fix_problem(ctx, PR_1_ZERO_DTIME, &pctx)) { - inode->i_dtime = time(0); + inode->i_dtime = time(NULL); e2fsck_write_inode(ctx, ino, inode, "pass1"); } @@ -3659,7 +3659,7 @@ static void e2fsck_pass1(e2fsck_t ctx) } e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, "recreate inode"); - inode->i_mtime = time(0); + inode->i_mtime = time(NULL); e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, "recreate inode"); fs->block_map = save_bmap; @@ -4169,7 +4169,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, if (pb.clear) { inode->i_links_count = 0; ext2fs_icount_store(ctx->inode_link_info, ino, 0); - inode->i_dtime = time(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); @@ -4202,7 +4202,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { inode->i_links_count = 0; ext2fs_icount_store(ctx->inode_link_info, ino, 0); - inode->i_dtime = time(0); + 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); @@ -5147,7 +5147,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino, /* Inode may have changed by block_iterate, so reread it */ e2fsck_read_inode(ctx, ino, &inode, "delete_file"); inode.i_links_count = 0; - inode.i_dtime = time(0); + inode.i_dtime = time(NULL); if (inode.i_file_acl && (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { count = 1; @@ -6393,7 +6393,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) ext2fs_icount_store(ctx->inode_link_info, ino, 0); e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); inode.i_links_count = 0; - inode.i_dtime = time(0); + inode.i_dtime = time(NULL); e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; @@ -6890,7 +6890,7 @@ static void check_root(e2fsck_t ctx) memset(&inode, 0, sizeof(inode)); inode.i_mode = 040755; inode.i_size = fs->blocksize; - inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); + inode.i_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; @@ -7138,7 +7138,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; - inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); + inode.i_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; @@ -7492,7 +7492,7 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i) if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { ext2fs_icount_store(ctx->inode_link_info, i, 0); inode.i_links_count = 0; - inode.i_dtime = time(0); + inode.i_dtime = time(NULL); e2fsck_write_inode(ctx, i, &inode, "disconnect_inode"); /* @@ -10014,7 +10014,7 @@ static int do_one_pass(journal_t *journal, * all of the sequence number checks. What are we going * to do with it? That depends on the pass... */ - switch(blocktype) { + switch (blocktype) { case JFS_DESCRIPTOR_BLOCK: /* If it is a valid descriptor block, replay it * in pass REPLAY; otherwise, just skip over the @@ -11158,7 +11158,7 @@ int journal_init_revoke(journal_t *journal, int hash_size) shift = 0; tmp = hash_size; - while((tmp >>= 1UL) != 0UL) + while ((tmp >>= 1UL) != 0UL) shift++; journal->j_revoke->hash_shift = shift; @@ -11558,7 +11558,7 @@ static int release_orphan_inodes(e2fsck_t ctx) if (!inode.i_links_count) { ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); - inode.i_dtime = time(0); + inode.i_dtime = time(NULL); } else { inode.i_dtime = 0; } @@ -12251,7 +12251,7 @@ static int read_a_char(void) int r; int fail = 0; - while(1) { + while (1) { if (e2fsck_global_ctx && (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) { return 3; @@ -12281,7 +12281,7 @@ static int ask_yn(const char * string, int def) tmp.c_lflag &= ~(ICANON | ECHO); tmp.c_cc[VMIN] = 1; tmp.c_cc[VTIME] = 0; - tcsetattr (0, TCSANOW, &tmp); + tcsetattr_stdin_TCSANOW(&tmp); #endif if (def == 1) @@ -12297,7 +12297,7 @@ static int ask_yn(const char * string, int def) break; if (c == 3) { #ifdef HAVE_TERMIOS_H - tcsetattr (0, TCSANOW, &termios); + tcsetattr_stdin_TCSANOW(&termios); #endif if (e2fsck_global_ctx && e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) { @@ -12323,7 +12323,7 @@ static int ask_yn(const char * string, int def) else puts ("no\n"); #ifdef HAVE_TERMIOS_H - tcsetattr (0, TCSANOW, &termios); + tcsetattr_stdin_TCSANOW(&termios); #endif return def; } @@ -12632,7 +12632,7 @@ static void check_mount(e2fsck_t ctx) retval = ext2fs_check_if_mounted(ctx->filesystem_name, &ctx->mount_flags); if (retval) { - bb_error_msg(_("while determining whether %s is mounted."), + bb_error_msg(_("while determining whether %s is mounted"), ctx->filesystem_name); return; } @@ -12653,7 +12653,7 @@ static void check_mount(e2fsck_t ctx) printf(_("%s is mounted. "), ctx->filesystem_name); if (!ctx->interactive) - bb_error_msg_and_die(_("Cannot continue, aborting.")); + bb_error_msg_and_die(_("cannot continue, aborting")); printf(_("\n\n\007\007\007\007WARNING!!! " "Running e2fsck on a mounted filesystem may cause\n" "SEVERE filesystem damage.\007\007\007\n\n")); @@ -12714,7 +12714,7 @@ static void check_if_skip(e2fsck_t ctx) unsigned int reason_arg = 0; long next_check; int batt = is_on_batt(); - time_t now = time(0); + time_t now = time(NULL); if ((ctx->options & E2F_OPT_FORCE) || cflag || swapfs) return; @@ -12892,7 +12892,7 @@ static int e2fsck_update_progress(e2fsck_t ctx, int pass, if (ctx->progress_fd) { sprintf(buf, "%d %lu %lu\n", pass, cur, max); - write(ctx->progress_fd, buf, strlen(buf)); + xwrite_str(ctx->progress_fd, buf); } else { percent = calc_percent(&e2fsck_tbl, pass, cur, max); e2fsck_simple_progress(ctx, ctx->device_name, @@ -13060,7 +13060,7 @@ static errcode_t PRS(int argc, char **argv, e2fsck_t *ret_ctx) 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.")); + bb_error_msg_and_die(_("only one the options -p/-a, -n or -y may be specified")); } ctx->options |= E2F_OPT_PREEN; break; @@ -13405,7 +13405,7 @@ restart: #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.")); + bb_error_msg(_("warning: compression support is experimental")); #endif #ifndef ENABLE_HTREE if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c index 855f86eac9..1deae54e81 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c @@ -125,9 +125,9 @@ errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list) if (retval) goto cleanup; - inode.i_atime = inode.i_mtime = time(0); + inode.i_atime = inode.i_mtime = time(NULL); if (!inode.i_ctime) - inode.i_ctime = time(0); + inode.i_ctime = time(NULL); inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512); inode.i_size = rec.bad_block_count * fs->blocksize; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c index ab3243fd77..09e34be3b6 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c @@ -42,7 +42,7 @@ static void TEA_transform(__u32 buf[4], __u32 const in[]) sum += DELTA; b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); - } while(--n); + } while (--n); buf[0] += b0; buf[1] += b1; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h index cb49d7a600..6f4f708628 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h @@ -13,9 +13,8 @@ * * Copyright (C) 1991, 1992 Linus Torvalds */ - -#ifndef _LINUX_EXT2_FS_H -#define _LINUX_EXT2_FS_H +#ifndef LINUX_EXT2_FS_H +#define LINUX_EXT2_FS_H 1 #include "ext2_types.h" /* Changed from linux/types.h */ @@ -567,4 +566,4 @@ struct ext2_dir_entry_2 { #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) -#endif /* _LINUX_EXT2_FS_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h index e6c9630e2c..1900a76392 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h @@ -9,9 +9,8 @@ * License. * %End-Header% */ - -#ifndef _EXT2FS_EXT2_IO_H -#define _EXT2FS_EXT2_IO_H +#ifndef EXT2FS_EXT2_IO_H +#define EXT2FS_EXT2_IO_H 1 /* * ext2_loff_t is defined here since unix_io.c needs it. @@ -110,5 +109,4 @@ extern void (*test_io_cb_write_blk) extern void (*test_io_cb_set_blksize) (int blksize, errcode_t err); -#endif /* _EXT2FS_EXT2_IO_H */ - +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h index 133fb1f1b1..9f772016f8 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h @@ -9,9 +9,8 @@ * License. * %End-Header% */ - -#ifndef _EXT2FS_EXT2FS_H -#define _EXT2FS_EXT2FS_H +#ifndef EXT2FS_EXT2FS_H +#define EXT2FS_EXT2FS_H 1 #define EXT2FS_ATTR(x) @@ -920,4 +919,4 @@ extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, } #endif -#endif /* _EXT2FS_EXT2FS_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h index 4c6c7dedd3..853d97ac7f 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h @@ -13,9 +13,8 @@ * Definitions for transaction data structures for the buffer cache * filesystem journaling support. */ - -#ifndef _LINUX_JBD_H -#define _LINUX_JBD_H +#ifndef LINUX_JBD_H +#define LINUX_JBD_H 1 #include #include @@ -233,4 +232,4 @@ extern void journal_brelse_array(struct buffer_head *b[], int n); extern void journal_destroy_revoke(journal_t *); -#endif /* _LINUX_JBD_H */ +#endif diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h index 3392596ca8..d80716a454 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H +#ifndef LINUX_LIST_H +#define LINUX_LIST_H 1 /* * Simple doubly linked list implementation. diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c index 5bdd346820..af47aee18b 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c @@ -231,7 +231,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, inode.i_size += fs->blocksize * size; inode.i_blocks += (fs->blocksize / 512) * es.newblocks; - inode.i_mtime = inode.i_ctime = time(0); + inode.i_mtime = inode.i_ctime = time(NULL); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c index f7ee8b1fb3..3c550d511e 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c @@ -113,11 +113,11 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) inode_size *= fs->blocksize; inode.i_size = inode_size & 0xFFFFFFFF; inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; - if(inode.i_size_high) { + if (inode.i_size_high) { sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; } - inode.i_ctime = time(0); + inode.i_ctime = time(NULL); } for (rsv_off = 0, gdt_off = fs->desc_blocks, @@ -209,7 +209,7 @@ out_inode: inode.i_size); #endif if (inode_dirty) { - inode.i_atime = inode.i_mtime = time(0); + inode.i_atime = inode.i_mtime = time(NULL); retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode); if (!retval) retval = retval2; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/fsck.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/fsck.c index 9cb9f754db..98e4e38fee 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/fsck.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/fsck.c @@ -20,10 +20,7 @@ * 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% + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include @@ -533,21 +530,21 @@ static struct fs_info *lookup(char *filesys) /* 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; + 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"); + /* 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; + 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) @@ -885,7 +882,7 @@ static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) list = string_copy(fs_type); num = 0; s = strtok(list, ","); - while(s) { + while (s) { negate = 0; if (strncmp(s, "no", 2) == 0) { s += 2; @@ -930,7 +927,7 @@ static int opt_in_list(char *opt, char *optlist) list = string_copy(optlist); s = strtok(list, ","); - while(s) { + while (s) { if (strcmp(s, opt) == 0) { free(list); return 1; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/mke2fs.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/mke2fs.c index 852c249b10..a1327437d7 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/mke2fs.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/mke2fs.c @@ -5,8 +5,7 @@ * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, * 2003, 2004, 2005 by Theodore Ts'o. * - * This file may be redistributed under the terms of the GNU Public - * License. + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ /* Usage: mke2fs [options] device @@ -676,7 +675,7 @@ static int set_os(struct ext2_super_block *sb, char *os) return 1; } - if((sb->s_creator_os = e2p_string2os(os)) >= 0) { + if ((sb->s_creator_os = e2p_string2os(os)) >= 0) { return 1; } else if (!strcasecmp("GNU", os)) { sb->s_creator_os = EXT2_OS_HURD; @@ -1187,7 +1186,7 @@ int mke2fs_main (int argc, char **argv) if (ENABLE_FEATURE_CLEAN_UP) atexit(mke2fs_clean_up); - if(!PRS(argc, argv)) + if (!PRS(argc, argv)) return 0; #ifdef CONFIG_TESTIO_DEBUG diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/tune2fs.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/tune2fs.c index b7a1b21eb0..1d39ed1b04 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/tune2fs.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/tune2fs.c @@ -8,10 +8,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. * - * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. - * %End-Header% + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ /* diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/util.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/util.c index b30c294b8b..7ab6591d58 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/util.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/util.c @@ -4,10 +4,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. * - * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. - * %End-Header% + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include @@ -37,7 +34,7 @@ void check_plausibility(const char *device, int force) val = stat(device, &s); if (force) return; - if(val == -1) + if (val == -1) bb_perror_msg_and_die("cannot stat %s", device); if (!S_ISBLK(s.st_mode)) { printf("%s is not a block special device.\n", device); @@ -220,13 +217,13 @@ void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int fo fs->blocksize, io_ptr, &jfs); if (retval) bb_error_msg_and_die("cannot journal device %s", journal_device); - if(!quiet) + if (!quiet) printf("Adding journal to device %s: ", journal_device); fflush(stdout); retval = ext2fs_add_journal_device(fs, jfs); - if(retval) + if (retval) bb_error_msg_and_die("\nFailed to add journal to device %s", journal_device); - if(!quiet) + if (!quiet) puts("done"); ext2fs_close(jfs); } @@ -242,14 +239,14 @@ void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, in ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; return; } - if(!quiet) + if (!quiet) printf("Creating journal (%ld blocks): ", journal_blocks); fflush(stdout); retval = ext2fs_add_journal_inode(fs, journal_blocks, journal_flags); - if(retval) + if (retval) bb_error_msg_and_die("cannot create journal"); - if(!quiet) + if (!quiet) puts("done"); } @@ -262,6 +259,6 @@ char *e2fs_set_sbin_path(void) oldpath = xasprintf("%s:%s", PATH_SET, oldpath); else oldpath = PATH_SET; - putenv (oldpath); + putenv(oldpath); return oldpath; } diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c index 03a9f376a5..4310c17db9 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c @@ -165,7 +165,7 @@ static int get_node_id(unsigned char *node_id) n = ifc.ifc_len; for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); - strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.ifr_name, ifrp->ifr_name); #ifdef SIOCGIFHWADDR if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) continue; diff --git a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/uuid.h b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/uuid.h index b30ca3c629..7a9706449b 100644 --- a/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/uuid.h +++ b/release/src/router/busybox/e2fsprogs/old_e2fsprogs/uuid/uuid.h @@ -32,9 +32,8 @@ * DAMAGE. * %End-Header% */ - -#ifndef _UUID_UUID_H -#define _UUID_UUID_H +#ifndef UUID_UUID_H +#define UUID_UUID_H 1 #include #include diff --git a/release/src/router/busybox/editors/Config.in b/release/src/router/busybox/editors/Config.in index 27426bc2e3..7dbc9b6da6 100644 --- a/release/src/router/busybox/editors/Config.in +++ b/release/src/router/busybox/editors/Config.in @@ -12,9 +12,9 @@ config AWK Awk is used as a pattern scanning and processing language. This is the BusyBox implementation of that programming language. -config FEATURE_AWK_MATH +config FEATURE_AWK_LIBM bool "Enable math functions (requires libm)" - default y + default n depends on AWK help Enable math functions of the Awk programming language. diff --git a/release/src/router/busybox/editors/awk.c b/release/src/router/busybox/editors/awk.c index 72eca245f0..89ce2cfc81 100644 --- a/release/src/router/busybox/editors/awk.c +++ b/release/src/router/busybox/editors/awk.c @@ -366,25 +366,22 @@ static const uint32_t tokeninfo[] = { enum { CONVFMT, OFMT, FS, OFS, ORS, RS, RT, FILENAME, - SUBSEP, ARGIND, ARGC, ARGV, - ERRNO, FNR, - NR, NF, IGNORECASE, - ENVIRON, F0, NUM_INTERNAL_VARS + SUBSEP, F0, ARGIND, ARGC, + ARGV, ERRNO, FNR, NR, + NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS }; static const char vNames[] ALIGN1 = "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" "ORS\0" "RS\0*" "RT\0" "FILENAME\0" - "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0" - "ERRNO\0" "FNR\0" - "NR\0" "NF\0*" "IGNORECASE\0*" - "ENVIRON\0" "$\0*" "\0"; + "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0" + "ARGV\0" "ERRNO\0" "FNR\0" "NR\0" + "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0"; static const char vValues[] ALIGN1 = "%.6g\0" "%.6g\0" " \0" " \0" "\n\0" "\n\0" "\0" "\0" - "\034\0" - "\377"; + "\034\0" "\0" "\377"; /* hash size may grow to these values */ #define FIRST_PRIME 61 @@ -392,8 +389,12 @@ static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 }; /* Globals. Split in two parts so that first one is addressed - * with (mostly short) negative offsets */ + * with (mostly short) negative offsets. + * NB: it's unsafe to put members of type "double" + * into globals2 (gcc may fail to align them). + */ struct globals { + double t_double; chain beginseq, mainseq, endseq; chain *seq; node *break_ptr, *continue_ptr; @@ -442,16 +443,16 @@ struct globals2 { tsplitter exec_builtin__tspl; /* biggest and least used members go last */ - double t_double; tsplitter fsplitter, rsplitter; }; #define G1 (ptr_to_globals[-1]) #define G (*(struct globals2 *)ptr_to_globals) /* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */ -/* char G1size[sizeof(G1)]; - 0x6c */ -/* char Gsize[sizeof(G)]; - 0x1cc */ +/*char G1size[sizeof(G1)]; - 0x74 */ +/*char Gsize[sizeof(G)]; - 0x1c4 */ /* Trying to keep most of members accessible with short offsets: */ -/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ +/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ +#define t_double (G1.t_double ) #define beginseq (G1.beginseq ) #define mainseq (G1.mainseq ) #define endseq (G1.endseq ) @@ -479,7 +480,6 @@ struct globals2 { #define t_info (G.t_info ) #define t_tclass (G.t_tclass ) #define t_string (G.t_string ) -#define t_double (G.t_double ) #define t_lineno (G.t_lineno ) #define t_rollback (G.t_rollback ) #define intvar (G.intvar ) @@ -512,7 +512,7 @@ static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; -#if !ENABLE_FEATURE_AWK_MATH +#if !ENABLE_FEATURE_AWK_LIBM static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; #endif @@ -604,8 +604,8 @@ static void *hash_find(xhash *hash, const char *name) hash_rebuild(hash); l = strlen(name) + 1; - hi = xzalloc(sizeof(hash_item) + l); - memcpy(hi->name, name, l); + hi = xzalloc(sizeof(*hi) + l); + strcpy(hi->name, name); idx = hashidx(name) % hash->csize; hi->next = hash->items[idx]; @@ -681,6 +681,18 @@ static ALWAYS_INLINE int isalnum_(int c) return (isalnum(c) || c == '_'); } +static double my_strtod(char **pp) +{ +#if ENABLE_DESKTOP + if ((*pp)[0] == '0' + && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1])) + ) { + return strtoull(*pp, pp, 0); + } +#endif + return strtod(*pp, pp); +} + /* -------- working with variables (set/get/copy/etc) -------- */ static xhash *iamarray(var *v) @@ -790,7 +802,7 @@ static double getvar_i(var *v) v->number = 0; s = v->string; if (s && *s) { - v->number = strtod(s, &s); + v->number = my_strtod(&s); if (v->type & VF_USER) { skip_spaces(&s); if (*s != '\0') @@ -804,6 +816,19 @@ static double getvar_i(var *v) return v->number; } +/* Used for operands of bitwise ops */ +static unsigned long getvar_i_int(var *v) +{ + double d = getvar_i(v); + + /* Casting doubles to longs is undefined for values outside + * of target type range. Try to widen it as much as possible */ + if (d >= 0) + return (unsigned long)d; + /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */ + return - (long) (unsigned long) (-d); +} + static var *copyvar(var *dest, const var *src) { if (dest != src) { @@ -973,12 +998,7 @@ static uint32_t next_token(uint32_t expected) } else if (*p == '.' || isdigit(*p)) { /* it's a number */ -#if ENABLE_DESKTOP - if (p[0] == '0' && (p[1] | 0x20) == 'x') - t_double = strtoll(p, &p, 0); - else -#endif - t_double = strtod(p, &p); + t_double = my_strtod(&p); if (*p == '.') syntax_error(EMSG_UNEXP_TOKEN); tc = TC_NUMBER; @@ -1462,6 +1482,7 @@ static node *mk_splitter(const char *s, tsplitter *spl) */ static regex_t *as_regex(node *op, regex_t *preg) { + int cflags; var *v; const char *s; @@ -1470,7 +1491,17 @@ static regex_t *as_regex(node *op, regex_t *preg) } v = nvalloc(1); s = getvar_s(evaluate(op, v)); - xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); + + cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; + /* Testcase where REG_EXTENDED fails (unpaired '{'): + * echo Hi | awk 'gsub("@(samp|code|file)\{","");' + * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED + * (maybe gsub is not supposed to use REG_EXTENDED?). + */ + if (regcomp(preg, s, cflags)) { + cflags &= ~REG_EXTENDED; + xregcomp(preg, s, cflags); + } nvfree(v); return preg; } @@ -1543,7 +1574,10 @@ static int awk_split(const char *s, node *spl, char **slist) if (s[l]) pmatch[0].rm_eo++; } memcpy(s1, s, l); - s1[l] = '\0'; + /* make sure we remove *all* of the separator chars */ + while (l < pmatch[0].rm_eo) { + s1[l++] = '\0'; + } nextword(&s1); s += pmatch[0].rm_eo; } while (*s); @@ -1836,7 +1870,6 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i return r; } - /* formatted output into an allocated buffer, return ptr to buffer */ static char *awk_printf(node *n) { @@ -2004,8 +2037,8 @@ static var *exec_builtin(node *op, var *res) switch (info & OPNMASK) { case B_a2: -#if ENABLE_FEATURE_AWK_MATH - setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); +#if ENABLE_FEATURE_AWK_LIBM + setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); #else syntax_error(EMSG_NO_MATH); #endif @@ -2022,7 +2055,7 @@ static var *exec_builtin(node *op, var *res) n = awk_split(as[0], spl, &s); s1 = s; clear_array(iamarray(av[1])); - for (i=1; i<=n; i++) + for (i = 1; i <= n; i++) setari_u(av[1], i, nextword(&s1)); free(s); setvar_i(res, n); @@ -2042,27 +2075,27 @@ static var *exec_builtin(node *op, var *res) /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5: * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */ case B_an: - setvar_i(res, (unsigned long)getvar_i(av[0]) & (unsigned long)getvar_i(av[1])); + setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1])); break; case B_co: - setvar_i(res, ~(unsigned long)getvar_i(av[0])); + setvar_i(res, ~getvar_i_int(av[0])); break; case B_ls: - setvar_i(res, (unsigned long)getvar_i(av[0]) << (unsigned long)getvar_i(av[1])); + setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1])); break; case B_or: - setvar_i(res, (unsigned long)getvar_i(av[0]) | (unsigned long)getvar_i(av[1])); + setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1])); break; case B_rs: - setvar_i(res, (unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])); + setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1])); break; case B_xo: - setvar_i(res, (unsigned long)getvar_i(av[0]) ^ (unsigned long)getvar_i(av[1])); + setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1])); break; case B_lo: @@ -2445,7 +2478,7 @@ static var *evaluate(node *op, var *res) case F_rn: R.d = (double)rand() / (double)RAND_MAX; break; -#if ENABLE_FEATURE_AWK_MATH +#if ENABLE_FEATURE_AWK_LIBM case F_co: R.d = cos(L.d); break; @@ -2613,7 +2646,7 @@ static var *evaluate(node *op, var *res) L.d /= R.d; break; case '&': -#if ENABLE_FEATURE_AWK_MATH +#if ENABLE_FEATURE_AWK_LIBM L.d = pow(L.d, R.d); #else syntax_error(EMSG_NO_MATH); @@ -2846,18 +2879,18 @@ int awk_main(int argc, char **argv) parse_program(s + 1); free(s); } while (list_f); + argc++; } else { // no -f: take program from 1st parameter if (!argc) bb_show_usage(); g_progname = "cmd. line"; parse_program(*argv++); - argc--; } if (opt & 0x8) // -W bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); /* fill in ARGV array */ - setvar_i(intvar[ARGC], argc + 1); + setvar_i(intvar[ARGC], argc); setari_u(intvar[ARGV], 0, "awk"); i = 0; while (*argv) diff --git a/release/src/router/busybox/editors/diff.c b/release/src/router/busybox/editors/diff.c index 64ad6511da..7fce70d083 100644 --- a/release/src/router/busybox/editors/diff.c +++ b/release/src/router/busybox/editors/diff.c @@ -858,7 +858,7 @@ static void print_header(const char *file1, const char *file2) * lines appended (beginning at b). If c is greater than d then there are * lines missing from the to file. */ -static void change(char *file1, FILE *f1, char *file2, FILE *f2, +static void change(const char *file1, FILE *f1, const char *file2, FILE *f2, int a, int b, int c, int d) { if ((a > b && c > d) || (option_mask32 & FLAG_q)) { @@ -902,7 +902,7 @@ static void change(char *file1, FILE *f1, char *file2, FILE *f2, } -static void output(char *file1, FILE *f1, char *file2, FILE *f2) +static void output(const char *file1, FILE *f1, const char *file2, FILE *f2) { /* Note that j0 and j1 can't be used as they are defined in math.h. * This also allows the rather amusing variable 'j00'... */ @@ -999,7 +999,7 @@ static void output(char *file1, FILE *f1, char *file2, FILE *f2) */ /* NB: files can be not REGular. The only sure thing that they * are not both DIRectories. */ -static unsigned diffreg(char *file1, char *file2, int flags) +static unsigned diffreg(const char *file1, const char *file2, int flags) { int *member; /* will be overlaid on nfile[1] */ int *class; /* will be overlaid on nfile[0] */ @@ -1022,13 +1022,11 @@ static unsigned diffreg(char *file1, char *file2, int flags) if (flags & D_EMPTY1) /* can't be stdin, but xfopen_stdin() is smaller code */ - f1 = xfopen_stdin(bb_dev_null); - else - f1 = xfopen_stdin(file1); + file1 = bb_dev_null; + f1 = xfopen_stdin(file1); if (flags & D_EMPTY2) - f2 = xfopen_stdin(bb_dev_null); - else - f2 = xfopen_stdin(file2); + file2 = bb_dev_null; + f2 = xfopen_stdin(file2); /* NB: if D_EMPTY1/2 is set, other file is always a regular file, * not pipe/fifo/chardev/etc - D_EMPTY is used by "diff -r" only, @@ -1189,7 +1187,7 @@ static char **get_recursive_dirlist(char *path) recursive_action(path, ACTION_RECURSE|ACTION_FOLLOWLINKS, add_to_dirlist, /* file_action */ NULL, /* dir_action */ - (void*)(strlen(path) + 1), + (void*)(ptrdiff_t)(strlen(path) + 1), 0); } else { DIR *dp; diff --git a/release/src/router/busybox/editors/vi.c b/release/src/router/busybox/editors/vi.c index 08599c92c6..4885ee5605 100644 --- a/release/src/router/busybox/editors/vi.c +++ b/release/src/router/busybox/editors/vi.c @@ -57,30 +57,6 @@ enum { MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, }; -// Misc. non-Ascii keys that report an escape sequence -#define VI_K_UP (char)128 // cursor key Up -#define VI_K_DOWN (char)129 // cursor key Down -#define VI_K_RIGHT (char)130 // Cursor Key Right -#define VI_K_LEFT (char)131 // cursor key Left -#define VI_K_HOME (char)132 // Cursor Key Home -#define VI_K_END (char)133 // Cursor Key End -#define VI_K_INSERT (char)134 // Cursor Key Insert -#define VI_K_DELETE (char)135 // Cursor Key Insert -#define VI_K_PAGEUP (char)136 // Cursor Key Page Up -#define VI_K_PAGEDOWN (char)137 // Cursor Key Page Down -#define VI_K_FUN1 (char)138 // Function Key F1 -#define VI_K_FUN2 (char)139 // Function Key F2 -#define VI_K_FUN3 (char)140 // Function Key F3 -#define VI_K_FUN4 (char)141 // Function Key F4 -#define VI_K_FUN5 (char)142 // Function Key F5 -#define VI_K_FUN6 (char)143 // Function Key F6 -#define VI_K_FUN7 (char)144 // Function Key F7 -#define VI_K_FUN8 (char)145 // Function Key F8 -#define VI_K_FUN9 (char)146 // Function Key F9 -#define VI_K_FUN10 (char)147 // Function Key F10 -#define VI_K_FUN11 (char)148 // Function Key F11 -#define VI_K_FUN12 (char)149 // Function Key F12 - /* vt102 typical ESC sequence */ /* terminal standout start/normal ESC sequence */ static const char SOs[] ALIGN1 = "\033[7m"; @@ -96,6 +72,12 @@ static const char CMrc[] ALIGN1 = "\033[%d;%dH"; static const char CMup[] ALIGN1 = "\033[A"; static const char CMdown[] ALIGN1 = "\n"; +#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK +// cmds modifying text[] +// vda: removed "aAiIs" as they switch us into insert mode +// and remembering input for replay after them makes no sense +static const char modifying_cmds[] = "cCdDJoOpPrRxX<>~"; +#endif enum { YANKONLY = FALSE, @@ -165,10 +147,11 @@ struct globals { char *screen; // pointer to the virtual screen buffer int screensize; // and its size int tabstop; + int last_forward_char; // last char searched for with 'f' (int because of Unicode) char erase_char; // the users erase character char last_input_char; // last char read from user - char last_forward_char; // last char searched for with 'f' + smalluint chars_to_parse; #if ENABLE_FEATURE_VI_DOT_CMD smallint adding2q; // are we currently adding user input to q int lmc_len; // length of last_modifying_cmd @@ -180,13 +163,10 @@ struct globals { #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME int my_pid; #endif -#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK - char *modifying_cmds; // cmds that modify text[] -#endif #if ENABLE_FEATURE_VI_SEARCH char *last_search_pattern; // last pattern from a '/' or '?' search #endif - int chars_to_parse; + /* former statics */ #if ENABLE_FEATURE_VI_YANKMARK char *edit_file__cur_line; @@ -209,11 +189,11 @@ struct globals { char *initial_cmds[3]; // currently 2 entries, NULL terminated #endif // Should be just enough to hold a key sequence, - // but CRASME mode uses it as generated command buffer too + // but CRASHME mode uses it as generated command buffer too #if ENABLE_FEATURE_VI_CRASHME char readbuffer[128]; #else - char readbuffer[32]; + char readbuffer[KEYCODE_BUFFER_SIZE]; #endif #define STATUS_BUFFER_LEN 200 char status_buffer[STATUS_BUFFER_LEN]; // messages to the user @@ -252,9 +232,10 @@ struct globals { #define screensize (G.screensize ) #define screenbegin (G.screenbegin ) #define tabstop (G.tabstop ) +#define last_forward_char (G.last_forward_char ) #define erase_char (G.erase_char ) #define last_input_char (G.last_input_char ) -#define last_forward_char (G.last_forward_char ) +#define chars_to_parse (G.chars_to_parse ) #if ENABLE_FEATURE_VI_READONLY #define readonly_mode (G.readonly_mode ) #else @@ -266,9 +247,7 @@ struct globals { #define ioq_start (G.ioq_start ) #define last_row (G.last_row ) #define my_pid (G.my_pid ) -#define modifying_cmds (G.modifying_cmds ) #define last_search_pattern (G.last_search_pattern) -#define chars_to_parse (G.chars_to_parse ) #define edit_file__cur_line (G.edit_file__cur_line) #define refresh__old_offset (G.refresh__old_offset) @@ -291,14 +270,14 @@ struct globals { #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ last_file_modified = -1; \ - /* "" but has space for 2 chars */ \ + /* "" but has space for 2 chars: */ \ USE_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ } while (0) static int init_text_buffer(char *); // init from file or create new static void edit_file(char *); // edit one file -static void do_cmd(char); // execute a command +static void do_cmd(int); // execute a command static int next_tabstop(int); static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot static char *begin_line(char *); // return pointer to cur line B-o-l @@ -321,27 +300,31 @@ static void dot_delete(void); // delete the char at 'dot' static char *bound_dot(char *); // make sure text[0] <= P < "end" static char *new_screen(int, int); // malloc virtual screen memory static char *char_insert(char *, char); // insert the char c at 'p' -static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' +// might reallocate text[]! use p += stupid_insert(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t stupid_insert(char *, char); // stupidly insert the char c at 'p' static int find_range(char **, char **, char); // return pointers for an object static int st_test(char *, int, int, char *); // helper for skip_thing() static char *skip_thing(char *, int, int, int); // skip some object static char *find_pair(char *, char); // find matching pair () [] {} static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole -static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole +// might reallocate text[]! use p += text_hole_make(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete static void show_help(void); // display some help info static void rawmode(void); // set "raw" mode on tty static void cookmode(void); // return to "cooked" mode on tty // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) static int mysleep(int); -static char readit(void); // read (maybe cursor) key from stdin -static char get_one_char(void); // read 1 char from stdin +static int readit(void); // read (maybe cursor) key from stdin +static int get_one_char(void); // read 1 char from stdin static int file_size(const char *); // what is the byte size of "fn" -#if ENABLE_FEATURE_VI_READONLY -static int file_insert(const char *, char *, int); -#else -static int file_insert(const char *, char *); +#if !ENABLE_FEATURE_VI_READONLY +#define file_insert(fn, p, update_ro_status) file_insert(fn, p) #endif +// file_insert might reallocate text[]! +static int file_insert(const char *, char *, int); static int file_write(char *, char *, char *); #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR #define place_cursor(a, b, optimize) place_cursor(a, b) @@ -350,6 +333,7 @@ static void place_cursor(int, int, int); static void screen_erase(void); static void clear_to_eol(void); static void clear_to_eos(void); +static void go_bottom_and_clear_to_eol(void); static void standout_start(void); // send "start reverse video" sequence static void standout_end(void); // send "end reverse video" sequence static void flash(int); // flash the terminal screen @@ -390,7 +374,9 @@ static void end_cmd_q(void); // stop saving input chars static void showmatching(char *); // show the matching pair () [] {} #endif #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME -static char *string_insert(char *, char *); // insert the string at 'p' +// might reallocate text[]! use p += string_insert(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t string_insert(char *, const char *); // insert the string at 'p' #endif #if ENABLE_FEATURE_VI_YANKMARK static char *text_yank(char *, char *, int); // save copy of "p" into a register @@ -430,10 +416,6 @@ int vi_main(int argc, char **argv) #endif vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; -#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK - modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] -#endif - // 1- process $HOME/.exrc file (not inplemented yet) // 2- process EXINIT variable from environment // 3- process command line args @@ -510,8 +492,7 @@ static int init_text_buffer(char *fn) char_insert(text, '\n'); rc = 0; } else { - rc = file_insert(fn, text - USE_FEATURE_VI_READONLY(, 1)); + rc = file_insert(fn, text, 1); } file_modified = 0; last_file_modified = -1; @@ -527,7 +508,7 @@ static void edit_file(char *fn) #if ENABLE_FEATURE_VI_YANKMARK #define cur_line edit_file__cur_line #endif - char c; + int c; int size; #if ENABLE_FEATURE_VI_USE_SIGNALS int sig; @@ -608,7 +589,8 @@ static void edit_file(char *fn) crash_dummy(); // generate a random command } else { crashme = 0; - dot = string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string + string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string + dot = text; refresh(FALSE); } } @@ -625,18 +607,21 @@ static void edit_file(char *fn) // These are commands that change text[]. // Remember the input for the "." command if (!adding2q && ioq_start == NULL - && c != '\0' && strchr(modifying_cmds, c) + && cmd_mode == 0 // command mode + && c > '\0' // exclude NUL and non-ASCII chars + && c < 0x7f // (Unicode and such) + && strchr(modifying_cmds, c) ) { start_new_cmd_q(c); } #endif do_cmd(c); // execute the user command - // + // poll to see if there is input already waiting. if we are // not able to display output fast enough to keep up, skip // the display update until we catch up with input. - if (mysleep(0) == 0) { - // no input pending- so update output + if (!chars_to_parse && mysleep(0) == 0) { + // no input pending - so update output refresh(FALSE); show_status_line(); } @@ -647,8 +632,7 @@ static void edit_file(char *fn) } //------------------------------------------------------------------- - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // erase to end of line + go_bottom_and_clear_to_eol(); cookmode(); #undef cur_line } @@ -678,7 +662,7 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present c = c - 'a'; q = mark[(unsigned char) c]; if (q != NULL) { // is mark valid - *addr = count_lines(text, q); // count lines + *addr = count_lines(text, q); } } } @@ -844,8 +828,7 @@ static void colon(char *buf) else if (strncmp(cmd, "!", 1) == 0) { // run a cmd int retcode; // :!ls run the - place_cursor(rows - 1, 0, FALSE); // go to Status line - clear_to_eol(); // clear the line + go_bottom_and_clear_to_eol(); cookmode(); retcode = system(orig_buf + 1); // run the cmd if (retcode) @@ -922,8 +905,7 @@ static void colon(char *buf) } } else if (strncasecmp(cmd, "features", i) == 0) { // what features are available // print out values of all features - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line + go_bottom_and_clear_to_eol(); cookmode(); show_help(); rawmode(); @@ -933,8 +915,7 @@ static void colon(char *buf) q = begin_line(dot); // assume .,. for the range r = end_line(dot); } - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line + go_bottom_and_clear_to_eol(); puts("\r"); for (; q <= r; q++) { int c_is_no_print; @@ -1001,7 +982,11 @@ static void colon(char *buf) // read after current line- unless user said ":0r foo" if (b != 0) q = next_line(q); - ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0)); + { // dance around potentially-reallocated text[] + uintptr_t ofs = q - text; + ch = file_insert(fn, q, 0); + q = text + ofs; + } if (ch < 0) goto vc1; // nothing was inserted // how many lines in text[]? @@ -1015,7 +1000,7 @@ static void colon(char *buf) // if the insert is before "dot" then we need to update if (q <= dot) dot += ch; - file_modified++; + /*file_modified++; - done by file_insert */ } } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args if (file_modified && !useforce) { @@ -1034,8 +1019,7 @@ static void colon(char *buf) // only blank is regarded as args delmiter. What about tab '\t' ? if (!args[0] || strcasecmp(args, "all") == 0) { // print out values of all options - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line + go_bottom_and_clear_to_eol(); printf("----------------------------------------\r\n"); #if ENABLE_FEATURE_VI_SETOPTS if (!autoindent) @@ -1089,10 +1073,12 @@ static void colon(char *buf) 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; + if (!R) + goto colon_s_fail; *R++ = '\0'; // terminate "find" buf1 = strchr(R, c); - if (!buf1) goto colon_s_fail; + if (!buf1) + goto colon_s_fail; *buf1++ = '\0'; // terminate "replace" if (*buf1 == 'g') { // :s/foo/bar/g buf1++; @@ -1110,10 +1096,14 @@ static void colon(char *buf) vc4: buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" if (buf1) { + uintptr_t bias; // we found the "find" pattern - delete it text_hole_delete(buf1, buf1 + strlen(F) - 1); // inset the "replace" patern - string_insert(buf1, R); // insert the string + bias = string_insert(buf1, R); // insert the string + buf1 += bias; + ls += bias; + /*q += bias; - recalculated anyway */ // check for "global" :s/foo/bar/g if (gflag == 1) { if ((buf1 + strlen(R)) < end_line(ls)) { @@ -1205,7 +1195,7 @@ static void colon(char *buf) static void Hit_Return(void) { - char c; + int c; standout_start(); write1("[Hit return to continue]"); @@ -1649,8 +1639,7 @@ static char *char_search(char *p, const char *pat, int dir, int range) static char *char_insert(char *p, char c) // insert the char c at 'p' { if (c == 22) { // Is this an ctrl-V? - p = stupid_insert(p, '^'); // use ^ to indicate literal next - p--; // backup onto ^ + p += stupid_insert(p, '^'); // use ^ to indicate literal next refresh(FALSE); // show the ^ c = get_one_char(); *p = c; @@ -1677,17 +1666,23 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' if (c == 13) c = '\n'; // translate \r to \n sp = p; // remember addr of insert - p = stupid_insert(p, c); // insert the char + p += 1 + stupid_insert(p, c); // insert the char #if ENABLE_FEATURE_VI_SETOPTS if (showmatch && strchr(")]}", *sp) != NULL) { showmatching(sp); } if (autoindent && c == '\n') { // auto indent the new line char *q; - - q = prev_line(p); // use prev line as templet - for (; isblank(*q); q++) { - p = stupid_insert(p, *q); // insert the char + size_t len; + q = prev_line(p); // use prev line as template + len = strspn(q, " \t"); // space or tab + if (len) { + uintptr_t bias; + bias = text_hole_make(p, len); + p += bias; + q += bias; + memcpy(p, q, len); + p += len; } } #endif @@ -1695,12 +1690,16 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' return p; } -static char *stupid_insert(char *p, char c) // stupidly insert the char c at 'p' +// might reallocate text[]! use p += stupid_insert(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at 'p' { - p = text_hole_make(p, 1); + uintptr_t bias; + bias = text_hole_make(p, 1); + p += bias; *p = c; //file_modified++; - done by text_hole_make() - return p + 1; + return bias; } static int find_range(char **start, char **stop, char c) @@ -1880,26 +1879,31 @@ static void showmatching(char *p) } #endif /* FEATURE_VI_SETOPTS */ -// open a hole in text[] -static char *text_hole_make(char *p, int size) // at "p", make a 'size' byte hole +// open a hole in text[] +// might reallocate text[]! use p += text_hole_make(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte hole { + uintptr_t bias = 0; + if (size <= 0) - return p; + return bias; end += size; // adjust the new END if (end >= (text + text_size)) { char *new_text; text_size += end - (text + text_size) + 10240; new_text = xrealloc(text, text_size); - screenbegin = new_text + (screenbegin - text); - dot = new_text + (dot - text); - end = new_text + (end - text); - p = new_text + (p - text); + bias = (new_text - text); + screenbegin += bias; + dot += bias; + end += bias; + p += bias; text = new_text; } memmove(p + size, p, end - size - p); memset(p, ' ', size); // clear new hole file_modified++; - return p; + return bias; } // close a hole in text[] @@ -2032,42 +2036,41 @@ static void end_cmd_q(void) #if ENABLE_FEATURE_VI_YANKMARK \ || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \ || ENABLE_FEATURE_VI_CRASHME -static char *string_insert(char *p, char *s) // insert the string at 'p' +// might reallocate text[]! use p += string_insert(p, ...), +// and be careful to not use pointers into potentially freed text[]! +static uintptr_t string_insert(char *p, const char *s) // insert the string at 'p' { - int cnt, i; + uintptr_t bias; + int i; i = strlen(s); - text_hole_make(p, i); - strncpy(p, s, i); - for (cnt = 0; *s != '\0'; s++) { - if (*s == '\n') - cnt++; - } + bias = text_hole_make(p, i); + p += bias; + memcpy(p, s, i); #if ENABLE_FEATURE_VI_YANKMARK - status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); + { + int cnt; + for (cnt = 0; *s != '\0'; s++) { + if (*s == '\n') + cnt++; + } + status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); + } #endif - return p; + return bias; } #endif #if ENABLE_FEATURE_VI_YANKMARK static char *text_yank(char *p, char *q, int dest) // copy text into a register { - char *t; - int cnt; - - if (q < p) { // they are backwards- reverse them - t = q; - q = p; - p = t; + int cnt = q - p; + if (cnt < 0) { // they are backwards- reverse them + p = q; + cnt = -cnt; } - cnt = q - p + 1; - t = reg[dest]; - free(t); // if already a yank register, free it - t = xmalloc(cnt + 1); // get a new register - memset(t, '\0', cnt + 1); // clear new text[] - strncpy(t, p, cnt); // copy text[] into bufer - reg[dest] = t; + free(reg[dest]); // if already a yank register, free it + reg[dest] = xstrndup(p, cnt + 1); return p; } @@ -2132,13 +2135,13 @@ static void rawmode(void) term_vi.c_cc[VMIN] = 1; term_vi.c_cc[VTIME] = 0; erase_char = term_vi.c_cc[VERASE]; - tcsetattr(0, TCSANOW, &term_vi); + tcsetattr_stdin_TCSANOW(&term_vi); } static void cookmode(void) { fflush(stdout); - tcsetattr(0, TCSANOW, &term_orig); + tcsetattr_stdin_TCSANOW(&term_orig); } //----- Come here when we get a window resize signal --------- @@ -2171,8 +2174,7 @@ static void cont_sig(int sig UNUSED_PARAM) //----- Come here when we get a Suspend signal ------------------- static void suspend_sig(int sig UNUSED_PARAM) { - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // erase to end of line + go_bottom_and_clear_to_eol(); cookmode(); // terminal to "cooked" signal(SIGCONT, cont_sig); @@ -2199,120 +2201,24 @@ static int mysleep(int hund) // sleep for 'h' 1/100 seconds } //----- IO Routines -------------------------------------------- -static char readit(void) // read (maybe cursor) key from stdin +static int readit(void) // read (maybe cursor) key from stdin { - char c; - int n; - struct esc_cmds { - const char seq[4]; - char val; - }; - - static const struct esc_cmds esccmds[] = { - {"OA" , VI_K_UP }, // cursor key Up - {"OB" , VI_K_DOWN }, // cursor key Down - {"OC" , VI_K_RIGHT }, // Cursor Key Right - {"OD" , VI_K_LEFT }, // cursor key Left - {"OH" , VI_K_HOME }, // Cursor Key Home - {"OF" , VI_K_END }, // Cursor Key End - {"[A" , VI_K_UP }, // cursor key Up - {"[B" , VI_K_DOWN }, // cursor key Down - {"[C" , VI_K_RIGHT }, // Cursor Key Right - {"[D" , VI_K_LEFT }, // cursor key Left - {"[H" , VI_K_HOME }, // Cursor Key Home - {"[F" , VI_K_END }, // Cursor Key End - {"[1~" , VI_K_HOME }, // Cursor Key Home - {"[2~" , VI_K_INSERT }, // Cursor Key Insert - {"[3~" , VI_K_DELETE }, // Cursor Key Delete - {"[4~" , VI_K_END }, // Cursor Key End - {"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up - {"[6~" , VI_K_PAGEDOWN}, // Cursor Key Page Down - {"OP" , VI_K_FUN1 }, // Function Key F1 - {"OQ" , VI_K_FUN2 }, // Function Key F2 - {"OR" , VI_K_FUN3 }, // Function Key F3 - {"OS" , VI_K_FUN4 }, // Function Key F4 - // careful: these have no terminating NUL! - {"[11~", VI_K_FUN1 }, // Function Key F1 - {"[12~", VI_K_FUN2 }, // Function Key F2 - {"[13~", VI_K_FUN3 }, // Function Key F3 - {"[14~", VI_K_FUN4 }, // Function Key F4 - {"[15~", VI_K_FUN5 }, // Function Key F5 - {"[17~", VI_K_FUN6 }, // Function Key F6 - {"[18~", VI_K_FUN7 }, // Function Key F7 - {"[19~", VI_K_FUN8 }, // Function Key F8 - {"[20~", VI_K_FUN9 }, // Function Key F9 - {"[21~", VI_K_FUN10 }, // Function Key F10 - {"[23~", VI_K_FUN11 }, // Function Key F11 - {"[24~", VI_K_FUN12 }, // Function Key F12 - }; - enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) }; + int c; fflush(stdout); - n = chars_to_parse; - // get input from User - are there already input chars in Q? - if (n <= 0) { - // the Q is empty, wait for a typed char - again: - n = safe_read(STDIN_FILENO, readbuffer, sizeof(readbuffer)); - if (n <= 0) { - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // erase to end of line - cookmode(); // terminal to "cooked" - bb_error_msg_and_die("can't read user input"); - } - /* elsewhere we can get very confused by NULs */ - if (readbuffer[0] == '\0') - goto again; - if (readbuffer[0] == 27) { - // This is an ESC char. Is this Esc sequence? - // Could be bare Esc key. See if there are any - // more chars to read after the ESC. This would - // be a Function or Cursor Key sequence. - struct pollfd pfd[1]; - pfd[0].fd = 0; - pfd[0].events = POLLIN; - // keep reading while there are input chars, and room in buffer - // for a complete ESC sequence (assuming 8 chars is enough) - while ((safe_poll(pfd, 1, 0) > 0) - && ((size_t)n <= (sizeof(readbuffer) - 8)) - ) { - // read the rest of the ESC string - int r = safe_read(STDIN_FILENO, readbuffer + n, sizeof(readbuffer) - n); - if (r > 0) - n += r; - } - } - chars_to_parse = n; - } - c = readbuffer[0]; - if (c == 27 && n > 1) { - // Maybe cursor or function key? - const struct esc_cmds *eindex; - - for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) { - int cnt = strnlen(eindex->seq, 4); - if (n <= cnt) - continue; - if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0) - continue; - c = eindex->val; // magic char value - n = cnt + 1; // squeeze out the ESC sequence - goto found; - } - // defined ESC sequence not found - } - n = 1; - found: - // remove key sequence from Q - chars_to_parse -= n; - memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n); + c = read_key(STDIN_FILENO, &chars_to_parse, readbuffer); + if (c == -1) { // EOF/error + go_bottom_and_clear_to_eol(); + cookmode(); // terminal to "cooked" + bb_error_msg_and_die("can't read user input"); + } return c; } //----- IO Routines -------------------------------------------- -static char get_one_char(void) +static int get_one_char(void) { - char c; + int c; #if ENABLE_FEATURE_VI_DOT_CMD if (!adding2q) { @@ -2323,7 +2229,8 @@ static char get_one_char(void) c = readit(); // get the users input } else { // there is a queue to get chars from first - c = *ioq++; + // careful with correct sign expansion! + c = (unsigned char)*ioq++; if (c == '\0') { // the end of the q, read from STDIN free(ioq_start); @@ -2353,13 +2260,12 @@ static char *get_input_line(const char *prompt) // char [MAX_INPUT_LEN] #define buf get_input_line__buf - char c; + int c; int i; strcpy(buf, prompt); last_status_cksum = 0; // force status update - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line + go_bottom_and_clear_to_eol(); write1(prompt); // write out the :, /, or ? prompt i = strlen(buf); @@ -2373,7 +2279,8 @@ static char *get_input_line(const char *prompt) write1("\b \b"); // erase char on screen if (i <= 0) // user backs up before b-o-l, exit break; - } else { + } else if (c > 0 && c < 256) { // exclude Unicode + // (TODO: need to handle Unicode) buf[i] = c; buf[++i] = '\0'; bb_putchar(c); @@ -2395,8 +2302,8 @@ static int file_size(const char *fn) // what is the byte size of "fn" return cnt; } -static int file_insert(const char *fn, char *p - USE_FEATURE_VI_READONLY(, int update_ro_status)) +// might reallocate text[]! +static int file_insert(const char *fn, char *p, int update_ro_status) { int cnt = -1; int fd, size; @@ -2424,7 +2331,7 @@ static int file_insert(const char *fn, char *p goto fi0; } size = statbuf.st_size; - p = text_hole_make(p, size); + p += text_hole_make(p, size); cnt = safe_read(fd, p, size); if (cnt < 0) { status_line_bold("\"%s\" %s", fn, strerror(errno)); @@ -2465,13 +2372,13 @@ 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), 0666); +/* fd = open(fn, (O_WRONLY | O_CREAT), 0666); */ fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0666); if (fd < 0) return -1; cnt = last - first + 1; charcnt = full_write(fd, first, cnt); -// ftruncate(fd, charcnt); // buggy? - zzz +/* ftruncate(fd, charcnt); buggy for us - zzz */ if (charcnt == cnt) { // good write //file_modified = FALSE; @@ -2564,6 +2471,12 @@ static void clear_to_eol(void) write1(Ceol); // Erase from cursor to end of line } +static void go_bottom_and_clear_to_eol(void) +{ + place_cursor(rows - 1, 0, FALSE); // go to bottom of screen + clear_to_eol(); // erase to end of line +} + //----- Erase from cursor to end of screen ----------------------- static void clear_to_eos(void) { @@ -2635,9 +2548,8 @@ static void show_status_line(void) } if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) { last_status_cksum = cksum; // remember if we have seen this line - place_cursor(rows - 1, 0, FALSE); // put cursor on status line + go_bottom_and_clear_to_eol(); write1(status_buffer); - clear_to_eol(); if (have_status_msg) { if (((int)strlen(status_buffer) - (have_status_msg - 1)) > (columns - 1) ) { @@ -2972,13 +2884,14 @@ static void refresh(int full_screen) //--------------------------------------------------------------------- //----- Execute a Vi Command ----------------------------------- -static void do_cmd(char c) +static void do_cmd(int c) { const char *msg = msg; // for compiler - char c1, *p, *q, *save_dot; + char *p, *q, *save_dot; char buf[12]; int dir; int cnt, i, j; + int c1; // c1 = c; // quiet the compiler // cnt = yf = 0; // quiet the compiler @@ -2989,20 +2902,21 @@ static void do_cmd(char c) /* if this is a cursor key, skip these checks */ switch (c) { - case VI_K_UP: - case VI_K_DOWN: - case VI_K_LEFT: - case VI_K_RIGHT: - case VI_K_HOME: - case VI_K_END: - case VI_K_PAGEUP: - case VI_K_PAGEDOWN: + case KEYCODE_UP: + case KEYCODE_DOWN: + case KEYCODE_LEFT: + case KEYCODE_RIGHT: + case KEYCODE_HOME: + case KEYCODE_END: + case KEYCODE_PAGEUP: + case KEYCODE_PAGEDOWN: + case KEYCODE_DELETE: goto key_cmd_mode; } if (cmd_mode == 2) { // flip-flop Insert/Replace mode - if (c == VI_K_INSERT) + if (c == KEYCODE_INSERT) goto dc_i; // we are 'R'eplacing the current *dot with new char if (*dot == '\n') { @@ -3019,7 +2933,7 @@ static void do_cmd(char c) } if (cmd_mode == 1) { // hitting "Insert" twice means "R" replace mode - if (c == VI_K_INSERT) goto dc5; + if (c == KEYCODE_INSERT) goto dc5; // insert the char c at "dot" if (1 <= c || Isprint(c)) { dot = char_insert(dot, c); @@ -3083,7 +2997,7 @@ static void do_cmd(char c) case 0x00: // nul- ignore break; case 2: // ctrl-B scroll up full screen - case VI_K_PAGEUP: // Cursor Key Page Up + case KEYCODE_PAGEUP: // Cursor Key Page Up dot_scroll(rows - 2, -1); break; case 4: // ctrl-D scroll down half screen @@ -3093,14 +3007,14 @@ static void do_cmd(char c) dot_scroll(1, 1); break; case 6: // ctrl-F scroll down full screen - case VI_K_PAGEDOWN: // Cursor Key Page Down + case KEYCODE_PAGEDOWN: // Cursor Key Page Down dot_scroll(rows - 2, 1); break; case 7: // ctrl-G show current status last_status_cksum = 0; // force status update break; case 'h': // h- move left - case VI_K_LEFT: // cursor key Left + case 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-- > 1) { @@ -3110,7 +3024,7 @@ static void do_cmd(char c) break; case 10: // Newline ^J case 'j': // j- goto next line, same col - case VI_K_DOWN: // cursor key Down + case KEYCODE_DOWN: // cursor key Down if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt @@ -3149,7 +3063,7 @@ static void do_cmd(char c) break; case ' ': // move right case 'l': // move right - case VI_K_RIGHT: // Cursor Key Right + case KEYCODE_RIGHT: // Cursor Key Right if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt @@ -3157,21 +3071,18 @@ static void do_cmd(char c) break; #if ENABLE_FEATURE_VI_YANKMARK case '"': // "- name a register to use for Delete/Yank - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - YDreg = c1 - 'a'; + c1 = (get_one_char() | 0x20) - 'a'; // | 0x20 is tolower() + if ((unsigned)c1 <= 25) { // a-z? + YDreg = c1; } else { indicate_error(c); } break; case '\'': // '- goto a specific mark - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; + c1 = (get_one_char() | 0x20) - 'a'; + if ((unsigned)c1 <= 25) { // a-z? // get the b-o-l - q = mark[(unsigned char) c1]; + q = mark[c1]; if (text <= q && q < end) { dot = q; dot_begin(); // go to B-o-l @@ -3190,12 +3101,10 @@ static void do_cmd(char c) // between text[0] and dot then this mark will not point to the // correct location! It could be off by many lines! // Well..., at least its quick and dirty. - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; + c1 = (get_one_char() | 0x20) - 'a'; + if ((unsigned)c1 <= 25) { // a-z? // remember the line - mark[(int) c1] = dot; + mark[c1] = dot; } else { indicate_error(c); } @@ -3203,7 +3112,7 @@ static void do_cmd(char c) case 'P': // P- Put register before case 'p': // p- put register after p = reg[YDreg]; - if (p == 0) { + if (p == NULL) { status_line_bold("Nothing in register %c", what_reg()); break; } @@ -3224,7 +3133,7 @@ static void do_cmd(char c) if (c == 'p') dot_right(); // move to right, can move to NL } - dot = string_insert(dot, p); // insert the string + string_insert(dot, p); // insert the string end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version @@ -3232,14 +3141,14 @@ static void do_cmd(char c) p = begin_line(dot); q = end_line(dot); p = text_hole_delete(p, q); // delete cur line - p = string_insert(p, reg[Ureg]); // insert orig line + p += string_insert(p, reg[Ureg]); // insert orig line dot = p; dot_skip_over_ws(); } break; #endif /* FEATURE_VI_YANKMARK */ case '$': // $- goto end of line - case VI_K_END: // Cursor Key End + case KEYCODE_END: // Cursor Key End if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt @@ -3524,12 +3433,11 @@ static void do_cmd(char c) end_cmd_q(); // stop adding to q #endif break; - case 'g': // 'gg' goto a line number (from vim) - // (default to first line in file) + case 'g': // 'gg' goto a line number (vim) (default: very first line) c1 = get_one_char(); if (c1 != 'g') { buf[0] = 'g'; - buf[1] = c1; + buf[1] = c1; // TODO: if Unicode? buf[2] = '\0'; not_implemented(buf); break; @@ -3559,7 +3467,7 @@ static void do_cmd(char c) dot_skip_over_ws(); //**** fall through to ... 'i' case 'i': // i- insert before current char - case VI_K_INSERT: // Cursor Key Insert + case KEYCODE_INSERT: // Cursor Key Insert dc_i: cmd_mode = 1; // start insrting break; @@ -3612,7 +3520,7 @@ static void do_cmd(char c) dc5: cmd_mode = 2; break; - case VI_K_DELETE: + case KEYCODE_DELETE: c = 'x'; // fall through case 'X': // X- delete char before dot @@ -3686,7 +3594,7 @@ static void do_cmd(char c) case 'y': // y- yank something case 'Y': // Y- Yank a line #endif - { + { int yf, ml, whole = 0; yf = YANKDEL; // assume either "c" or "d" #if ENABLE_FEATURE_VI_YANKMARK @@ -3759,10 +3667,10 @@ static void do_cmd(char c) #endif end_cmd_q(); // stop adding to q } - } break; + } case 'k': // k- goto prev line, same col - case VI_K_UP: // cursor key Up + case KEYCODE_UP: // cursor key Up if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt @@ -3782,7 +3690,7 @@ static void do_cmd(char c) do_cmd(';'); if (*dot == last_forward_char) dot_left(); - last_forward_char= 0; + last_forward_char = 0; break; case 'w': // w- forward a word if (cmdcnt-- > 1) { @@ -3827,23 +3735,25 @@ static void do_cmd(char c) end_cmd_q(); // stop adding to q break; //----- The Cursor and Function Keys ----------------------------- - case VI_K_HOME: // Cursor Key Home + case KEYCODE_HOME: // Cursor Key Home dot_begin(); break; // The Fn keys could point to do_macro which could translate them - case VI_K_FUN1: // Function Key F1 - case VI_K_FUN2: // Function Key F2 - case VI_K_FUN3: // Function Key F3 - case VI_K_FUN4: // Function Key F4 - case VI_K_FUN5: // Function Key F5 - case VI_K_FUN6: // Function Key F6 - case VI_K_FUN7: // Function Key F7 - case VI_K_FUN8: // Function Key F8 - case VI_K_FUN9: // Function Key F9 - case VI_K_FUN10: // Function Key F10 - case VI_K_FUN11: // Function Key F11 - case VI_K_FUN12: // Function Key F12 +#if 0 + case KEYCODE_FUN1: // Function Key F1 + case KEYCODE_FUN2: // Function Key F2 + case KEYCODE_FUN3: // Function Key F3 + case KEYCODE_FUN4: // Function Key F4 + case KEYCODE_FUN5: // Function Key F5 + case KEYCODE_FUN6: // Function Key F6 + case KEYCODE_FUN7: // Function Key F7 + case KEYCODE_FUN8: // Function Key F8 + case KEYCODE_FUN9: // Function Key F9 + case KEYCODE_FUN10: // Function Key F10 + case KEYCODE_FUN11: // Function Key F11 + case KEYCODE_FUN12: // Function Key F12 break; +#endif } dc1: diff --git a/release/src/router/busybox/examples/depmod-t.pl b/release/src/router/busybox/examples/depmod-t.pl new file mode 100644 index 0000000000..fa5ca977ba --- /dev/null +++ b/release/src/router/busybox/examples/depmod-t.pl @@ -0,0 +1,293 @@ +#!/usr/bin/perl -w +# vi: set sw=4 ts=4: +# Copyright (c) 2001 David Schleef +# Copyright (c) 2001 Erik Andersen +# Copyright (c) 2001 Stuart Hughes +# Copyright (c) 2002 Steven J. Hill +# Copyright (c) 2006 Freescale Semiconductor, Inc +# +# History: +# March 2006: Stuart Hughes . +# Significant updates, including implementing the '-F' option +# and adding support for 2.6 kernels. + +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +use Getopt::Long; +use File::Find; +use strict; + +# Set up some default values +my $kdir=""; +my $basedir=""; +my $kernel=""; +my $kernelsyms=""; +my $symprefix=""; +my $stdout=0; +my $verbose=0; +my $help=0; +my $nm = $ENV{'NM'} || "nm"; + +# more globals +my (@liblist) = (); +my $exp = {}; +my $dep = {}; +my $mod = {}; + +my $usage = < | -F } [options]... + Where: + -h --help : Show this help screen + -b --basedir : Modules base directory (e.g /lib/modules/<2.x.y>) + -k --kernel : Kernel binary for the target (e.g. vmlinux) + -F --kernelsyms : Kernel symbol file (e.g. System.map) + -n --stdout : Write to stdout instead of /modules.dep + -v --verbose : Print out lots of debugging stuff + -P --symbol-prefix : Symbol prefix +TXT + +# get command-line options +GetOptions( + "help|h" => \$help, + "basedir|b=s" => \$basedir, + "kernel|k=s" => \$kernel, + "kernelsyms|F=s" => \$kernelsyms, + "stdout|n" => \$stdout, + "verbose|v" => \$verbose, + "symbol-prefix|P=s" => \$symprefix, +); + +die $usage if $help; +die $usage unless $basedir && ( $kernel || $kernelsyms ); +die "can't use both -k and -F\n\n$usage" if $kernel && $kernelsyms; + +# Strip any trailing or multiple slashes from basedir +$basedir =~ s-(/)\1+-/-g; + +# The base directory should contain /lib/modules somewhere +if($basedir !~ m-/lib/modules-) { + warn "WARNING: base directory does not match ..../lib/modules\n"; +} + +# if no kernel version is contained in the basedir, try to find one +if($basedir !~ m-/lib/modules/\d\.\d-) { + opendir(BD, $basedir) or die "can't open basedir $basedir : $!\n"; + foreach ( readdir(BD) ) { + next if /^\.\.?$/; + next unless -d "$basedir/$_"; + warn "dir = $_\n" if $verbose; + if( /^\d\.\d/ ) { + $kdir = $_; + warn("Guessed module directory as $basedir/$kdir\n"); + last; + } + } + closedir(BD); + die "Cannot find a kernel version under $basedir\n" unless $kdir; + $basedir = "$basedir/$kdir"; +} + +# Find the list of .o or .ko files living under $basedir +warn "**** Locating all modules\n" if $verbose; +find sub { + my $file; + if ( -f $_ && ! -d $_ ) { + $file = $File::Find::name; + if ( $file =~ /\.k?o$/ ) { + push(@liblist, $file); + warn "$file\n" if $verbose; + } + } +}, $basedir; +warn "**** Finished locating modules\n" if $verbose; + +foreach my $obj ( @liblist ){ + # turn the input file name into a target tag name + my ($tgtname) = $obj =~ m-(/lib/modules/.*)$-; + + warn "\nMODULE = $tgtname\n" if $verbose; + + # get a list of symbols + my @output=`$nm $obj`; + + build_ref_tables($tgtname, \@output, $exp, $dep); +} + + +# vmlinux is a special name that is only used to resolve symbols +my $tgtname = 'vmlinux'; +my @output = $kernelsyms ? `cat $kernelsyms` : `$nm $kernel`; +warn "\nMODULE = $tgtname\n" if $verbose; +build_ref_tables($tgtname, \@output, $exp, $dep); + +# resolve the dependencies for each module +# reduce dependencies: remove unresolvable and resolved from vmlinux/System.map +# remove duplicates +foreach my $module (keys %$dep) { + warn "reducing module: $module\n" if $verbose; + $mod->{$module} = {}; + foreach (@{$dep->{$module}}) { + if( $exp->{$_} ) { + warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose; + next if $exp->{$_} =~ /vmlinux/; + $mod->{$module}{$exp->{$_}} = 1; + } else { + warn "unresolved symbol $_ in file $module\n"; + } + } +} + +# figure out where the output should go +if ($stdout == 0) { + open(STDOUT, ">$basedir/modules.dep") + or die "cannot open $basedir/modules.dep: $!"; +} +my $kseries = $basedir =~ m,/2\.6\.[^/]*, ? '2.6' : '2.4'; + +foreach my $module ( keys %$mod ) { +# \t breaks modprobe 1.13.2? -- zzz +# if($kseries eq '2.4') { +# print "$module:\t"; +# my @sorted = sort bydep keys %{$mod->{$module}}; +# print join(" \\\n\t",@sorted); +# print "\n\n"; +# } else { + print "$module: "; + my @sorted = sort bydep keys %{$mod->{$module}}; + print join(" ",@sorted); + print "\n"; +# } +} + + +sub build_ref_tables +{ + my ($name, $sym_ar, $exp, $dep) = @_; + + my $ksymtab = grep m/ __ksymtab/, @$sym_ar; + + # gather the exported symbols + if($ksymtab){ + # explicitly exported + foreach ( @$sym_ar ) { + / __ksymtab_(.*)$/ and do { + warn "sym = $1\n" if $verbose; + $exp->{$1} = $name; + }; + } + } else { + # exporting all symbols + foreach ( @$sym_ar ) { + / [ABCDGRSTW] (.*)$/ and do { + warn "syma = $1\n" if $verbose; + $exp->{$1} = $name; + }; + } + } + + # this takes makes sure modules with no dependencies get listed + push @{$dep->{$name}}, $symprefix . 'printk' unless $name eq 'vmlinux'; + + # gather the unresolved symbols + foreach ( @$sym_ar ) { + !/ __this_module/ && / U (.*)$/ and do { + warn "und = $1\n" if $verbose; + push @{$dep->{$name}}, $1; + }; + } +} + +sub bydep +{ + foreach my $f ( keys %{$mod->{$b}} ) { + if($f eq $a) { + return 1; + } + } + return -1; +} + + + +__END__ + +=head1 NAME + +depmod.pl - a cross platform script to generate kernel module +dependency lists (modules.conf) which can then be used by modprobe +on the target platform. + +It supports Linux 2.4 and 2.6 styles of modules.conf (auto-detected) + +=head1 SYNOPSIS + +depmod.pl [OPTION]... [basedir]... + +Example: + + depmod.pl -F linux/System.map -b target/lib/modules/2.6.11 + +=head1 DESCRIPTION + +The purpose of this script is to automagically generate a list of of kernel +module dependencies. This script produces dependency lists that should be +identical to the depmod program from the modutils package. Unlike the depmod +binary, however, depmod.pl is designed to be run on your host system, not +on your target system. + +This script was written by David Schleef to be used in +conjunction with the BusyBox modprobe applet. + +=head1 OPTIONS + +=over 4 + +=item B<-h --help> + +This displays the help message. + +=item B<-b --basedir> + +The base directory uner which the target's modules will be found. This +defaults to the /lib/modules directory. + +If you don't specify the kernel version, this script will search for +one under the specified based directory and use the first thing that +looks like a kernel version. + +=item B<-k --kernel> + +Kernel binary for the target (vmlinux). You must either supply a kernel binary +or a kernel symbol file (using the -F option). + +=item B<-F --kernelsyms> + +Kernel symbol file for the target (System.map). + +=item B<-n --stdout> + +Write to stdout instead of modules.dep +kernel binary for the target (using the -k option). + +=item B<--verbose> + +Verbose (debug) output + +=back + +=head1 COPYRIGHT AND LICENSE + + Copyright (c) 2001 David Schleef + Copyright (c) 2001 Erik Andersen + Copyright (c) 2001 Stuart Hughes + Copyright (c) 2002 Steven J. Hill + Copyright (c) 2006 Freescale Semiconductor, Inc + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 AUTHOR + +David Schleef + +=cut diff --git a/release/src/router/busybox/findutils/Config.in b/release/src/router/busybox/findutils/Config.in index 9bb73d3f39..d69a2385b4 100644 --- a/release/src/router/busybox/findutils/Config.in +++ b/release/src/router/busybox/findutils/Config.in @@ -146,7 +146,7 @@ config FEATURE_FIND_DELETE default n depends on FIND && FEATURE_FIND_DEPTH help - Support the 'find -delete' option for deleting files and direcotries. + Support the 'find -delete' option for deleting files and directories. WARNING: This option can do much harm if used wrong. Busybox will not try to protect the user from doing stupid things. Use with care. diff --git a/release/src/router/busybox/findutils/find.c b/release/src/router/busybox/findutils/find.c index f2b89746f5..df632f2198 100644 --- a/release/src/router/busybox/findutils/find.c +++ b/release/src/router/busybox/findutils/find.c @@ -381,9 +381,11 @@ static int FAST_FUNC fileAction(const char *fileName, { int i; #if ENABLE_FEATURE_FIND_MAXDEPTH - int maxdepth = (int)(ptrdiff_t)userData; +#define minmaxdepth ((int*)userData) - if (depth > maxdepth) return SKIP; + if (depth < minmaxdepth[0]) return TRUE; + if (depth > minmaxdepth[1]) return SKIP; +#undef minmaxdepth #endif #if ENABLE_FEATURE_FIND_XDEV @@ -812,19 +814,21 @@ int find_main(int argc, char **argv) static const char options[] ALIGN1 = "-follow\0" USE_FEATURE_FIND_XDEV( "-xdev\0" ) -USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0") +USE_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") ; enum { OPT_FOLLOW, USE_FEATURE_FIND_XDEV( OPT_XDEV ,) -USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,) +USE_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) }; char *arg; char **argp; int i, firstopt, status = EXIT_SUCCESS; #if ENABLE_FEATURE_FIND_MAXDEPTH - int maxdepth = INT_MAX; + int minmaxdepth[2] = { 0, INT_MAX }; +#else +#define minmaxdepth NULL #endif for (firstopt = 1; firstopt < argc; firstopt++) { @@ -875,10 +879,10 @@ USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,) } #endif #if ENABLE_FEATURE_FIND_MAXDEPTH - if (opt == OPT_MAXDEPTH) { + if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) { if (!argp[1]) bb_show_usage(); - maxdepth = xatoi_u(argp[1]); + minmaxdepth[opt - OPT_MINDEPTH] = xatoi_u(argp[1]); argp[0] = (char*)"-a"; argp[1] = (char*)"-a"; argp++; @@ -895,9 +899,7 @@ USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,) fileAction, /* file action */ fileAction, /* dir action */ #if ENABLE_FEATURE_FIND_MAXDEPTH - /* double cast suppresses - * "cast to ptr from int of different size" */ - (void*)(ptrdiff_t)maxdepth,/* user data */ + minmaxdepth, /* user data */ #else NULL, /* user data */ #endif diff --git a/release/src/router/busybox/findutils/grep.c b/release/src/router/busybox/findutils/grep.c index 73e74f4b38..e23f9bcf3a 100644 --- a/release/src/router/busybox/findutils/grep.c +++ b/release/src/router/busybox/findutils/grep.c @@ -28,7 +28,9 @@ USE_FEATURE_GREP_CONTEXT("A:B:C:") \ USE_FEATURE_GREP_EGREP_ALIAS("E") \ USE_DESKTOP("w") \ + USE_EXTRA_COMPAT("z") \ "aI" + /* ignored: -a "assume all files to be text" */ /* ignored: -I "assume binary files have no matches" */ @@ -54,6 +56,7 @@ enum { USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ USE_DESKTOP( OPTBIT_w ,) /* whole word match */ + USE_EXTRA_COMPAT( OPTBIT_z ,) /* input is NUL terminated */ OPT_l = 1 << OPTBIT_l, OPT_n = 1 << OPTBIT_n, OPT_q = 1 << OPTBIT_q, @@ -75,6 +78,7 @@ enum { OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, OPT_w = USE_DESKTOP( (1 << OPTBIT_w)) + 0, + OPT_z = USE_EXTRA_COMPAT( (1 << OPTBIT_z)) + 0, }; #define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l) @@ -84,6 +88,7 @@ enum { #define PRINT_MATCH_COUNTS (option_mask32 & OPT_c) #define FGREP_FLAG (option_mask32 & OPT_F) #define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) +#define NUL_DELIMITED (option_mask32 & OPT_z) struct globals { int max_matches; @@ -186,7 +191,7 @@ static void print_line(const char *line, size_t line_len, int linenum, char deco puts(line); #else fwrite(line, 1, line_len, stdout); - putchar('\n'); + putchar(NUL_DELIMITED ? '\0' : '\n'); #endif } } @@ -197,12 +202,13 @@ static ssize_t FAST_FUNC bb_getline(char **line_ptr, size_t *line_alloc_len, FIL { ssize_t res_sz; char *line; + int delim = (NUL_DELIMITED ? '\0' : '\n'); - res_sz = getline(line_ptr, line_alloc_len, file); + res_sz = getdelim(line_ptr, line_alloc_len, delim, file); line = *line_ptr; if (res_sz > 0) { - if (line[res_sz - 1] == '\n') + if (line[res_sz - 1] == delim) line[--res_sz] = '\0'; } else { free(line); /* uclibc allocates a buffer even on EOF. WTF? */ @@ -374,11 +380,11 @@ static int grep_file(FILE *file) break; #else if (re_search(&gl->compiled_regex, line, line_len, - gl->matched_range.rm_eo, line_len - gl->matched_range.rm_eo, + gl->matched_range.rm_eo, line_len - gl->matched_range.rm_eo, &gl->matched_range) < 0) break; #endif - } + } } else { print_line(line, line_len, linenum, ':'); } @@ -407,8 +413,11 @@ static int grep_file(FILE *file) #endif /* Did we print all context after last requested match? */ if ((option_mask32 & OPT_m) - && !print_n_lines_after && nmatches == max_matches) + && !print_n_lines_after + && nmatches == max_matches + ) { break; + } } /* while (read line) */ /* special-case file post-processing for options where we don't print line diff --git a/release/src/router/busybox/include/applets.h b/release/src/router/busybox/include/applets.h index 0c9930d459..1d932589bf 100644 --- a/release/src/router/busybox/include/applets.h +++ b/release/src/router/busybox/include/applets.h @@ -69,6 +69,7 @@ s - suid type: USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) +USE_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER)) @@ -80,6 +81,7 @@ USE_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER, awk)) USE_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_NEVER, basename)) USE_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_NEVER)) //USE_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_NEVER)) +USE_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER, bzcat)) @@ -118,6 +120,7 @@ USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER)) +USE_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -149,10 +152,11 @@ USE_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush)) USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER)) -USE_FETCHMAIL(APPLET_ODDNAME(fetchmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, fetchmail)) USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep)) USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find)) USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) +//USE_FLASH_ERASEALL(APPLET_ODDNAME(flash_eraseall, flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER, flash_eraseall)) +USE_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_NEVER)) @@ -160,6 +164,7 @@ USE_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_NEVER)) //USE_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext2)) //USE_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext3)) USE_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix)) +USE_FTPD(APPLET(ftpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpget)) USE_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpput)) USE_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -191,6 +196,7 @@ USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_NEVER)) #if ENABLE_FEATURE_IP_ADDRESS \ || ENABLE_FEATURE_IP_ROUTE \ || ENABLE_FEATURE_IP_LINK \ @@ -236,6 +242,7 @@ USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) +USE_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum)) @@ -243,12 +250,15 @@ USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_NEVER, mkdir)) +USE_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat)) //USE_MKE2FS(APPLET(mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) //USE_MKE2FS(APPLET_ODDNAME(mkfs.ext2, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext2)) //USE_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext3)) USE_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_minix)) +USE_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat)) USE_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_NEVER)) +USE_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER, mkpasswd)) USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER)) @@ -268,7 +278,7 @@ USE_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) -USE_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +//USE_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS)) USE_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -278,6 +288,7 @@ USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill)) +USE_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff)) USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf)) @@ -292,6 +303,7 @@ USE_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot)) +USE_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -313,7 +325,7 @@ USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) -USE_SENDMAIL(APPLET_ODDNAME(sendmail, sendgetmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER, sendmail)) +USE_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq)) USE_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER)) @@ -330,6 +342,8 @@ USE_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_NEVER, sh)) USE_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_NEVER, sh)) USE_FEATURE_SH_IS_MSH(APPLET_ODDNAME(sh, msh, _BB_DIR_BIN, _BB_SUID_NEVER, sh)) USE_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha1sum)) +USE_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha256sum)) +USE_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha512sum)) USE_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_NEVER, sleep)) @@ -355,6 +369,7 @@ USE_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tac)) USE_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +/* USE_TC(APPLET(tc, _BB_DIR_SBIN, _BB_SUID_NEVER)) */ USE_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tcpsvd)) USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -365,6 +380,7 @@ USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) #endif USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_NEVER, touch)) USE_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) @@ -372,6 +388,7 @@ USE_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) USE_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_NEVER, true)) USE_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_NEVER)) //USE_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) diff --git a/release/src/router/busybox/include/busybox.h b/release/src/router/busybox/include/busybox.h index 314b95126f..54c278f87d 100644 --- a/release/src/router/busybox/include/busybox.h +++ b/release/src/router/busybox/include/busybox.h @@ -4,14 +4,12 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#ifndef _BB_INTERNAL_H_ -#define _BB_INTERNAL_H_ 1 +#ifndef BUSYBOX_H +#define BUSYBOX_H 1 #include "libbb.h" -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* order matters: used as index into "install_dir[]" in appletlib.c */ typedef enum bb_install_loc_t { @@ -71,8 +69,6 @@ int lbb_main(char **argv); #endif #endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* _BB_INTERNAL_H_ */ +#endif diff --git a/release/src/router/busybox/include/dump.h b/release/src/router/busybox/include/dump.h index 44f2082b7c..925270d9cc 100644 --- a/release/src/router/busybox/include/dump.h +++ b/release/src/router/busybox/include/dump.h @@ -1,8 +1,6 @@ /* vi: set sw=4 ts=4: */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN #define F_IGNORE 0x01 /* %_A */ #define F_SETREP 0x02 /* rep count set, not default */ @@ -55,6 +53,4 @@ dumper_t* alloc_dumper(void) FAST_FUNC; extern void bb_dump_add(dumper_t *dumper, const char *fmt) FAST_FUNC; extern int bb_dump_dump(dumper_t *dumper, char **argv) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY diff --git a/release/src/router/busybox/include/grp_.h b/release/src/router/busybox/include/grp_.h index 23c4dcc035..deaf9e6a32 100644 --- a/release/src/router/busybox/include/grp_.h +++ b/release/src/router/busybox/include/grp_.h @@ -15,27 +15,20 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - + 02111-1307 USA. + */ /* * POSIX Standard: 9.2.1 Group Database Access */ +#ifndef BB_GRP_H +#define BB_GRP_H 1 -#ifndef _GRP_H -#define _GRP_H 1 - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif - -/* The group structure. */ -struct group { - char *gr_name; /* Group name. */ - char *gr_passwd; /* Password. */ - gid_t gr_gid; /* Group ID. */ - char **gr_mem; /* Member list. */ -}; +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN +/* This file is #included after #include + * We will use libc-defined structures, but will #define function names + * so that function calls are directed to bb_internal_XXX replacements + */ #define setgrent bb_internal_setgrent #define endgrent bb_internal_endgrent @@ -53,9 +46,7 @@ struct group { /* All function names below should be remapped by #defines above - * in order to not collide with libc names. - * In theory it isn't necessary, but I saw weird interactions at link time. - * Let's play safe */ + * in order to not collide with libc names. */ /* Rewind the group-file stream. */ @@ -71,14 +62,14 @@ extern struct group *getgrent(void); extern struct group *fgetgrent(FILE *__stream); /* Write the given entry onto the given stream. */ -extern int putgrent(__const struct group *__restrict __p, +extern int putgrent(const struct group *__restrict __p, FILE *__restrict __f); /* Search for an entry with a matching group ID. */ extern struct group *getgrgid(gid_t __gid); /* Search for an entry with a matching group name. */ -extern struct group *getgrnam(__const char *__name); +extern struct group *getgrnam(const char *__name); /* Reentrant versions of some of the functions above. @@ -98,7 +89,7 @@ extern int getgrgid_r(gid_t __gid, struct group *__restrict __resultbuf, struct group **__restrict __result); /* Search for an entry with a matching group name. */ -extern int getgrnam_r(__const char *__restrict __name, +extern int getgrnam_r(const char *__restrict __name, struct group *__restrict __resultbuf, char *__restrict __buffer, size_t __buflen, struct group **__restrict __result); @@ -113,16 +104,14 @@ extern int fgetgrent_r(FILE *__restrict __stream, /* Store at most *NGROUPS members of the group set for USER into *GROUPS. Also include GROUP. The actual number of groups found is returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. */ -extern int getgrouplist(__const char *__user, gid_t __group, +extern int getgrouplist(const char *__user, gid_t __group, gid_t *__groups, int *__ngroups); /* Initialize the group set for the current user by reading the group database and using all groups of which USER is a member. Also include GROUP. */ -extern int initgroups(__const char *__user, gid_t __group); +extern int initgroups(const char *__user, gid_t __group); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/include/libbb.h b/release/src/router/busybox/include/libbb.h index ef1f6c934d..1faa9e9fd2 100644 --- a/release/src/router/busybox/include/libbb.h +++ b/release/src/router/busybox/include/libbb.h @@ -7,8 +7,8 @@ * * Licensed under the GPL version 2, see the file LICENSE in this tarball. */ -#ifndef __LIBBUSYBOX_H__ -#define __LIBBUSYBOX_H__ 1 +#ifndef LIBBB_H +#define LIBBB_H 1 #include "platform.h" @@ -69,21 +69,15 @@ #include #endif -#if !ENABLE_USE_BB_PWD_GRP -# include -# include -#endif +#include +#include #if ENABLE_FEATURE_SHADOWPASSWDS -# if !ENABLE_USE_BB_SHADOW -# include -# endif +# include #endif /* Some libc's forget to declare these, do it ourself */ -extern char **environ; -/* Set the group set for the current user to GROUPS (N of them). */ -int setgroups(size_t n, const gid_t *groups); +extern char **environ; #if defined(__GLIBC__) && __GLIBC__ < 2 int vdprintf(int d, const char *format, va_list ap); #endif @@ -109,16 +103,14 @@ struct sysinfo { 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.. */ + char _f[20 - 2 * sizeof(long) - sizeof(int)]; /* Padding: libc5 uses this.. */ }; int sysinfo(struct sysinfo* info); /* Make all declarations hidden (-fvisibility flag only affects definitions) */ /* (don't include system headers after this until corresponding pop!) */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN #if ENABLE_USE_BB_PWD_GRP @@ -156,6 +148,7 @@ int sysinfo(struct sysinfo* info); /* CONFIG_LFS is on */ # 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) /* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */ # define BB_STRTOOFF bb_strtoul @@ -164,6 +157,7 @@ int sysinfo(struct sysinfo* info); # define OFF_FMT "l" # else /* "long" is too short, need "long long" */ +typedef unsigned long long uoff_t; # define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX) # define BB_STRTOOFF bb_strtoull # define STRTOOFF strtoull @@ -174,11 +168,13 @@ int sysinfo(struct sysinfo* info); # if UINT_MAX == 0xffffffff /* While sizeof(off_t) == sizeof(int), off_t is typedef'ed to long anyway. * gcc will throw warnings on printf("%d", off_t). Crap... */ +typedef unsigned long uoff_t; # define XATOOFF(a) xatoi_u(a) # define BB_STRTOOFF bb_strtou # define STRTOOFF strtol # define OFF_FMT "l" # else +typedef unsigned long uoff_t; # define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtol @@ -359,8 +355,8 @@ enum { void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; /* Unlike signal() and bb_signals, sets handler with sigaction() * and in a way that while signal handler is run, no other signals - * will be blocked: */ -void bb_signals_recursive(int sigs, void (*f)(int)) FAST_FUNC; + * will be blocked; syscalls will not be restarted: */ +void bb_signals_recursive_norestart(int sigs, void (*f)(int)) FAST_FUNC; /* syscalls like read() will be interrupted with EINTR: */ void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC; /* syscalls like read() won't be interrupted (though select/poll will be): */ @@ -373,6 +369,9 @@ void sig_unblock(int sig) FAST_FUNC; int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; /* SIG_BLOCK/SIG_UNBLOCK all signals: */ int sigprocmask_allsigs(int how) FAST_FUNC; +/* Standard handler which just records signo */ +extern smallint bb_got_signal; +void record_signo(int signo); /* not FAST_FUNC! */ void xsetgid(gid_t gid) FAST_FUNC; @@ -380,6 +379,7 @@ void xsetuid(uid_t uid) FAST_FUNC; void xchdir(const char *path) FAST_FUNC; void xchroot(const char *path) FAST_FUNC; void xsetenv(const char *key, const char *value) FAST_FUNC; +void bb_unsetenv(const char *key) FAST_FUNC; void xunlink(const char *pathname) FAST_FUNC; void xstat(const char *pathname, struct stat *buf) FAST_FUNC; int xopen(const char *pathname, int flags) FAST_FUNC FAST_FUNC; @@ -440,6 +440,7 @@ ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, * Turn it on before you call bind(). */ void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */ int setsockopt_broadcast(int fd) FAST_FUNC; +int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; /* NB: returns port in host byte order */ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC; typedef struct len_and_sockaddr { @@ -490,6 +491,8 @@ int create_and_bind_dgram_or_die(const char *bindaddr, int port) FAST_FUNC; int create_and_connect_stream_or_die(const char *peer, int port) FAST_FUNC; /* Connect to peer identified by lsa */ int xconnect_stream(const len_and_sockaddr *lsa) FAST_FUNC; +/* Get local address of bound or accepted socket */ +len_and_sockaddr *get_sock_lsa(int fd) FAST_FUNC; /* Return malloc'ed len_and_sockaddr with socket address of host:port * Currently will return IPv4 or IPv6 sockaddrs only * (depending on host), but in theory nothing prevents e.g. @@ -543,6 +546,7 @@ char *xstrdup(const char *s) FAST_FUNC; char *xstrndup(const char *s, int n) FAST_FUNC; void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; +char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; /* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc. * But potentially slow, don't use in one-billion-times loops */ int bb_putchar(int ch) FAST_FUNC; @@ -592,9 +596,9 @@ extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FA // 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; -/* Reads block up to *maxsz_p (default: MAX_INT(ssize_t)) */ +/* Reads block up to *maxsz_p (default: INT_MAX - 4095) */ extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC; -/* Returns NULL if file can't be opened */ +/* 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; /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; @@ -607,6 +611,7 @@ extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; // if some data was written before error occurred extern ssize_t full_write(int fd, const void *buf, size_t count) FAST_FUNC; extern void xwrite(int fd, const void *buf, size_t count) FAST_FUNC; +extern void xwrite_str(int fd, const char *str) FAST_FUNC; extern void xopen_xwrite_close(const char* file, const char *str) FAST_FUNC; /* Reads and prints to stdout till eof, then closes FILE. Exits on error: */ @@ -616,6 +621,8 @@ 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; +/* Same, with limited max size, and returns the length (excluding NUL): */ +extern char *xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p) FAST_FUNC; /* Chops off TERMINATING_STRING from the end: */ extern char *xmalloc_fgetline_str(FILE *file, const char *terminating_string) FAST_FUNC; /* Reads up to (and including) "\n" or NUL byte: */ @@ -704,14 +711,16 @@ int get_uidgid(struct bb_uidgid_t*, const char*, int numeric_ok) FAST_FUNC; void xget_uidgid(struct bb_uidgid_t*, const char*) FAST_FUNC; /* chown-like handling of "user[:[group]" */ void parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group) FAST_FUNC; -/* bb_getpwuid, bb_getgrgid: - * bb_getXXXid(buf, bufsz, id) - copy user/group name or id - * as a string to buf, return user/group name or NULL - * bb_getXXXid(NULL, 0, id) - return user/group name or NULL - * bb_getXXXid(NULL, -1, id) - return user/group name or exit -*/ -char *bb_getpwuid(char *name, int bufsize, long uid) FAST_FUNC; -char *bb_getgrgid(char *group, int bufsize, long gid) FAST_FUNC; +struct passwd* xgetpwnam(const char *name) FAST_FUNC; +struct group* xgetgrnam(const char *name) FAST_FUNC; +struct passwd* xgetpwuid(uid_t uid) FAST_FUNC; +struct group* xgetgrgid(gid_t gid) FAST_FUNC; +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; /* 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; @@ -746,7 +755,7 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; pid_t spawn(char **argv) FAST_FUNC; pid_t xspawn(char **argv) FAST_FUNC; -int safe_waitpid(int pid, int *wstat, int options) FAST_FUNC; +pid_t safe_waitpid(pid_t pid, int *wstat, int options) FAST_FUNC; /* Unlike waitpid, waits ONLY for one process. * It's safe to pass negative 'pids' from failed [v]fork - * wait4pid will return -1 (and will not clobber [v]fork's errno). @@ -754,14 +763,14 @@ int safe_waitpid(int pid, int *wstat, int options) FAST_FUNC; * if (rc < 0) bb_perror_msg("%s", argv[0]); * if (rc > 0) bb_error_msg("exit code: %d", rc); */ -int wait4pid(int pid) FAST_FUNC; -int wait_any_nohang(int *wstat) FAST_FUNC; +int wait4pid(pid_t pid) FAST_FUNC; +pid_t wait_any_nohang(int *wstat) FAST_FUNC; #define wait_crashed(w) ((w) & 127) #define wait_exitcode(w) ((w) >> 8) #define wait_stopsig(w) ((w) >> 8) #define wait_stopped(w) (((w) & 127) == 127) /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ -int spawn_and_wait(char **argv) FAST_FUNC; +pid_t spawn_and_wait(char **argv) FAST_FUNC; struct nofork_save_area { jmp_buf die_jmp; const char *applet_name; @@ -790,9 +799,9 @@ int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char ** * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty * (will do setsid()). * - * forkexit_or_rexec(argv) = bare-bones "fork + parent exits" on MMU, + * fork_or_rexec(argv) = bare-bones "fork" on MMU, * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid(). - * Currently used for openvt and setsid. On MMU ignores argv. + * On MMU ignores argv. * * Helper for network daemons in foreground mode: * @@ -806,14 +815,14 @@ enum { DAEMON_ONLY_SANITIZE = 8, /* internal use */ }; #if BB_MMU - void forkexit_or_rexec(void) FAST_FUNC; + pid_t fork_or_rexec(void) FAST_FUNC; enum { re_execed = 0 }; -# define forkexit_or_rexec(argv) forkexit_or_rexec() +# define fork_or_rexec(argv) fork_or_rexec() # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else void re_exec(char **argv) NORETURN FAST_FUNC; - void forkexit_or_rexec(char **argv) FAST_FUNC; + pid_t fork_or_rexec(char **argv) FAST_FUNC; extern bool re_execed; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC; @@ -850,6 +859,7 @@ void *llist_pop(llist_t **elm) FAST_FUNC; void llist_unlink(llist_t **head, llist_t *elm) FAST_FUNC; void llist_free(llist_t *elm, void (*freeit)(void *data)) FAST_FUNC; llist_t *llist_rev(llist_t *list) FAST_FUNC; +llist_t *llist_find_str(llist_t *first, const char *str) FAST_FUNC; /* BTW, surprisingly, changing API to * llist_t *llist_add_to(llist_t *old_head, void *data) * etc does not result in smaller code... */ @@ -885,7 +895,7 @@ extern void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, f extern void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; extern void bb_simple_perror_msg(const char *s) FAST_FUNC; extern void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; -extern void bb_simple_perror_msg_and_die(const char *s) __attribute__ ((noreturn)) FAST_FUNC; +extern void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; extern void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; extern void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; extern void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; @@ -912,18 +922,52 @@ int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE); int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE); /* Similar, but used by chgrp, not shell */ int chown_main(int argc, char **argv) USE_CHOWN(MAIN_EXTERNALLY_VISIBLE); +/* Used by ftpd */ +int ls_main(int argc, char **argv) USE_LS(MAIN_EXTERNALLY_VISIBLE); /* Don't need USE_xxx() guard for these */ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int bbunpack(char **argv, - char* (*make_new_name)(char *filename), - USE_DESKTOP(long long) int (*unpacker)(void) -) FAST_FUNC; + #if ENABLE_ROUTE void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC; #endif +/* "Keycodes" that report an escape sequence. + * We use something which fits into signed char, + * yet doesn't represent any valid Unicode characher. + * Also, -1 is reserved for error indication and we don't use it. */ +enum { + KEYCODE_UP = -2, + KEYCODE_DOWN = -3, + KEYCODE_RIGHT = -4, + KEYCODE_LEFT = -5, + KEYCODE_HOME = -6, + KEYCODE_END = -7, + KEYCODE_INSERT = -8, + KEYCODE_DELETE = -9, + KEYCODE_PAGEUP = -10, + KEYCODE_PAGEDOWN = -11, +#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, +#endif + /* How long the longest ESC sequence we know? */ + KEYCODE_BUFFER_SIZE = 4 +}; +int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC; + + /* Networking */ int create_icmp_socket(void) FAST_FUNC; int create_icmp6_socket(void) FAST_FUNC; @@ -991,9 +1035,10 @@ extern int del_loop(const char *device) FAST_FUNC; * 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; - +/* Like bb_ask below, but asks on stdin with no timeout. */ +char *bb_ask_stdin(const char * prompt) FAST_FUNC; //TODO: pass buf pointer or return allocated buf (avoid statics)? -char *bb_askpass(int timeout, const char * prompt) FAST_FUNC; +char *bb_ask(const int fd, int timeout, const char * prompt) FAST_FUNC; int bb_ask_confirmation(void) FAST_FUNC; int bb_parse_mode(const char* s, mode_t* theMode) FAST_FUNC; @@ -1008,7 +1053,7 @@ enum { PARSE_GREEDY = 0x00040000, // last token takes entire remainder of the line PARSE_MIN_DIE = 0x00100000, // die if < min tokens found // keep a copy of current line - PARSE_KEEP_COPY = 0x00200000 * ENABLE_DEBUG_CROND_OPTION, + PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, // PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens // NORMAL is: // * remove leading and trailing delimiters and collapse @@ -1097,9 +1142,16 @@ extern int obscure(const char *old, const char *newval, const struct passwd *pwd * (otherwise we risk having same salt generated) */ extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; + /* Returns number of lines changed, or -1 on error */ -extern int update_passwd(const char *filename, const char *username, - const char *new_pw) FAST_FUNC; +#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) +#define update_passwd(filename, username, data, member) \ + update_passwd(filename, username, data) +#endif +extern int update_passwd(const char *filename, + const char *username, + const char *data, + const char *member) FAST_FUNC; int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC; int index_in_strings(const char *strings, const char *key) FAST_FUNC; @@ -1110,9 +1162,12 @@ const char *nth_string(const char *strings, int n) FAST_FUNC; extern void print_login_issue(const char *issue_file, const char *tty) FAST_FUNC; extern void print_login_prompt(void) FAST_FUNC; +char *xmalloc_ttyname(int fd) FAST_FUNC; /* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */ int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FUNC; +int tcsetattr_stdin_TCSANOW(const struct termios *tp) FAST_FUNC; + /* NB: "unsigned request" is crucial! "int request" will break some arches! */ int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; @@ -1142,9 +1197,9 @@ unsigned long long bb_makedev(unsigned int major, unsigned int minor) FAST_FUNC; #if ENABLE_FEATURE_EDITING /* It's NOT just ENABLEd or disabled. It's a number: */ #ifdef CONFIG_FEATURE_EDITING_HISTORY -#define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0) +# define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0) #else -#define MAX_HISTORY 0 +# define MAX_HISTORY 0 #endif typedef struct line_input_t { int flags; @@ -1152,7 +1207,10 @@ typedef struct line_input_t { #if MAX_HISTORY int cnt_history; int cur_history; - USE_FEATURE_EDITING_SAVEHISTORY(const char *hist_file;) +#if ENABLE_FEATURE_EDITING_SAVEHISTORY + unsigned cnt_history_in_file; + const char *hist_file; +#endif char *history[MAX_HISTORY + 1]; #endif } line_input_t; @@ -1166,6 +1224,7 @@ enum { FOR_SHELL = DO_HISTORY | SAVE_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; */ /* Returns: * -1 on read errors or EOF, or on bare Ctrl-D, * 0 on ctrl-C (the line entered is still returned in 'command'), @@ -1222,6 +1281,9 @@ typedef struct procps_status_t { * by link target or interpreter name) */ char comm[COMM_LEN]; /* user/group? - use passwd/group parsing functions */ +#if ENABLE_FEATURE_TOP_SMP_PROCESS + int last_seen_on_cpu; +#endif } procps_status_t; enum { PSSCAN_PID = 1 << 0, @@ -1240,15 +1302,25 @@ enum { PSSCAN_UTIME = 1 << 13, PSSCAN_TTY = 1 << 14, PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM, - PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP || ENABLE_PKILL || ENABLE_PIDOF), + /* NB: used by find_pid_by_name(). Any applet using it + * needs to be mentioned here. */ + PSSCAN_ARGVN = (1 << 16) * (ENABLE_KILLALL + || ENABLE_PGREP || ENABLE_PKILL + || ENABLE_PIDOF + || ENABLE_SESTATUS + ), USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) PSSCAN_START_TIME = 1 << 18, + PSSCAN_CPU = 1 << 19, /* 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_COMM | PSSCAN_STATE + /**/ | PSSCAN_VSZ | PSSCAN_RSS + /**/ | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME + /**/ | PSSCAN_TTY +#if ENABLE_FEATURE_TOP_SMP_PROCESS + /**/ | PSSCAN_CPU +#endif }; //procps_status_t* alloc_procps_scan(void) FAST_FUNC; void free_procps_scan(procps_status_t* sp) FAST_FUNC; @@ -1265,14 +1337,27 @@ extern const char bb_uuenc_tbl_std[]; void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; typedef struct sha1_ctx_t { - uint32_t count[2]; - uint32_t hash[5]; - uint32_t wbuf[16]; + uint32_t hash[8]; /* 5, +3 elements for sha256 */ + uint64_t total64; + uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */ + void (*process_block)(struct sha1_ctx_t*) FAST_FUNC; } sha1_ctx_t; void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC; void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx) FAST_FUNC; -void *sha1_end(void *resbuf, sha1_ctx_t *ctx) FAST_FUNC; - +void sha1_end(void *resbuf, sha1_ctx_t *ctx) FAST_FUNC; +typedef struct sha1_ctx_t sha256_ctx_t; +void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; +#define sha256_hash sha1_hash +#define sha256_end sha1_end +typedef struct sha512_ctx_t { + uint64_t hash[8]; + uint64_t total64[2]; + uint8_t wbuffer[128]; /* NB: always correctly aligned for uint64_t */ +} sha512_ctx_t; +void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; +void sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) FAST_FUNC; +void sha512_end(void *resbuf, sha512_ctx_t *ctx) FAST_FUNC; +#if 1 typedef struct md5_ctx_t { uint32_t A; uint32_t B; @@ -1282,9 +1367,18 @@ typedef struct md5_ctx_t { uint32_t buflen; char buffer[128]; } md5_ctx_t; +#else +/* libbb/md5prime.c uses a bit different one: */ +typedef struct md5_ctx_t { + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} md5_ctx_t; +#endif void md5_begin(md5_ctx_t *ctx) FAST_FUNC; void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) FAST_FUNC; -void *md5_end(void *resbuf, md5_ctx_t *ctx) FAST_FUNC; +void md5_end(void *resbuf, md5_ctx_t *ctx) FAST_FUNC; + uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; @@ -1329,7 +1423,7 @@ extern const char bb_busybox_exec_path[]; * but I want to save a few bytes here */ extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ #define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) -#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/bin:/usr/bin:/sbin:/usr/sbin")) +#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) extern const int const_int_0; extern const int const_int_1; @@ -1444,9 +1538,6 @@ extern const char bb_default_login_shell[]; #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif - +POP_SAVED_FUNCTION_VISIBILITY -#endif /* __LIBBUSYBOX_H__ */ +#endif diff --git a/release/src/router/busybox/include/platform.h b/release/src/router/busybox/include/platform.h index 0f2f83a7dd..47fd5f63d2 100644 --- a/release/src/router/busybox/include/platform.h +++ b/release/src/router/busybox/include/platform.h @@ -1,11 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - Copyright 2006, Bernhard Fischer + Copyright 2006, Bernhard Reutner-Fischer Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#ifndef __PLATFORM_H -#define __PLATFORM_H 1 +#ifndef BB_PLATFORM_H +#define BB_PLATFORM_H 1 /* Convenience macros to test the version of gcc. */ #undef __GNUC_PREREQ @@ -78,7 +78,7 @@ //__attribute__ ((__externally_visible__)) #else # define EXTERNALLY_VISIBLE -#endif /* GNUC >= 4.1 */ +#endif /* We use __extension__ in some places to suppress -pedantic warnings about GCC extensions. This feature didn't work properly before @@ -110,6 +110,16 @@ # define FAST_FUNC #endif +/* Make all declarations hidden (-fvisibility flag only affects definitions) */ +/* (don't include system headers after this until corresponding pop!) */ +#if __GNUC_PREREQ(4,1) +# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") +# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") +#else +# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN +# define POP_SAVED_FUNCTION_VISIBILITY +#endif + /* ---- Endian Detection ------------------------------------ */ #if (defined __digital__ && defined __unix__) @@ -132,6 +142,7 @@ # define BB_LITTLE_ENDIAN 1 #endif +/* SWAP_LEnn means "convert CPU<->little_endian by swapping bytes" */ #if BB_BIG_ENDIAN #define SWAP_BE16(x) (x) #define SWAP_BE32(x) (x) @@ -150,13 +161,19 @@ /* ---- Unaligned access ------------------------------------ */ -/* parameter is supposed to be an uint32_t* ptr */ +/* 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__) -#define get_unaligned_u32p(u32p) (*(u32p)) +#define move_from_unaligned16(v, u16p) ((v) = *(uint16_t*)(u16p)) +#define move_from_unaligned32(v, u32p) ((v) = *(uint32_t*)(u32p)) +#define move_to_unaligned32(u32p, v) (*(uint32_t*)(u32p) = (v)) /* #elif ... - add your favorite arch today! */ #else /* performs reasonably well (gcc usually inlines memcpy here) */ -#define get_unaligned_u32p(u32p) ({ uint32_t __t; memcpy(&__t, (u32p), 4); __t; }) +#define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2)) +#define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) +#define move_to_unaligned32(u32p, v) (memcpy((u32p), &(v), 4)) #endif /* ---- Networking ------------------------------------------ */ @@ -184,7 +201,7 @@ typedef int socklen_t; * until userspace is widely fixed. */ #if (defined __INTEL_COMPILER && !defined __GNUC__) || \ (defined __GNUC__ && defined __STRICT_ANSI__) -__extension__ typedef __signed__ long long __s64; +__extension__ typedef long long __s64; __extension__ typedef unsigned long long __u64; #endif @@ -295,30 +312,32 @@ static ALWAYS_INLINE char* strchrnul(const char *s, char c) #endif #if (defined __digital__ && defined __unix__) -#include -#define HAVE_STANDARDS_H -#include -#define HAVE_INTTYPES_H -#define PRIu32 "u" +# include +# define HAVE_STANDARDS_H +# include +# define HAVE_INTTYPES_H +# define PRIu32 "u" /* use legacy setpgrp(pid_t,pid_t) for now. move to platform.c */ -#define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me,__me); } while (0) +# define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me,__me); } while (0) -#if !defined ADJ_OFFSET_SINGLESHOT && defined MOD_CLKA && defined MOD_OFFSET -#define ADJ_OFFSET_SINGLESHOT (MOD_CLKA | MOD_OFFSET) -#endif -#if !defined ADJ_FREQUENCY && defined MOD_FREQUENCY -#define ADJ_FREQUENCY MOD_FREQUENCY -#endif -#if !defined ADJ_TIMECONST && defined MOD_TIMECONST -#define ADJ_TIMECONST MOD_TIMECONST -#endif -#if !defined ADJ_TICK && defined MOD_CLKB -#define ADJ_TICK MOD_CLKB -#endif +# if !defined ADJ_OFFSET_SINGLESHOT && defined MOD_CLKA && defined MOD_OFFSET +# define ADJ_OFFSET_SINGLESHOT (MOD_CLKA | MOD_OFFSET) +# endif +# if !defined ADJ_FREQUENCY && defined MOD_FREQUENCY +# define ADJ_FREQUENCY MOD_FREQUENCY +# endif +# if !defined ADJ_TIMECONST && defined MOD_TIMECONST +# define ADJ_TIMECONST MOD_TIMECONST +# endif +# if !defined ADJ_TICK && defined MOD_CLKB +# define ADJ_TICK MOD_CLKB +# endif + +#else /* !__digital__ */ + +# define bb_setpgrp() setpgrp() -#else -#define bb_setpgrp() setpgrp() #endif #if defined(__linux__) @@ -362,4 +381,4 @@ static ALWAYS_INLINE char* strchrnul(const char *s, char c) #endif #endif -#endif /* platform.h */ +#endif diff --git a/release/src/router/busybox/include/pwd_.h b/release/src/router/busybox/include/pwd_.h index 6199034d2b..f52445ceba 100644 --- a/release/src/router/busybox/include/pwd_.h +++ b/release/src/router/busybox/include/pwd_.h @@ -21,24 +21,15 @@ * POSIX Standard: 9.2.2 User Database Access */ -#ifndef _PWD_H -#define _PWD_H 1 +#ifndef BB_PWD_H +#define BB_PWD_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif - -/* The passwd structure. */ -struct passwd { - char *pw_name; /* Username. */ - char *pw_passwd; /* Password. */ - uid_t pw_uid; /* User ID. */ - gid_t pw_gid; /* Group ID. */ - char *pw_gecos; /* Real name. */ - char *pw_dir; /* Home directory. */ - char *pw_shell; /* Shell program. */ -}; +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN +/* This file is #included after #include + * We will use libc-defined structures, but will #define function names + * so that function calls are directed to bb_internal_XXX replacements + */ #define setpwent bb_internal_setpwent #define endpwent bb_internal_endpwent @@ -51,13 +42,11 @@ struct passwd { #define getpwuid_r bb_internal_getpwuid_r #define getpwnam_r bb_internal_getpwnam_r #define fgetpwent_r bb_internal_fgetpwent_r -#define getpw bb_internal_getpw +//#define getpw bb_internal_getpw /* All function names below should be remapped by #defines above - * in order to not collide with libc names. - * In theory it isn't necessary, but I saw weird interactions at link time. - * Let's play safe */ + * in order to not collide with libc names. */ /* Rewind the password-file stream. */ @@ -73,14 +62,14 @@ extern struct passwd *getpwent(void); extern struct passwd *fgetpwent(FILE *__stream); /* Write the given entry onto the given stream. */ -extern int putpwent(__const struct passwd *__restrict __p, +extern int putpwent(const struct passwd *__restrict __p, FILE *__restrict __f); /* Search for an entry with a matching user ID. */ extern struct passwd *getpwuid(uid_t __uid); /* Search for an entry with a matching username. */ -extern struct passwd *getpwnam(__const char *__name); +extern struct passwd *getpwnam(const char *__name); /* Reentrant versions of some of the functions above. @@ -99,7 +88,7 @@ extern int getpwuid_r(uid_t __uid, char *__restrict __buffer, size_t __buflen, struct passwd **__restrict __result); -extern int getpwnam_r(__const char *__restrict __name, +extern int getpwnam_r(const char *__restrict __name, struct passwd *__restrict __resultbuf, char *__restrict __buffer, size_t __buflen, struct passwd **__restrict __result); @@ -114,10 +103,8 @@ extern int fgetpwent_r(FILE *__restrict __stream, /* Re-construct the password-file line for the given uid in the given buffer. This knows the format that the caller will expect, but this need not be the format of the password file. */ -extern int getpw(uid_t __uid, char *__buffer); +/* UNUSED extern int getpw(uid_t __uid, char *__buffer); */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif /* pwd.h */ diff --git a/release/src/router/busybox/include/rtc_.h b/release/src/router/busybox/include/rtc_.h index 2e990581fa..74bb695a08 100644 --- a/release/src/router/busybox/include/rtc_.h +++ b/release/src/router/busybox/include/rtc_.h @@ -4,14 +4,12 @@ * Licensed under the GPL-2 or later. */ -#ifndef _BB_RTC_H_ -#define _BB_RTC_H_ +#ifndef BB_RTC_H +#define BB_RTC_H 1 #include "libbb.h" -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN extern int rtc_adjtime_is_utc(void) FAST_FUNC; extern int rtc_xopen(const char **default_rtc, int flags) FAST_FUNC; @@ -44,27 +42,26 @@ struct linux_rtc_wkalrm { * ioctl calls that are permitted to the /dev/rtc interface, if * any of the RTC drivers are enabled. */ +#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ +#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ +#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ +#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ +#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ +#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ +#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ -#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ -#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ - -#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */ -#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */ +#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */ +#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ +#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ +#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ +#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ -#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ -#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ +#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ +#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ /* interrupt flags */ #define RTC_IRQF 0x80 /* any of the following is active */ @@ -72,8 +69,6 @@ struct linux_rtc_wkalrm { #define RTC_AF 0x20 #define RTC_UF 0x10 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/include/shadow_.h b/release/src/router/busybox/include/shadow_.h index 5a8b71a471..02d3bf9a56 100644 --- a/release/src/router/busybox/include/shadow_.h +++ b/release/src/router/busybox/include/shadow_.h @@ -19,32 +19,21 @@ /* Declaration of types and functions for shadow password suite */ -#ifndef _SHADOW_H -#define _SHADOW_H 1 +#ifndef BB_SHADOW_H +#define BB_SHADOW_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +/* This file is #included after #include + * We will use libc-defined structures, but will #define function names + * so that function calls are directed to bb_internal_XXX replacements + */ /* Paths to the user database files */ #ifndef _PATH_SHADOW #define _PATH_SHADOW "/etc/shadow" #endif -/* Structure of the password file */ -struct spwd { - char *sp_namp; /* Login name */ - char *sp_pwdp; /* Encrypted password */ - long sp_lstchg; /* Date of last change */ - long sp_min; /* Minimum number of days between changes */ - long sp_max; /* Maximum number of days between changes */ - long sp_warn; /* Number of days to warn user to change the password */ - long sp_inact; /* Number of days the account may be inactive */ - long sp_expire; /* Number of days since 1970-01-01 until account expires */ - unsigned long sp_flag; /* Reserved */ -}; - - #define setspent bb_internal_setspent #define endspent bb_internal_endspent #define getspent bb_internal_getspent @@ -61,9 +50,7 @@ struct spwd { /* All function names below should be remapped by #defines above - * in order to not collide with libc names. - * In theory it isn't necessary, but I saw weird interactions at link time. - * Let's play safe */ + * in order to not collide with libc names. */ /* Open database for reading */ @@ -76,26 +63,26 @@ extern void endspent(void); extern struct spwd *getspent(void); /* Get shadow entry matching NAME */ -extern struct spwd *getspnam(__const char *__name); +extern struct spwd *getspnam(const char *__name); /* Read shadow entry from STRING */ -extern struct spwd *sgetspent(__const char *__string); +extern struct spwd *sgetspent(const char *__string); /* Read next shadow entry from STREAM */ extern struct spwd *fgetspent(FILE *__stream); /* Write line containing shadow password entry to stream */ -extern int putspent(__const struct spwd *__p, FILE *__stream); +extern int putspent(const struct spwd *__p, FILE *__stream); /* Reentrant versions of some of the functions above */ extern int getspent_r(struct spwd *__result_buf, char *__buffer, size_t __buflen, struct spwd **__result); -extern int getspnam_r(__const char *__name, struct spwd *__result_buf, +extern int getspnam_r(const char *__name, struct spwd *__result_buf, char *__buffer, size_t __buflen, struct spwd **__result); -extern int sgetspent_r(__const char *__string, struct spwd *__result_buf, +extern int sgetspent_r(const char *__string, struct spwd *__result_buf, char *__buffer, size_t __buflen, struct spwd **__result); @@ -108,8 +95,6 @@ extern int lckpwdf(void); /* Unlock password file */ extern int ulckpwdf(void); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif /* shadow.h */ diff --git a/release/src/router/busybox/include/unarchive.h b/release/src/router/busybox/include/unarchive.h index 7ff791be53..beb962c8ff 100644 --- a/release/src/router/busybox/include/unarchive.h +++ b/release/src/router/busybox/include/unarchive.h @@ -1,10 +1,8 @@ /* vi: set sw=4 ts=4: */ -#ifndef __UNARCHIVE_H__ -#define __UNARCHIVE_H__ +#ifndef UNARCHIVE_H +#define UNARCHIVE_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN #define ARCHIVE_PRESERVE_DATE 1 #define ARCHIVE_CREATE_LEADING_DIRS 2 @@ -77,6 +75,12 @@ typedef struct archive_handle_t { } archive_handle_t; +/* Info struct unpackers can fill out to inform users of thing like + * timestamps of unpacked files */ +typedef struct unpack_info_t { + time_t mtime; +} unpack_info_t; + extern archive_handle_t *init_handle(void) FAST_FUNC; extern char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; @@ -126,10 +130,15 @@ USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; /* the rest wants 2 first bytes already skipped by the caller */ USE_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; +USE_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; USE_DESKTOP(long long) int unpack_Z_stream(int fd_in, int fd_out) FAST_FUNC; /* wrapper which checks first two bytes to be "BZ" */ USE_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; +int bbunpack(char **argv, + char* (*make_new_name)(char *filename), + USE_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)) FAST_FUNC; + #if BB_MMU void open_transformer(int fd, USE_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; @@ -139,8 +148,6 @@ void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; #define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) #endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/include/usage.h b/release/src/router/busybox/include/usage.h index 57a9f99b8a..d3bf7849e0 100644 --- a/release/src/router/busybox/include/usage.h +++ b/release/src/router/busybox/include/usage.h @@ -9,25 +9,41 @@ * or * |<5 spaces>"\ntext with tabs".... */ - -#ifndef __BB_USAGE_H__ -#define __BB_USAGE_H__ +#ifndef BB_USAGE_H +#define BB_USAGE_H 1 #define NOUSAGE_STR "\b" +#define acpid_trivial_usage \ + "[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE...]" + +#define acpid_full_usage "\n\n" \ + "Listen to ACPI events and spawn specific helpers on event arrival\n" \ + "\nOptions:" \ + "\n -d Do not daemonize and log to stderr" \ + "\n -c DIR Config directory [/etc/acpi]" \ + "\n -e FILE /proc event file [/proc/acpi/event]" \ + "\n -l FILE Log file [/var/log/acpid]" \ + USE_FEATURE_ACPID_COMPAT( \ + "\n\nAccept and ignore compatibility options -g -m -s -S -v" \ + ) + +#define acpid_example_usage \ + "# acpid -l /var/log/my-acpi-log\n" \ + "# acpid -d /dev/input/event*\n" #define addgroup_trivial_usage \ "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name" #define addgroup_full_usage "\n\n" \ - "Add a group " USE_FEATURE_ADDUSER_TO_GROUP("or add an user to a group") "\n" \ + "Add a group " USE_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \ "\nOptions:" \ "\n -g GID Group id" \ #define adduser_trivial_usage \ "[OPTIONS] user_name" #define adduser_full_usage "\n\n" \ - "Add an user\n" \ + "Add a user\n" \ "\nOptions:" \ "\n -h DIR Home directory" \ "\n -g GECOS GECOS field" \ @@ -61,12 +77,11 @@ "\n -v Verbose" \ #define arp_trivial_usage \ - "\n" \ - "[-vn] [-H type] [-i if] -a [hostname]\n" \ - "[-v] [-i if] -d hostname [pub]\n" \ - "[-v] [-H type] [-i if] -s hostname hw_addr [temp]\n" \ - "[-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n" \ - "[-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub\n" + "\n[-vn] [-H type] [-i if] -a [hostname]" \ + "\n[-v] [-i if] -d hostname [pub]" \ + "\n[-v] [-H type] [-i if] -s hostname hw_addr [temp]" \ + "\n[-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub" \ + "\n[-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub" #define arp_full_usage "\n\n" \ "Manipulate ARP cache\n" \ "\nOptions:" \ @@ -515,33 +530,38 @@ "\n -l,-s Create (sym)links" \ #define cpio_trivial_usage \ - "-[dim" USE_FEATURE_CPIO_O("o") "tuv][F cpiofile]" \ - USE_FEATURE_CPIO_O( "[H newc]" ) + "-[ti" USE_FEATURE_CPIO_O("o") USE_FEATURE_CPIO_P("p") "dmvu] [-F FILE]" \ + USE_FEATURE_CPIO_O( " [-H newc]" ) #define cpio_full_usage "\n\n" \ "Extract or list files from a cpio archive" \ USE_FEATURE_CPIO_O( ", or create a cpio archive" ) \ - "\n" \ - "Main operation mode:" \ - "\n d Make leading directories" \ - "\n i Extract" \ - "\n m Preserve mtime" \ + "\nMain operation mode:" \ + "\n -t List" \ + "\n -i Extract" \ USE_FEATURE_CPIO_O( \ - "\n o Create" \ - "\n H newc Define format" \ + "\n -o Create" \ + ) \ + USE_FEATURE_CPIO_P( \ + "\n -p Passthrough" \ + ) \ + "\nOptions:" \ + "\n -d Make leading directories" \ + "\n -m Preserve mtime" \ + "\n -v Verbose" \ + "\n -u Overwrite" \ + "\n -F Input file" \ + USE_FEATURE_CPIO_O( \ + "\n -H Define format" \ ) \ - "\n t List" \ - "\n v Verbose" \ - "\n u Unconditional overwrite" \ - "\n F Input from file" \ #define crond_trivial_usage \ - "-fbS -l N " USE_DEBUG_CROND_OPTION("-d N ") "-L LOGFILE -c DIR" + "-fbS -l N " USE_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" \ - USE_DEBUG_CROND_OPTION( \ + USE_FEATURE_CROND_D( \ "\n -d Set log level, log to stderr" \ ) \ "\n -L Log to file" \ @@ -558,12 +578,44 @@ "\n FILE Replace crontab by FILE ('-': stdin)" \ #define cryptpw_trivial_usage \ - "[-a des|md5] [string]" + "[OPTIONS] [PASSWORD] [SALT]" +/* We do support -s, we just don't mention it */ #define cryptpw_full_usage "\n\n" \ - "Output crypted string.\n" \ - "If string isn't supplied on cmdline, read it from stdin.\n" \ + "Crypt the PASSWORD using crypt(3)\n" \ + "\nOptions:" \ + USE_GETOPT_LONG( \ + "\n -P,--password-fd=NUM Read password from fd NUM" \ +/* "\n -s,--stdin Use stdin; like -P0" */ \ + "\n -m,--method=TYPE Encryption method TYPE" \ + "\n -S,--salt=SALT" \ + ) \ + SKIP_GETOPT_LONG( \ + "\n -P NUM Read password from fd NUM" \ +/* "\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:" \ - "\n -a Algorithm to use (default: md5)" \ + USE_GETOPT_LONG( \ + "\n -P,--password-fd=NUM Read password from fd NUM" \ +/* "\n -s,--stdin Use stdin; like -P0" */ \ + "\n -m,--method=TYPE Encryption method TYPE" \ + "\n -S,--salt=SALT" \ + ) \ + SKIP_GETOPT_LONG( \ + "\n -P NUM Read password from fd NUM" \ +/* "\n -s Use stdin; like -P0" */ \ + "\n -m TYPE Encryption method TYPE" \ + "\n -S SALT" \ + ) \ #define cttyhack_trivial_usage NOUSAGE_STR #define cttyhack_full_usage "" @@ -690,6 +742,15 @@ #define depmod_trivial_usage NOUSAGE_STR #define depmod_full_usage "" +#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]" USE_DEVFSD_FG_NP("[-fg][-np]") #define devfsd_full_usage "\n\n" \ @@ -705,42 +766,45 @@ "\n do not poll for events" \ ) -/* -k is accepted but ignored for !HUMAN_READABLE, - * but we won't mention this (unimportant) */ -#if ENABLE_FEATURE_HUMAN_READABLE || ENABLE_FEATURE_DF_INODE -#define DF_HAS_OPTIONS(x) x -#else -#define DF_HAS_OPTIONS(x) -#endif #define df_trivial_usage \ - DF_HAS_OPTIONS("[-") \ - USE_FEATURE_HUMAN_READABLE("hmk") USE_FEATURE_DF_INODE("i") \ - DF_HAS_OPTIONS("] ") "[FILESYSTEM...]" + "[-Pk" \ + USE_FEATURE_HUMAN_READABLE("mh") \ + USE_FEATURE_DF_FANCY("ai] [-B SIZE") \ + "] [FILESYSTEM...]" #define df_full_usage "\n\n" \ "Print filesystem usage statistics\n" \ - DF_HAS_OPTIONS("\nOptions:") \ + "\nOptions:" \ + "\n -P POSIX output format" \ + "\n -k 1024-byte blocks (default)" \ USE_FEATURE_HUMAN_READABLE( \ + "\n -m 1M-byte blocks" \ "\n -h Human readable (e.g. 1K 243M 2G)" \ - "\n -m 1024*1024 blocks" \ - "\n -k 1024 blocks" \ ) \ - USE_FEATURE_DF_INODE( \ + USE_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" \ + "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" + "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 \ - "[client1,client2,...] [server_device]" + "CLIENT_IFACE[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP]" #define dhcprelay_full_usage "\n\n" \ - "Relay dhcp requests from client devices to server device.\n" \ - "Pass clients as CSV" + "Relay DHCP requests between clients and server" \ #define diff_trivial_usage \ "[-abdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" @@ -1082,17 +1146,10 @@ "\n -H HEADS\n" \ "\n -S SECTORS" \ -#define fetchmail_trivial_usage \ - "[-w timeout] [-H [user:pass@]server[:port]] [-S] [-t] [-z] maildir [prog]" -#define fetchmail_full_usage "\n\n" \ - "Fetch content of remote mailbox to local maildir\n" \ - "\nOptions:" \ - "\n -w timeout Network timeout" \ - "\n -H [user:pass@]server[:port] Server" \ - "\n -S Use openssl connection helper for secure servers" \ - "\n -t Get only headers" \ - "\n -z Delete messages on server" \ - "\n prog Run 'prog ' on message delivery" \ +#define blkid_trivial_usage \ + "" +#define blkid_full_usage "\n\n" \ + "Print UUIDs of all filesystems." #define findfs_trivial_usage \ "LABEL=label or UUID=uuid" @@ -1113,6 +1170,7 @@ USE_FEATURE_FIND_MAXDEPTH( \ "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" \ "\n tests/actions to command line arguments only") \ + "\n -mindepth N Do not act on first N levels" \ "\n -name PATTERN File name (w/o directory name) matches PATTERN" \ "\n -iname PATTERN Case insensitive -name" \ USE_FEATURE_FIND_PATH( \ @@ -1163,6 +1221,14 @@ "$ find / -name passwd\n" \ "/etc/passwd\n" +#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 fold_trivial_usage \ "[-bs] [-w WIDTH] [FILE]" #define fold_full_usage "\n\n" \ @@ -1218,19 +1284,36 @@ "\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" \ + "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] remote-host local-file remote-file" #define ftpget_full_usage "\n\n" \ "Retrieve a remote file via FTP\n" \ "\nOptions:" \ - USE_GETOPT_LONG( \ + USE_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" \ ) \ - SKIP_GETOPT_LONG( \ + SKIP_FEATURE_FTPGETPUT_LONG_OPTIONS( \ "\n -c Continue previous transfer" \ "\n -v Verbose" \ "\n -u Username" \ @@ -1243,13 +1326,13 @@ #define ftpput_full_usage "\n\n" \ "Store a local file on a remote machine via FTP\n" \ "\nOptions:" \ - USE_GETOPT_LONG( \ + USE_FEATURE_FTPGETPUT_LONG_OPTIONS( \ "\n -v,--verbose Verbose" \ "\n -u,--username Username" \ "\n -p,--password Password" \ "\n -P,--port Port number" \ ) \ - SKIP_GETOPT_LONG( \ + SKIP_FEATURE_FTPGETPUT_LONG_OPTIONS( \ "\n -v Verbose" \ "\n -u Username" \ "\n -p Password" \ @@ -1346,6 +1429,7 @@ "eF" \ USE_FEATURE_GREP_EGREP_ALIAS("E") \ USE_FEATURE_GREP_CONTEXT("ABC") \ + USE_EXTRA_COMPAT("z") \ "] PATTERN [FILEs...]" #define grep_full_usage "\n\n" \ "Search for PATTERN in each FILE or standard input\n" \ @@ -1374,6 +1458,8 @@ "\n -A Print NUM lines of trailing context" \ "\n -B Print NUM lines of leading context" \ "\n -C Print NUM lines of output context") \ + USE_EXTRA_COMPAT( \ + "\n -z Input is NUL terminated") \ #define grep_example_usage \ "$ grep root /etc/passwd\n" \ @@ -1420,7 +1506,7 @@ "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" #define halt_trivial_usage \ - "[-d delay] [-n] [-f]" + "[-d delay] [-n] [-f]" USE_FEATURE_WTMP(" [-w]") #define halt_full_usage "\n\n" \ "Halt the system\n" \ "\nOptions:" \ @@ -1572,12 +1658,12 @@ "\n -d STRING URL decode STRING" \ #define hwclock_trivial_usage \ - USE_GETOPT_LONG( \ + USE_FEATURE_HWCLOCK_LONG_OPTIONS( \ "[-r|--show] [-s|--hctosys] [-w|--systohc]" \ " [-l|--localtime] [-u|--utc]" \ " [-f FILE]" \ ) \ - SKIP_GETOPT_LONG( \ + SKIP_FEATURE_HWCLOCK_LONG_OPTIONS( \ "[-r] [-s] [-w] [-l] [-u] [-f FILE]" \ ) #define hwclock_full_usage "\n\n" \ @@ -1598,8 +1684,9 @@ USE_SELINUX( \ "\n -Z Print the security context" \ ) \ - "\n -g Print group ID" \ "\n -u Print user ID" \ + "\n -g Print group ID" \ + "\n -G Print supplementary group IDs" \ "\n -n Print name instead of a number" \ "\n -r Print real user ID instead of effective ID" \ @@ -1827,31 +1914,38 @@ " ::shutdown:/sbin/swapoff -a\n" #define inotifyd_trivial_usage \ - "/user/space/agent dir/or/file/being/watched[:mask] ..." + "PROG FILE1[:MASK] ..." #define inotifyd_full_usage "\n\n" \ - "Spawn userspace agent on filesystem changes." \ - "\nWhen a filesystem event matching the mask occurs" \ - "\non specified file/directory an userspace agent is spawned" \ - "\nwith the parameters:" \ - "\n1. actual event(s)" \ - "\n2. file/directory name" \ - "\n3. name of subfile (if any), in case of watching a directory" \ - "\n" \ + "Run PROG on filesystem changes." \ + "\nWhen a filesystem event matching MASK occurs on FILEn," \ + "\nPROG [] is run." \ + "\nEvents:" \ "\n a File is accessed" \ "\n c File is modified" \ "\n e Metadata changed" \ "\n w Writtable file is closed" \ "\n 0 Unwrittable file is closed" \ "\n r File is opened" \ - "\n m File is moved from X" \ - "\n y File is moved to Y" \ + "\n 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 D Self is deleted" \ - "\n M Self is moved" \ + "\n" \ + "\ninotifyd waits for PROG to exit." \ + "\nWhen x event happens for all FILEs, inotifyd exits" \ +/* 2.6 style insmod has no options and required filename + * (not module name - .ko can't be omitted) */ #define insmod_trivial_usage \ - USE_FEATURE_2_4_MODULES("[OPTION]... ") "MODULE [symbol=value]..." + USE_FEATURE_2_4_MODULES("[OPTION]... MODULE ") \ + SKIP_FEATURE_2_4_MODULES("FILE ") \ + "[symbol=value]..." #define insmod_full_usage "\n\n" \ "Load the specified kernel modules into the kernel" \ USE_FEATURE_2_4_MODULES( "\n" \ @@ -1868,22 +1962,32 @@ "\n -x Do not export externs" \ ) +/* -v, -b, -c are ignored */ #define install_trivial_usage \ - "[-cgmops] [sources] dest|directory" + "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [source] dest|directory" #define install_full_usage "\n\n" \ "Copy files and set attributes\n" \ "\nOptions:" \ - "\n -c Copy the file, default" \ + "\n -c Just copy (default)" \ "\n -d Create directories" \ - "\n -g Set group ownership" \ - "\n -m Set permissions" \ - "\n -o Set ownership" \ + "\n -D Create leading target directories" \ + "\n -s Strip symbol table" \ "\n -p Preserve date" \ - "\n -s Strip symbol tables" \ + "\n -o USER Set ownership" \ + "\n -g GRP Set group ownership" \ + "\n -m MODE Set permissions" \ USE_SELINUX( \ - "\n -Z Set security context of copy" \ + "\n -Z Set security context" \ ) +#define ionice_trivial_usage \ + "[-c 1-3] [-n 0-7] [-p PID] [PROG]" +#define ionice_full_usage "\n\n" \ + "Change I/O scheduling class and priority\n" \ + "\nOptions:" \ + "\n -c Class. 1:realtime 2:best-effort 3:idle" \ + "\n -n Priority" \ + /* would need to make the " | " optional depending on more than one selected: */ #define ip_trivial_usage \ "[OPTIONS] {" \ @@ -1985,7 +2089,8 @@ " [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]" \ + " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO]\n" \ + " [metric METRIC]" \ #define iprule_trivial_usage \ "{[list | add | del] RULE}" @@ -2009,7 +2114,7 @@ " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" \ #define kbd_mode_trivial_usage \ - "[-a|k|s|u]" + "[-a|k|s|u] [-C TTY]" #define kbd_mode_full_usage "\n\n" \ "Report or set the keyboard mode\n" \ "\nOptions set mode:" \ @@ -2017,13 +2122,15 @@ "\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] [-signal] process-id..." + "[-l] [-SIG] PID..." #define kill_full_usage "\n\n" \ - "Send a signal (default is TERM) to the specified process(es)\n" \ + "Send a signal (default is 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" \ @@ -2036,22 +2143,25 @@ "$ kill 252\n" #define killall_trivial_usage \ - "[-l] [-q] [-signal] process-name..." + "[-l] [-q] [-SIG] process-name..." #define killall_full_usage "\n\n" \ - "Send a signal (default is TERM) to the specified process(es)\n" \ + "Send a signal (default is 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 Do not complain if no processes were killed" \ #define killall_example_usage \ "$ killall apache\n" #define killall5_trivial_usage \ - "[-l] [-signal]" + "[-l] [-SIG] [-o PID]..." #define killall5_full_usage "\n\n" \ "Send a signal (default is TERM) to all processes outside current session\n" \ "\nOptions:" \ "\n -l List all signal names and numbers" \ + "\n -o PID Do not signal this PID" \ +/* "\n -s SIG Yet another way of specifying SIG" */ \ #define klogd_trivial_usage \ "[-c N] [-n]" @@ -2071,7 +2181,7 @@ "5\n" #define less_trivial_usage \ - "[-EMNmh~?] [FILE...]" + "[-EMNmh~I?] [FILE...]" #define less_full_usage "\n\n" \ "View a file or list of files. The position within files can be\n" \ "changed, and files can be manipulated in various ways.\n" \ @@ -2080,6 +2190,7 @@ "\n -M,-m Display a status line containing the line numbers" \ "\n and percentage through the file" \ "\n -N Prefix line numbers to each line" \ + "\n -I Ignore case in all searches" \ "\n -~ Suppress ~s displayed past the end of the file" \ #define linux32_trivial_usage NOUSAGE_STR @@ -2115,20 +2226,23 @@ "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" #define load_policy_trivial_usage NOUSAGE_STR - #define load_policy_full_usage "" #define loadfont_trivial_usage \ "< font" #define loadfont_full_usage "\n\n" \ - "Load a console font from standard input" + "Load a console font from standard input" \ +/* "\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 standard input" + "Load a binary keyboard translation table from standard input\n" \ +/* "\n -C TTY Affect TTY instead of /dev/tty" */ \ + #define loadkmap_example_usage \ "$ loadkmap < /etc/i18n/lang-keymap\n" @@ -2229,21 +2343,21 @@ #define ls_full_usage "\n\n" \ "List directory contents\n" \ "\nOptions:" \ - "\n -1 List files in a single column" \ - "\n -A Do not list implied . and .." \ - "\n -a Do not hide entries starting with ." \ - "\n -C List entries by columns" \ + "\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" \ USE_FEATURE_LS_TIMESTAMPS( \ - "\n -c With -l: show ctime") \ + "\n -c With -l: sort by ctime") \ USE_FEATURE_LS_COLOR( \ "\n --color[={always,never,auto}] Control coloring") \ "\n -d List directory entries instead of contents" \ USE_FEATURE_LS_TIMESTAMPS( \ - "\n -e List both full date and full time") \ + "\n -e List full date and time") \ USE_FEATURE_LS_FILETYPES( \ "\n -F Append indicator (one of */=@|) to entries") \ - "\n -i List the i-node for each file" \ - "\n -l Use a long listing format" \ + "\n -i List inode numbers" \ + "\n -l Long listing format" \ "\n -n List numeric UIDs and GIDs instead of names" \ USE_FEATURE_LS_FILETYPES( \ "\n -p Append indicator (one of /=@|) to entries") \ @@ -2252,31 +2366,31 @@ USE_FEATURE_LS_RECURSIVE( \ "\n -R List subdirectories recursively") \ USE_FEATURE_LS_SORTFILES( \ - "\n -r Sort the listing in reverse order") \ + "\n -r Sort in reverse order") \ USE_FEATURE_LS_SORTFILES( \ - "\n -S Sort the listing by file size") \ + "\n -S Sort by file size") \ "\n -s List the size of each file, in blocks" \ USE_FEATURE_AUTOWIDTH( \ - "\n -T NUM Assume Tabstop every NUM columns") \ + "\n -T NUM Assume tabstop every NUM columns") \ USE_FEATURE_LS_TIMESTAMPS( \ - "\n -t With -l: show modification time") \ + "\n -t With -l: sort by modification time") \ USE_FEATURE_LS_TIMESTAMPS( \ - "\n -u With -l: show access time") \ + "\n -u With -l: sort by access time") \ USE_FEATURE_LS_SORTFILES( \ - "\n -v Sort the listing by version") \ + "\n -v Sort by version") \ USE_FEATURE_AUTOWIDTH( \ "\n -w NUM Assume the terminal is NUM columns wide") \ - "\n -x List entries by lines instead of by columns" \ + "\n -x List by lines" \ USE_FEATURE_LS_SORTFILES( \ - "\n -X Sort the listing by extension") \ + "\n -X Sort by extension") \ USE_FEATURE_HUMAN_READABLE( \ - "\n -h Print sizes in human readable format (e.g., 1K 243M 2G)") \ + "\n -h List sizes in human readable format (1K 243M 2G)") \ USE_SELINUX( \ - "\n -k Print security context") \ + "\n -k List security context") \ USE_SELINUX( \ - "\n -K Print security context in long format") \ + "\n -K List security context in long format") \ USE_SELINUX( \ - "\n -Z Print security context and permission") \ + "\n -Z List security context and permission") \ #define lsattr_trivial_usage \ "[-Radlv] [files...]" @@ -2286,7 +2400,7 @@ "\n -R Recursively list subdirectories" \ "\n -a Do not hide entries starting with ." \ "\n -d List directory entries instead of contents" \ - "\n -l Print long flag names" \ + "\n -l List long flag names" \ "\n -v List the file's version/generation number" \ #define lsmod_trivial_usage \ @@ -2352,6 +2466,16 @@ "/dev/hda[0-15]\n" #endif +#define makemime_trivial_usage \ + "[OPTION]... [FILE]..." +#define makemime_full_usage "\n\n" \ + "Create MIME-encoded message\n" \ + "\nOptions:" \ + "\n -C Charset" \ + "\n -e Transfer encoding. Ignored. base64 is assumed" \ + "\n" \ + "\nOther options are silently ignored." \ + #define man_trivial_usage \ "[OPTION]... [MANPAGE]..." #define man_full_usage "\n\n" \ @@ -2376,9 +2500,10 @@ "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \ USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ "\nOptions:" \ - "\n -c Check MD5 sums against given list" \ + "\n -c Check sums against given list" \ "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted MD5 checksum lines") \ + "\n -w Warn about improperly formatted checksum lines" \ + ) #define md5sum_example_usage \ "$ md5sum < busybox\n" \ @@ -2390,13 +2515,55 @@ "busybox: OK\n" \ "^D\n" +#define sha1sum_trivial_usage \ + "[OPTION] [FILEs...]" \ + USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum [OPTION] -c [FILE]") +#define sha1sum_full_usage "\n\n" \ + "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \ + USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ + "\nOptions:" \ + "\n -c Check 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 \ + "[OPTION] [FILEs...]" \ + USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha256sum [OPTION] -c [FILE]") +#define sha256sum_full_usage "\n\n" \ + "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \ + USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ + "\nOptions:" \ + "\n -c Check 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 \ + "[OPTION] [FILEs...]" \ + USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha512sum [OPTION] -c [FILE]") +#define sha512sum_full_usage "\n\n" \ + "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \ + USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ + "\nOptions:" \ + "\n -c Check 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" \ - "Called with no options (via hotplug) it uses environment variables\n" \ - "to determine which device to add/remove." + "It can be run by kernel as a hotplug helper. To activate it:\n" \ + " echo /bin/mdev >/proc/sys/kernel/hotplug\n" \ + USE_FEATURE_MDEV_CONF( \ + "It uses /etc/mdev.conf with lines\n" \ + "[-]DEVNAME UID:GID PERM" \ + USE_FEATURE_MDEV_RENAME(" [>|=PATH]") \ + USE_FEATURE_MDEV_EXEC(" [@|$|*COMMAND]") \ + ) \ #define mdev_notes_usage "" \ USE_FEATURE_MDEV_CONFIG( \ @@ -2507,6 +2674,22 @@ "\n -l FILENAME Read bad blocks list from FILENAME" \ "\n -v Make version 2 filesystem" \ +#define mkfs_vfat_trivial_usage \ + "[-v] [-n LABEL] FILE_OR_DEVICE [SIZE_IN_KB]" +/* 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 \ "[OPTIONS] NAME TYPE MAJOR MINOR" #define mknod_full_usage "\n\n" \ @@ -2562,19 +2745,24 @@ "[-knqrsv] MODULE [symbol=value...]" #define modprobe_full_usage "\n\n" \ "Options:" \ + USE_FEATURE_2_4_MODULES( \ "\n -k Make module autoclean-able" \ + ) \ "\n -n Dry run" \ "\n -q Quiet" \ "\n -r Remove module (stacks) or do autoclean" \ "\n -s Report via syslog instead of stderr" \ "\n -v Verbose" \ + USE_FEATURE_MODPROBE_BLACKLIST( \ + "\n -b Apply blacklist to module names too" \ + ) #define modprobe_notes_usage \ "modprobe can (un)load a stack of modules, passing each module options (when\n" \ "loading). modprobe uses a configuration file to determine what option(s) to\n" \ "pass each module it loads.\n" \ "\n" \ -"The configuration file is searched (in order) amongst:\n" \ +"The configuration file is searched (in this order):\n" \ "\n" \ " /etc/modprobe.conf (2.6 only)\n" \ " /etc/modules.conf\n" \ @@ -2638,45 +2826,50 @@ "$ dmesg | more\n" #define mount_trivial_usage \ - "[flags] DEVICE NODE [-o options,more-options]" + "[flags] DEVICE NODE [-o OPT,OPT]" #define mount_full_usage "\n\n" \ "Mount a filesystem. Filesystem autodetection requires /proc be mounted.\n" \ "\nOptions:" \ "\n -a Mount all filesystems in fstab" \ USE_FEATURE_MOUNT_FAKE( \ - "\n -f "USE_FEATURE_MTAB_SUPPORT("Update /etc/mtab, but ")"don't mount" \ + USE_FEATURE_MTAB_SUPPORT( \ + "\n -f Update /etc/mtab, but don't mount" \ + ) \ + SKIP_FEATURE_MTAB_SUPPORT( \ + "\n -f Dry run" \ + ) \ ) \ USE_FEATURE_MTAB_SUPPORT( \ "\n -n Don't update /etc/mtab" \ ) \ "\n -r Read-only mount" \ - "\n -t fs-type Filesystem type" \ "\n -w Read-write mount (default)" \ - "\n" \ - "-o option:\n" \ + "\n -t FSTYPE Filesystem type" \ + "\n -O OPT Mount only filesystems with option OPT (-a only)" \ + "\n-o OPT:" \ USE_FEATURE_MOUNT_LOOP( \ - " loop Ignored (loop devices are autodetected)\n" \ + "\n loop Ignored (loop devices are autodetected)" \ ) \ USE_FEATURE_MOUNT_FLAGS( \ - " [a]sync Writes are asynchronous / synchronous\n" \ - " [no]atime Disable / enable updates to inode access times\n" \ - " [no]diratime Disable / enable atime updates to directories\n" \ - " [no]relatime Disable / enable atime updates relative to modification time\n" \ - " [no]dev Allow use of special device files / disallow them\n" \ - " [no]exec Allow use of executable files / disallow them\n" \ - " [no]suid Allow set-user-id-root programs / disallow them\n" \ - " [r]shared Convert [recursively] to a shared subtree\n" \ - " [r]slave Convert [recursively] to a slave subtree\n" \ - " [r]private Convert [recursively] to a private subtree\n" \ - " [un]bindable Make mount point [un]able to be bind mounted\n" \ - " bind Bind a directory to an additional location\n" \ - " move Relocate an existing mount point\n" \ + "\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 directory to an additional location" \ + "\n move Relocate an existing mount point" \ ) \ - " remount Remount a mounted filesystem, changing its flags\n" \ - " ro/rw Mount for read-only / read-write\n" \ - "\n" \ - "There are EVEN MORE flags that are specific to each filesystem\n" \ - "You'll have to see the written documentation for those filesystems" \ + "\n remount Remount a mounted filesystem, changing its flags" \ + "\n ro/rw Read-only/read-write mount" \ + "\n" \ + "\nThere are EVEN MORE flags that are specific to each filesystem" \ + "\nYou'll have to see the written documentation for those filesystems" \ #define mount_example_usage \ "$ mount\n" \ @@ -2690,12 +2883,13 @@ "Returns 0 for success, number of failed mounts for -a, or errno for one mount." #define mountpoint_trivial_usage \ - "[-q] <[-d] DIR | -x DEVICE>" + "[-q] <[-dn] DIR | -x DEVICE>" #define mountpoint_full_usage "\n\n" \ - "mountpoint checks if the directory is a mountpoint\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 \ @@ -3064,6 +3258,33 @@ "\n -v Negate the matching" \ "\n -x Match whole name (not substring)" \ +#define popmaildir_trivial_usage \ + "[OPTIONS] Maildir [connection-helper ...]" +#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 with RETR" \ + "\n -k Keep retrieved messages on the server" \ + "\n -t timeout Set network timeout" \ + USE_FEATURE_POPMAILDIR_DELIVERY( \ + "\n -F \"program arg1 arg2 ...\" Filter by program. May be multiple" \ + "\n -M \"program arg1 arg2 ...\" Deliver by program" \ + ) \ + "\n -R size Remove old messages on the server >= size (in bytes). Ignored" \ + "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" \ + "\n -L size Do not retrieve new messages >= size (in bytes). Ignored" \ + "\n -H lines Type specified number of 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" @@ -3442,31 +3687,39 @@ #define selinuxenabled_full_usage "" #define sendmail_trivial_usage \ - "[-w timeout] [-H [user:pass@]server[:port]] [-S]\n" \ - "[-c charset] [-N type] [-i] [-s subject] [-a attach]... [-t] [-f sender] [rcpt]..." + "[OPTIONS] [rcpt]..." #define sendmail_full_usage "\n\n" \ "Send an email\n" \ - "\nOptions:" \ - "\n -w timeout Network timeout" \ - "\n -H [user:pass@]server[:port] Server" \ - "\n -S Use openssl connection helper for secure servers" \ - "\n -c charset Assume charset for body and subject (utf-8)" \ - "\n -N type Request delivery notification. Type is ignored" \ - "\n -i Ignore single dots in mail body. Implied" \ - "\n -s subject Subject" \ - "\n -a file File to attach. May be multiple" \ - "\n -t Read recipients and subject from body" \ - "\n -f sender Sender" \ + "\nStandard options:" \ + "\n -t Read recipients from message body, add them to those on cmdline" \ + "\n -f sender Sender. REQUIRED!" \ + "\n -o options various options. -oi IMPLIED! others are 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" \ #define seq_trivial_usage \ - "[first [increment]] last" + "[-w] [-s SEP] [FIRST [INC]] LAST" #define seq_full_usage "\n\n" \ - "Print numbers from FIRST to LAST, in steps of INCREMENT.\n" \ - "FIRST, INCREMENT default to 1\n" \ - "\nArguments:" \ - "\n LAST" \ - "\n FIRST LAST" \ - "\n FIRST INCREMENT LAST" \ + "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]" @@ -3510,11 +3763,13 @@ "\n -W Display warnings about entries that had no matching files" \ #define setfont_trivial_usage \ - "[-m mapfile] font" + "FONT [-m MAPFILE] [-C TTY]" #define setfont_full_usage "\n\n" \ "Load a console font\n" \ "\nOptions:" \ - "\n -m mapfile Load console screen map from mapfile" + "\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" @@ -3564,18 +3819,6 @@ "\n -f file Read from file instead of /var/log/wtmp" \ ) -#define sha1sum_trivial_usage \ - "[OPTION] [FILEs...]" \ - USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum [OPTION] -c [FILE]") -#define sha1sum_full_usage "\n\n" \ - "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \ - USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check SHA1 sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted SHA1 checksum lines" \ - ) - #define showkey_trivial_usage \ "[-a | -k | -s]" #define showkey_full_usage "\n\n" \ @@ -3679,7 +3922,7 @@ "Search for matching processes, and then\n" \ "-K: stop all matching processes.\n" \ "-S: start a process unless a matching process is found.\n" \ - USE_GETOPT_LONG( \ + USE_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" \ @@ -3703,11 +3946,11 @@ "\nOther:" \ USE_FEATURE_START_STOP_DAEMON_FANCY( \ "\n -o,--oknodo Exit with status 0 if nothing is done" \ - "\n -q,--quiet Quiet" \ - ) \ "\n -v,--verbose Verbose" \ ) \ - SKIP_GETOPT_LONG( \ + "\n -q,--quiet Quiet" \ + ) \ + SKIP_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" \ @@ -3731,10 +3974,10 @@ "\nOther:" \ USE_FEATURE_START_STOP_DAEMON_FANCY( \ "\n -o Exit with status 0 if nothing is done" \ - "\n -q Quiet" \ - ) \ "\n -v Verbose" \ ) \ + "\n -q Quiet" \ + ) \ #define stat_trivial_usage \ "[OPTION] FILE..." @@ -4094,6 +4337,26 @@ "$ 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 |"USE_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \ + /* "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ \ + "\t[ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \ + "\tQDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" \ + "qdisc show [ dev STRING ]"USE_FEATURE_TC_INGRESS(" [ingress]")"\n" \ + "class [ classid CLASSID ] [ root | parent CLASSID ]\n" \ + "\t[ [ 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" */ \ + "\t[ root | classid CLASSID ] [ handle FILTERID ]\n" \ + "\t[ [ 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: */ @@ -4152,6 +4415,12 @@ "[-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" \ @@ -4165,8 +4434,14 @@ "\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] [-n COUNT] [-d SECONDS]" + "[-b] [-nCOUNT] [-dSECONDS]" #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" \ @@ -4250,6 +4525,23 @@ #define ttysize_full_usage "\n\n" \ "Print dimension(s) of standard input's terminal, on error return 80x25" +#define tunctl_trivial_usage \ + "[-f device] ([-t name] | -d name)" USE_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") +#define tunctl_full_usage "\n\n" \ + "Create or delete tun interfaces" \ + "\nOptions:" \ + "\n -f name tun device (/dev/net/tun)" \ + "\n -t name Create iface 'name'" \ + "\n -d name Delete iface 'name'" \ +USE_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 tune2fs_trivial_usage \ "[-c max-mounts-count] [-e errors-behavior] [-g group] " \ "[-i interval[d|m|w]] [-j] [-J journal-options] [-l] [-s sparse-flag] " \ @@ -4272,7 +4564,7 @@ "\n -C,--clientid-none Suppress default client identifier" \ "\n -p,--pidfile=file Create pidfile" \ "\n -r,--request=IP IP address to request" \ - "\n -s,--script=file Run file at DHCP events (default "CONFIG_DHCPC_DEFAULT_SCRIPT")" \ + "\n -s,--script=file Run file at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" \ "\n -t,--retries=N Send up to N request packets" \ "\n -T,--timeout=N Try to get a lease for N seconds (default 3)" \ "\n -A,--tryagain=N Wait N seconds (default 20) after failure" \ @@ -4301,7 +4593,7 @@ "\n -C Suppress default client identifier" \ "\n -p file Create pidfile" \ "\n -r IP IP address to request" \ - "\n -s file Run file at DHCP events (default "CONFIG_DHCPC_DEFAULT_SCRIPT")" \ + "\n -s file Run file at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" \ "\n -t N Send up to N request packets" \ "\n -T N Try to get a lease for N seconds (default 3)" \ "\n -A N Wait N seconds (default 20) after failure" \ @@ -4524,14 +4816,15 @@ "Mon Dec 17 10:31:44 GMT 2000" #define watchdog_trivial_usage \ - "[-t N[ms]] [-F] DEV" + "[-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 Timer period (default 30)" \ + "\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 -t 500ms to specify period in milliseconds" \ + "\nUse 500ms to specify period in milliseconds" \ #define wc_trivial_usage \ "[OPTION]... [FILE]..." @@ -4549,12 +4842,12 @@ " 31 46 1365 /etc/passwd\n" #define wget_trivial_usage \ - USE_GETOPT_LONG( \ + USE_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" \ " [-U|--user-agent agent] url" \ ) \ - SKIP_GETOPT_LONG( \ + SKIP_FEATURE_WGET_LONG_OPTIONS( \ "[-csq] [-O file] [-Y on/off] [-P DIR] [-U agent] url" \ ) #define wget_full_usage "\n\n" \ @@ -4599,7 +4892,7 @@ USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( \ "\n -0 Input is separated by NUL characters") \ "\n -t Print the command on stderr before execution" \ - "\n -e[STR] STR stops input processing (default _)" \ + "\n -e[STR] STR stops input processing" \ "\n -n N Pass no more than N args to COMMAND" \ "\n -s N Pass command line of no more than N bytes" \ USE_FEATURE_XARGS_SUPPORT_TERMOPT( \ @@ -4625,8 +4918,12 @@ "Manage a ZeroConf IPv4 link-local address\n" \ "\nOptions:" \ "\n -f Run in foreground" \ - "\n -q Quit after address (no daemon)" \ + "\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 /* __BB_USAGE_H__ */ + +#endif diff --git a/release/src/router/busybox/include/volume_id.h b/release/src/router/busybox/include/volume_id.h index 99cb11ff60..bba32c0baf 100644 --- a/release/src/router/busybox/include/volume_id.h +++ b/release/src/router/busybox/include/volume_id.h @@ -20,3 +20,4 @@ char *get_devname_from_label(const char *spec); char *get_devname_from_uuid(const char *spec); +void display_uuid_cache(void); diff --git a/release/src/router/busybox/include/xatonum.h b/release/src/router/busybox/include/xatonum.h index 86a3472d96..ee816efb40 100644 --- a/release/src/router/busybox/include/xatonum.h +++ b/release/src/router/busybox/include/xatonum.h @@ -7,9 +7,7 @@ * Licensed under GPLv2, see file LICENSE in this tarball for details. */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* Provides extern declarations of functions */ #define DECLARE_STR_CONV(type, T, UT) \ @@ -171,6 +169,4 @@ uint32_t bb_strtou32(const char *arg, char **endp, int base) double bb_strtod(const char *arg, char **endp) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY diff --git a/release/src/router/busybox/include/xregex.h b/release/src/router/busybox/include/xregex.h index 90cf124eea..61658ed859 100644 --- a/release/src/router/busybox/include/xregex.h +++ b/release/src/router/busybox/include/xregex.h @@ -8,20 +8,16 @@ * * Licensed under GPLv2 or later, see file License in this tarball for details. */ -#ifndef __BB_REGEX__ -#define __BB_REGEX__ +#ifndef BB_REGEX_H +#define BB_REGEX_H 1 #include -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN char* regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags) FAST_FUNC; void xregcomp(regex_t *preg, const char *regex, int cflags) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/init/Config.in b/release/src/router/busybox/init/Config.in index c26c4c5e6b..1a1be4a9b2 100644 --- a/release/src/router/busybox/init/Config.in +++ b/release/src/router/busybox/init/Config.in @@ -12,14 +12,6 @@ config INIT help init is the first program run when the system boots. -config DEBUG_INIT - bool "Debugging aid" - default n - depends on INIT - help - Turn this on to disable all the dangerous - rebooting stuff when debugging. - config FEATURE_USE_INITTAB bool "Support reading an inittab file" default y @@ -40,11 +32,12 @@ config FEATURE_KILL_DELAY int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED range 0 1024 default 0 + depends on FEATURE_KILL_REMOVED help With nonzero setting, init sends TERM, forks, child waits N seconds, sends KILL and exits. Setting it too high is unwise - (child will hang around for too long and can actually kill - wrong process!) + (child will hang around for too long and could actually kill + the wrong process!) config FEATURE_INIT_SCTTY bool "Run commands with leading dash with controlling tty" @@ -83,8 +76,6 @@ config FEATURE_INIT_COREDUMPS core file sizes. If this option is disabled, processes will not generate any core files. - - config FEATURE_INITRD bool "Support running init from within an initrd (not initramfs)" default y diff --git a/release/src/router/busybox/init/halt.c b/release/src/router/busybox/init/halt.c index 8c1f30b08c..3a23ecabb5 100644 --- a/release/src/router/busybox/init/halt.c +++ b/release/src/router/busybox/init/halt.c @@ -13,60 +13,69 @@ #if ENABLE_FEATURE_WTMP #include #include + +static void write_wtmp(void) +{ + struct utmp utmp; + struct utsname uts; + if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { + close(creat(bb_path_wtmp_file, 0664)); + } + memset(&utmp, 0, sizeof(utmp)); + utmp.ut_tv.tv_sec = time(NULL); + safe_strncpy(utmp.ut_user, "shutdown", UT_NAMESIZE); + utmp.ut_type = RUN_LVL; + safe_strncpy(utmp.ut_id, "~~", sizeof(utmp.ut_id)); + safe_strncpy(utmp.ut_line, "~~", UT_LINESIZE); + if (uname(&uts) == 0) + safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host)); + updwtmp(bb_path_wtmp_file, &utmp); + +} +#else +#define write_wtmp() ((void)0) +#endif + +#ifndef RB_HALT_SYSTEM +#define RB_HALT_SYSTEM RB_HALT +#endif + +#ifndef RB_POWER_OFF +#define RB_POWER_OFF RB_POWERDOWN #endif int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int halt_main(int argc UNUSED_PARAM, char **argv) { static const int magic[] = { -#ifdef RB_HALT_SYSTEM -RB_HALT_SYSTEM, -#elif defined RB_HALT -RB_HALT, -#endif -#ifdef RB_POWER_OFF -RB_POWER_OFF, -#elif defined RB_POWERDOWN -RB_POWERDOWN, -#endif -RB_AUTOBOOT + RB_HALT_SYSTEM, + RB_POWER_OFF, + RB_AUTOBOOT }; static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM }; int delay = 0; int which, flags, rc; -#if ENABLE_FEATURE_WTMP - struct utmp utmp; - struct utsname uts; -#endif /* Figure out which applet we're running */ - for (which = 0; "hpr"[which] != *applet_name; which++) + for (which = 0; "hpr"[which] != applet_name[0]; which++) continue; /* Parse and handle arguments */ opt_complementary = "d+"; /* -d N */ - flags = getopt32(argv, "d:nfw", &delay); + /* We support -w even if !ENABLE_FEATURE_WTMP, + * in order to not break scripts. + * -i (shut down network interfaces) is ignored. + */ + flags = getopt32(argv, "d:nfwi", &delay); sleep(delay); -#if ENABLE_FEATURE_WTMP - if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { - close(creat(bb_path_wtmp_file, 0664)); - } - memset(&utmp, 0, sizeof(utmp)); - utmp.ut_tv.tv_sec = time(NULL); - safe_strncpy(utmp.ut_user, "shutdown", UT_NAMESIZE); - utmp.ut_type = RUN_LVL; - safe_strncpy(utmp.ut_id, "~~", sizeof(utmp.ut_id)); - safe_strncpy(utmp.ut_line, "~~", UT_LINESIZE); - if (uname(&uts) == 0) - safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host)); - updwtmp(bb_path_wtmp_file, &utmp); -#endif /* !ENABLE_FEATURE_WTMP */ + write_wtmp(); if (flags & 8) /* -w */ return EXIT_SUCCESS; + if (!(flags & 2)) /* no -n */ sync(); @@ -82,12 +91,14 @@ RB_AUTOBOOT if (ENABLE_FEATURE_CLEAN_UP) free(pidlist); } - if (rc) + if (rc) { rc = kill(1, signals[which]); - } else + } + } else { rc = reboot(magic[which]); + } if (rc) - bb_error_msg("no"); + bb_perror_nomsg_and_die(); return rc; } diff --git a/release/src/router/busybox/init/init.c b/release/src/router/busybox/init/init.c index e02773cc0d..ce264283a1 100644 --- a/release/src/router/busybox/init/init.c +++ b/release/src/router/busybox/init/init.c @@ -13,37 +13,64 @@ #include #include #include +#include +#include -#define COMMAND_SIZE 256 -#define CONSOLE_NAME_SIZE 32 -#define MAXENV 16 /* Number of env. vars */ -/* - * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called - * before processes are spawned to set core file size as unlimited. - * This is for debugging only. Don't use this is production, unless - * you want core dumps lying about.... - */ -#define CORE_ENABLE_FLAG_FILE "/.init_enable_core" -#include +/* Was a CONFIG_xxx option. A lot of people were building + * not fully functional init by switching it on! */ +#define DEBUG_INIT 0 -#define INITTAB "/etc/inittab" /* inittab file location */ +#define COMMAND_SIZE 256 +#define CONSOLE_NAME_SIZE 32 + +/* Default sysinit script. */ #ifndef INIT_SCRIPT -#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ +#define INIT_SCRIPT "/etc/init.d/rcS" #endif -/* Allowed init action types */ +/* Each type of actions can appear many times. They will be + * handled in order. RESTART is an exception, only 1st is used. + */ +/* Start these actions first and wait for completion */ #define SYSINIT 0x01 -#define RESPAWN 0x02 -/* like respawn, but wait for to be pressed on tty: */ -#define ASKFIRST 0x04 -#define WAIT 0x08 -#define ONCE 0x10 +/* Start these after SYSINIT and wait for completion */ +#define WAIT 0x02 +/* Start these after WAIT and *dont* wait for completion */ +#define ONCE 0x04 +/* + * NB: while SYSINIT/WAIT/ONCE are being processed, + * SIGHUP ("reread /etc/inittab") will be ignored. + * Rationale: it would be ambiguous whether SYSINIT/WAIT/ONCE + * need to be rerun or not. + */ +/* Start these after ONCE are started, restart on exit */ +#define RESPAWN 0x08 +/* Like RESPAWN, but wait for to be pressed on tty */ +#define ASKFIRST 0x10 +/* + * Start these on SIGINT, and wait for completion. + * Then go back to respawning RESPAWN and ASKFIRST actions. + * NB: kernel sends SIGINT to us if Ctrl-Alt-Del was pressed. + */ #define CTRLALTDEL 0x20 +/* + * Start these before killing all processes in preparation for + * running RESTART actions or doing low-level halt/reboot/poweroff + * (initiated by SIGUSR1/SIGTERM/SIGUSR2). + * Wait for completion before proceeding. + */ #define SHUTDOWN 0x40 +/* + * exec() on SIGQUIT. SHUTDOWN actions are started and waited for, + * then all processes are killed, then init exec's 1st RESTART action, + * replacing itself by it. If no RESTART action specified, + * SIGQUIT has no effect. + */ #define RESTART 0x80 -/* Set up a linked list of init_actions, to be read from inittab */ + +/* A linked list of init_actions, to be read from inittab */ struct init_action { struct init_action *next; pid_t pid; @@ -52,22 +79,14 @@ struct init_action { char command[COMMAND_SIZE]; }; -/* Static variables */ static struct init_action *init_action_list = NULL; static const char *log_console = VC_5; -static sig_atomic_t got_cont = 0; enum { L_LOG = 0x1, L_CONSOLE = 0x2, - -#if ENABLE_FEATURE_EXTRA_QUIET - MAYBE_CONSOLE = 0x0, -#else - MAYBE_CONSOLE = L_CONSOLE, -#endif - + MAYBE_CONSOLE = L_CONSOLE * !ENABLE_FEATURE_EXTRA_QUIET, #ifndef RB_HALT_SYSTEM RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */ RB_ENABLE_CAD = 0x89abcdef, @@ -77,68 +96,41 @@ enum { #endif }; -static const char *const environment[] = { - "HOME=/", - bb_PATH_root_path, - "SHELL=/bin/sh", - "USER=root", - NULL -}; - -/* Function prototypes */ -static void halt_reboot_pwoff(int sig) NORETURN; - -static void waitfor(pid_t pid) -{ - /* waitfor(run(x)): protect against failed fork inside run() */ - if (pid <= 0) - return; - - /* Wait for any child (prevent zombies from exiting orphaned processes) - * but exit the loop only when specified one has exited. */ - while (wait(NULL) != pid) - continue; -} - -static void loop_forever(void) NORETURN; -static void loop_forever(void) -{ - while (1) - sleep(1); -} - /* Print a message to the specified device. * "where" may be bitwise-or'd from L_LOG | L_CONSOLE * NB: careful, we can be called after vfork! */ -#define messageD(...) do { if (ENABLE_DEBUG_INIT) message(__VA_ARGS__); } while (0) +#define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0) static void message(int where, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); static void message(int where, const char *fmt, ...) { - static int log_fd = -1; va_list arguments; - int l; + unsigned l; char msg[128]; msg[0] = '\r'; va_start(arguments, fmt); - vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); + l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); + if (l > sizeof(msg) - 1) + l = sizeof(msg) - 1; va_end(arguments); - msg[sizeof(msg) - 2] = '\0'; - l = strlen(msg); - if (ENABLE_FEATURE_INIT_SYSLOG) { +#if ENABLE_FEATURE_INIT_SYSLOG + msg[l] = '\0'; + if (where & L_LOG) { /* Log the message to syslogd */ - if (where & L_LOG) { - /* don't print out "\r" */ - openlog(applet_name, 0, LOG_DAEMON); - syslog(LOG_INFO, "init: %s", msg + 1); - closelog(); - } - msg[l++] = '\n'; - msg[l] = '\0'; - } else { + openlog("init", 0, LOG_DAEMON); + /* don't print "\r" */ + syslog(LOG_INFO, "%s", msg + 1); + closelog(); + } + msg[l++] = '\n'; + msg[l] = '\0'; +#else + { + static int log_fd = -1; + msg[l++] = '\n'; msg[l] = '\0'; /* Take full control of the log tty, and never close it. @@ -162,6 +154,7 @@ static void message(int where, const char *fmt, ...) return; /* don't print dup messages */ } } +#endif if (where & L_CONSOLE) { /* Send console messages to console so people will see them. */ @@ -169,33 +162,9 @@ static void message(int where, const char *fmt, ...) } } -/* From */ -struct serial_struct { - int type; - int line; - unsigned int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char io_type; - char reserved_char[1]; - int hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - unsigned char *iomem_base; - unsigned short iomem_reg_shift; - unsigned int port_high; - unsigned long iomap_base; /* cookie passed into ioremap */ - int reserved[1]; - /* Paranoia (imagine 64bit kernel overwriting 32bit userspace stack) */ - uint32_t bbox_reserved[16]; -}; static void console_init(void) { - struct serial_struct sr; + int vtno; char *s; s = getenv("CONSOLE"); @@ -208,16 +177,20 @@ static void console_init(void) dup2(fd, STDOUT_FILENO); xmove_fd(fd, STDERR_FILENO); } - messageD(L_LOG, "console='%s'", s); + dbg_message(L_LOG, "console='%s'", s); } else { /* Make sure fd 0,1,2 are not closed * (so that they won't be used by future opens) */ bb_sanitize_stdio(); +// Users report problems +// /* Make sure init can't be blocked by writing to stderr */ +// fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK); } s = getenv("TERM"); - if (ioctl(STDIN_FILENO, TIOCGSERIAL, &sr) == 0) { - /* Force the TERM setting to vt102 for serial console + if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) { + /* Not a linux terminal, probably serial console. + * Force the TERM setting to vt102 * if TERM is set to linux (the default) */ if (!s || strcmp(s, "linux") == 0) putenv((char*)"TERM=vt102"); @@ -262,34 +235,30 @@ static void set_sane_term(void) tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; - tcsetattr(STDIN_FILENO, TCSANOW, &tty); + tcsetattr_stdin_TCSANOW(&tty); } /* Open the new terminal device. * NB: careful, we can be called after vfork! */ -static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) +static int open_stdio_to_tty(const char* tty_name) { /* empty tty_name means "use init's tty", else... */ if (tty_name[0]) { int fd; + close(STDIN_FILENO); /* fd can be only < 0 or 0: */ fd = device_open(tty_name, O_RDWR); if (fd) { message(L_LOG | L_CONSOLE, "can't open %s: %s", tty_name, strerror(errno)); - if (exit_on_failure) - _exit(EXIT_FAILURE); - if (ENABLE_DEBUG_INIT) - _exit(2); - /* NB: we don't reach this if we were called after vfork. - * Thus halt_reboot_pwoff() itself need not be vfork-safe. */ - halt_reboot_pwoff(SIGUSR1); /* halt the system */ + return 0; /* failure */ } dup2(STDIN_FILENO, STDOUT_FILENO); dup2(STDIN_FILENO, STDERR_FILENO); } set_sane_term(); + return 1; /* success */ } /* Wrapper around exec: @@ -344,22 +313,19 @@ static void init_exec(const char *command) static pid_t run(const struct init_action *a) { pid_t pid; - sigset_t nmask, omask; - /* Block sigchild while forking (why?) */ - sigemptyset(&nmask); - sigaddset(&nmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &nmask, &omask); + /* Careful: don't be affected by a signal in vforked child */ + sigprocmask_allsigs(SIG_BLOCK); if (BB_MMU && (a->action_type & ASKFIRST)) pid = fork(); else pid = vfork(); - sigprocmask(SIG_SETMASK, &omask, NULL); - if (pid < 0) message(L_LOG | L_CONSOLE, "can't fork"); - if (pid) - return pid; + if (pid) { + sigprocmask_allsigs(SIG_UNBLOCK); + return pid; /* Parent or error */ + } /* Child */ @@ -367,65 +333,20 @@ static pid_t run(const struct init_action *a) bb_signals(0 + (1 << SIGUSR1) + (1 << SIGUSR2) - + (1 << SIGINT) + (1 << SIGTERM) - + (1 << SIGHUP) + (1 << SIGQUIT) - + (1 << SIGCONT) - + (1 << SIGSTOP) + + (1 << SIGINT) + + (1 << SIGHUP) + (1 << SIGTSTP) , SIG_DFL); + sigprocmask_allsigs(SIG_UNBLOCK); - /* Create a new session and make ourself the process - * group leader */ + /* Create a new session and make ourself the process group leader */ setsid(); /* Open the new terminal device */ - open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */); - -// NB: do not enable unless you change vfork to fork above -#ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING - /* If the init Action requires us to wait, then force the - * supplied terminal to be the controlling tty. */ - if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { - /* Now fork off another process to just hang around */ - pid = fork(); - if (pid < 0) { - message(L_LOG | L_CONSOLE, "can't fork"); - _exit(EXIT_FAILURE); - } - - if (pid > 0) { - /* Parent - wait till the child is done */ - bb_signals(0 - + (1 << SIGINT) - + (1 << SIGTSTP) - + (1 << SIGQUIT) - , SIG_IGN); - signal(SIGCHLD, SIG_DFL); - - waitfor(pid); - /* See if stealing the controlling tty back is necessary */ - if (tcgetpgrp(0) != getpid()) - _exit(EXIT_SUCCESS); - - /* Use a temporary process to steal the controlling tty. */ - pid = fork(); - if (pid < 0) { - message(L_LOG | L_CONSOLE, "can't fork"); - _exit(EXIT_FAILURE); - } - if (pid == 0) { - setsid(); - ioctl(0, TIOCSCTTY, 1); - _exit(EXIT_SUCCESS); - } - waitfor(pid); - _exit(EXIT_SUCCESS); - } - /* Child - fall though to actually execute things */ - } -#endif + if (!open_stdio_to_tty(a->terminal)) + _exit(EXIT_FAILURE); /* NB: on NOMMU we can't wait for input in child, so * "askfirst" will work the same as "respawn". */ @@ -444,7 +365,7 @@ static pid_t run(const struct init_action *a) * be allowed to start a shell or whatever an init script * specifies. */ - messageD(L_LOG, "waiting for enter to start '%s'" + dbg_message(L_LOG, "waiting for enter to start '%s'" "(pid %d, tty '%s')\n", a->command, getpid(), a->terminal); full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1); @@ -452,9 +373,14 @@ static pid_t run(const struct init_action *a) continue; } + /* + * When a file named /.init_enable_core exists, setrlimit is called + * before processes are spawned to set core file size as unlimited. + * This is for debugging only. Don't use this is production, unless + * you want core dumps lying about.... + */ if (ENABLE_FEATURE_INIT_COREDUMPS) { - struct stat sb; - if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) { + if (access("/.init_enable_core", F_OK) == 0) { struct rlimit limit; limit.rlim_cur = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY; @@ -473,196 +399,106 @@ static pid_t run(const struct init_action *a) _exit(-1); } -static void delete_init_action(struct init_action *action) +static struct init_action *mark_terminated(pid_t pid) { - struct init_action *a, *b = NULL; - - for (a = init_action_list; a; b = a, a = a->next) { - if (a == action) { - if (b == NULL) { - init_action_list = a->next; - } else { - b->next = a->next; - } - free(a); - break; - } - } -} + struct init_action *a; -/* Run all commands of a particular type */ -static void run_actions(int action_type) -{ - struct init_action *a, *tmp; - - for (a = init_action_list; a; a = tmp) { - tmp = a->next; - if (a->action_type & action_type) { - // Pointless: run() will error out if open of device fails. - ///* a->terminal of "" means "init's console" */ - //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) { - // //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/); - // delete_init_action(a); - //} else - if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { - waitfor(run(a)); - delete_init_action(a); - } else if (a->action_type & ONCE) { - run(a); - delete_init_action(a); - } else if (a->action_type & (RESPAWN | ASKFIRST)) { - /* Only run stuff with pid==0. If they have - * a pid, that means it is still running */ - if (a->pid == 0) { - a->pid = run(a); - } + if (pid > 0) { + for (a = init_action_list; a; a = a->next) { + if (a->pid == pid) { + a->pid = 0; + return a; } } } + return NULL; } -static void init_reboot(unsigned long magic) -{ - pid_t pid; - /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) in - * linux/kernel/sys.c, which can cause the machine to panic when - * the init process is killed.... */ - pid = vfork(); - if (pid == 0) { /* child */ - reboot(magic); - _exit(EXIT_SUCCESS); - } - waitfor(pid); -} - -static void kill_all_processes(void) -{ - /* run everything to be run at "shutdown". This is done _prior_ - * to killing everything, in case people wish to use scripts to - * shut things down gracefully... */ - run_actions(SHUTDOWN); - - /* first disable all our signals */ - sigprocmask_allsigs(SIG_BLOCK); - - message(L_CONSOLE | L_LOG, "The system is going down NOW!"); - - /* Allow Ctrl-Alt-Del to reboot system. */ - init_reboot(RB_ENABLE_CAD); - - /* Send signals to every process _except_ pid 1 */ - message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM"); - kill(-1, SIGTERM); - sync(); - sleep(1); - - message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL"); - kill(-1, SIGKILL); - sync(); - sleep(1); -} - -static void halt_reboot_pwoff(int sig) +static void waitfor(pid_t pid) { - const char *m = "halt"; - int rb; - - kill_all_processes(); + /* waitfor(run(x)): protect against failed fork inside run() */ + if (pid <= 0) + return; - rb = RB_HALT_SYSTEM; - if (sig == SIGTERM) { - m = "reboot"; - rb = RB_AUTOBOOT; - } else if (sig == SIGUSR2) { - m = "poweroff"; - rb = RB_POWER_OFF; + /* Wait for any child (prevent zombies from exiting orphaned processes) + * but exit the loop only when specified one has exited. */ + while (1) { + pid_t wpid = wait(NULL); + mark_terminated(wpid); + /* Unsafe. SIGTSTP handler might have wait'ed it already */ + /*if (wpid == pid) break;*/ + /* More reliable: */ + if (kill(pid, 0)) + break; } - message(L_CONSOLE | L_LOG, "Requesting system %s", m); - /* allow time for last message to reach serial console */ - sleep(2); - init_reboot(rb); - loop_forever(); } -/* Handler for QUIT - exec "restart" action, - * else (no such action defined) do nothing */ -static void exec_restart_action(int sig UNUSED_PARAM) +/* Run all commands of a particular type */ +static void run_actions(int action_type) { struct init_action *a; for (a = init_action_list; a; a = a->next) { - if (a->action_type & RESTART) { - kill_all_processes(); - - /* unblock all signals (blocked in kill_all_processes()) */ - sigprocmask_allsigs(SIG_UNBLOCK); - - /* Open the new terminal device */ - open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); + if (!(a->action_type & action_type)) + continue; - messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); - init_exec(a->command); - sleep(2); - init_reboot(RB_HALT_SYSTEM); - loop_forever(); + if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) { + pid_t pid = run(a); + if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN)) + waitfor(pid); + } + if (a->action_type & (RESPAWN | ASKFIRST)) { + /* Only run stuff with pid == 0. If pid != 0, + * it is already running + */ + if (a->pid == 0) + a->pid = run(a); } } } -static void ctrlaltdel_signal(int sig UNUSED_PARAM) -{ - run_actions(CTRLALTDEL); -} - -/* The SIGSTOP & SIGTSTP handler */ -static void stop_handler(int sig UNUSED_PARAM) -{ - int saved_errno = errno; - - got_cont = 0; - while (!got_cont) - pause(); - - errno = saved_errno; -} - -/* The SIGCONT handler */ -static void cont_handler(int sig UNUSED_PARAM) -{ - got_cont = 1; -} - static void new_init_action(uint8_t action_type, const char *command, const char *cons) { - struct init_action *a, *last; - -// Why? -// if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) -// return; - - /* Append to the end of the list */ - for (a = last = init_action_list; a; a = a->next) { - /* don't enter action if it's already in the list, - * but do overwrite existing actions */ + struct init_action *a, **nextp; + + /* Scenario: + * old inittab: + * ::shutdown:umount -a -r + * ::shutdown:swapoff -a + * new inittab: + * ::shutdown:swapoff -a + * ::shutdown:umount -a -r + * On reload, we must ensure entries end up in correct order. + * To achieve that, if we find a matching entry, we move it + * to the end. + */ + nextp = &init_action_list; + while ((a = *nextp) != NULL) { + /* Don't enter action if it's already in the list, + * This prevents losing running RESPAWNs. + */ if ((strcmp(a->command, command) == 0) && (strcmp(a->terminal, cons) == 0) ) { - a->action_type = action_type; - return; + /* Remove from list */ + *nextp = a->next; + /* Find the end of the list */ + while (*nextp != NULL) + nextp = &(*nextp)->next; + a->next = NULL; + break; } - last = a; + nextp = &a->next; } - a = xzalloc(sizeof(*a)); - if (last) { - last->next = a; - } else { - init_action_list = a; - } + if (!a) + a = xzalloc(sizeof(*a)); + /* Append to the end of the list */ + *nextp = a; a->action_type = action_type; safe_strncpy(a->command, command, sizeof(a->command)); safe_strncpy(a->terminal, cons, sizeof(a->terminal)); - messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", + dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", a->command, a->action_type, a->terminal); } @@ -675,15 +511,14 @@ static void new_init_action(uint8_t action_type, const char *command, const char */ static void parse_inittab(void) { +#if ENABLE_FEATURE_USE_INITTAB char *token[4]; - /* order must correspond to SYSINIT..RESTART constants */ - static const char actions[] ALIGN1 = - "sysinit\0""respawn\0""askfirst\0""wait\0""once\0" - "ctrlaltdel\0""shutdown\0""restart\0"; - - parser_t *parser = config_open2(INITTAB, fopen_for_read); - /* No inittab file -- set up some default behavior */ - if (parser == NULL) { + parser_t *parser = config_open2("/etc/inittab", fopen_for_read); + + if (parser == NULL) +#endif + { + /* No inittab file - set up some default behavior */ /* Reboot on Ctrl-Alt-Del */ new_init_action(CTRLALTDEL, "reboot", ""); /* Umount all filesystems on halt/reboot */ @@ -703,11 +538,17 @@ static void parse_inittab(void) new_init_action(SYSINIT, INIT_SCRIPT, ""); return; } + +#if ENABLE_FEATURE_USE_INITTAB /* optional_tty:ignored_runlevel:action:command * Delims are not to be collapsed and need exactly 4 tokens */ while (config_read(parser, token, 4, 0, "#:", PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) { + /* order must correspond to SYSINIT..RESTART constants */ + static const char actions[] ALIGN1 = + "sysinit\0""wait\0""once\0""respawn\0""askfirst\0" + "ctrlaltdel\0""shutdown\0""restart\0"; int action; char *tty = token[0]; @@ -731,93 +572,271 @@ static void parse_inittab(void) parser->lineno); } config_close(parser); +#endif +} + +static void pause_and_low_level_reboot(unsigned magic) NORETURN; +static void pause_and_low_level_reboot(unsigned magic) +{ + pid_t pid; + + /* Allow time for last message to reach serial console, etc */ + sleep(1); + + /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) + * in linux/kernel/sys.c, which can cause the machine to panic when + * the init process exits... */ + pid = vfork(); + if (pid == 0) { /* child */ + reboot(magic); + _exit(EXIT_SUCCESS); + } + while (1) + sleep(1); +} + +static void run_shutdown_and_kill_processes(void) +{ + /* Run everything to be run at "shutdown". This is done _prior_ + * to killing everything, in case people wish to use scripts to + * shut things down gracefully... */ + run_actions(SHUTDOWN); + + message(L_CONSOLE | L_LOG, "The system is going down NOW!"); + + /* Send signals to every process _except_ pid 1 */ + kill(-1, SIGTERM); + message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM"); + sync(); + sleep(1); + + kill(-1, SIGKILL); + message(L_CONSOLE, "Sent SIG%s to all processes", "KILL"); + sync(); + /*sleep(1); - callers take care about making a pause */ +} + +/* Signal handling by init: + * + * For process with PID==1, on entry kernel sets all signals to SIG_DFL + * and unmasks all signals. However, for process with PID==1, + * default action (SIG_DFL) on any signal is to ignore it, + * even for special signals SIGKILL and SIGCONT. + * Also, any signal can be caught or blocked. + * (but SIGSTOP is still handled specially, at least in 2.6.20) + * + * We install two kinds of handlers, "immediate" and "delayed". + * + * Immediate handlers execute at any time, even while, say, sysinit + * is running. + * + * Delayed handlers just set a flag variable. The variable is checked + * in the main loop and acted upon. + * + * halt/poweroff/reboot and restart have immediate handlers. + * They only traverse linked list of struct action's, never modify it, + * this should be safe to do even in signal handler. Also they + * never return. + * + * SIGSTOP and SIGTSTP have immediate handlers. They just wait + * for SIGCONT to happen. + * + * SIGHUP has a delayed handler, because modifying linked list + * of struct action's from a signal handler while it is manipulated + * by the program may be disastrous. + * + * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing + * it to happen even somewhere inside "sysinit" would be a bit awkward. + * + * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide + * and only one will be remembered and acted upon. + */ + +static void halt_reboot_pwoff(int sig) NORETURN; +static void halt_reboot_pwoff(int sig) +{ + const char *m; + unsigned rb; + + run_shutdown_and_kill_processes(); + + m = "halt"; + rb = RB_HALT_SYSTEM; + if (sig == SIGTERM) { + m = "reboot"; + rb = RB_AUTOBOOT; + } else if (sig == SIGUSR2) { + m = "poweroff"; + rb = RB_POWER_OFF; + } + message(L_CONSOLE, "Requesting system %s", m); + pause_and_low_level_reboot(rb); + /* not reached */ +} + +/* The SIGSTOP/SIGTSTP handler + * NB: inside it, all signals except SIGCONT are masked + * via appropriate setup in sigaction(). + */ +static void stop_handler(int sig UNUSED_PARAM) +{ + smallint saved_bb_got_signal; + int saved_errno; + + saved_bb_got_signal = bb_got_signal; + saved_errno = errno; + signal(SIGCONT, record_signo); + + while (1) { + pid_t wpid; + + if (bb_got_signal == SIGCONT) + break; + /* NB: this can accidentally wait() for a process + * which we waitfor() elsewhere! waitfor() must have + * code which is resilient against this. + */ + wpid = wait_any_nohang(NULL); + mark_terminated(wpid); + sleep(1); + } + + signal(SIGCONT, SIG_DFL); + errno = saved_errno; + bb_got_signal = saved_bb_got_signal; +} + +/* Handler for QUIT - exec "restart" action, + * else (no such action defined) do nothing */ +static void restart_handler(int sig UNUSED_PARAM) +{ + struct init_action *a; + + for (a = init_action_list; a; a = a->next) { + if (!(a->action_type & RESTART)) + continue; + + /* Starting from here, we won't return. + * Thus don't need to worry about preserving errno + * and such. + */ + run_shutdown_and_kill_processes(); + + /* Allow Ctrl-Alt-Del to reboot the system. + * This is how kernel sets it up for init, we follow suit. + */ + reboot(RB_ENABLE_CAD); /* misnomer */ + + if (open_stdio_to_tty(a->terminal)) { + dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); + /* Theoretically should be safe. + * But in practice, kernel bugs may leave + * unkillable processes, and wait() may block forever. + * Oh well. Hoping "new" init won't be too surprised + * by having children it didn't create. + */ + //while (wait(NULL) > 0) + // continue; + init_exec(a->command); + } + /* Open or exec failed */ + pause_and_low_level_reboot(RB_HALT_SYSTEM); + /* not reached */ + } } #if ENABLE_FEATURE_USE_INITTAB -static void reload_signal(int sig UNUSED_PARAM) +static void reload_inittab(void) { - struct init_action *a, *tmp; + struct init_action *a, **nextp; message(L_LOG, "reloading /etc/inittab"); - /* disable old entrys */ - for (a = init_action_list; a; a = a->next) { + /* Disable old entries */ + for (a = init_action_list; a; a = a->next) a->action_type = ONCE; - } + /* Append new entries, or modify existing entries + * (set a->action_type) if cmd and device name + * match new ones. End result: only entries with + * a->action_type == ONCE are stale. + */ parse_inittab(); - if (ENABLE_FEATURE_KILL_REMOVED) { - /* Be nice and send SIGTERM first */ - for (a = init_action_list; a; a = a->next) { - pid_t pid = a->pid; - if ((a->action_type & ONCE) && pid != 0) { - kill(pid, SIGTERM); - } - } -#if CONFIG_FEATURE_KILL_DELAY +#if ENABLE_FEATURE_KILL_REMOVED + /* Kill stale entries */ + /* Be nice and send SIGTERM first */ + for (a = init_action_list; a; a = a->next) + if (a->action_type == ONCE && a->pid != 0) + kill(a->pid, SIGTERM); + if (CONFIG_FEATURE_KILL_DELAY) { /* NB: parent will wait in NOMMU case */ if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ sleep(CONFIG_FEATURE_KILL_DELAY); - for (a = init_action_list; a; a = a->next) { - pid_t pid = a->pid; - if ((a->action_type & ONCE) && pid != 0) { - kill(pid, SIGKILL); - } - } + for (a = init_action_list; a; a = a->next) + if (a->action_type == ONCE && a->pid != 0) + kill(a->pid, SIGKILL); _exit(EXIT_SUCCESS); } -#endif } +#endif - /* remove unused entrys */ - for (a = init_action_list; a; a = tmp) { - tmp = a->next; - if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { - delete_init_action(a); + /* Remove stale (ONCE) and not useful (SYSINIT,WAIT) entries */ + nextp = &init_action_list; + while ((a = *nextp) != NULL) { + if (a->action_type & (ONCE | SYSINIT | WAIT)) { + *nextp = a->next; + free(a); + } else { + nextp = &a->next; } } - run_actions(RESPAWN | ASKFIRST); + + /* Not needed: */ + /* run_actions(RESPAWN | ASKFIRST); */ + /* - we return to main loop, which does this automagically */ } #endif +static int check_delayed_sigs(void) +{ + int sigs_seen = 0; + + while (1) { + smallint sig = bb_got_signal; + + if (!sig) + return sigs_seen; + bb_got_signal = 0; + sigs_seen = 1; +#if ENABLE_FEATURE_USE_INITTAB + if (sig == SIGHUP) + reload_inittab(); +#endif + if (sig == SIGINT) + run_actions(CTRLALTDEL); + } +} + int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { - struct init_action *a; - pid_t wpid; - - die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */ + die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */ if (argv[1] && !strcmp(argv[1], "-q")) { return kill(1, SIGHUP); } - if (!ENABLE_DEBUG_INIT) { + if (!DEBUG_INIT) { /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")) ) { bb_show_usage(); } - /* Set up sig handlers -- be sure to - * clear all of these in run() */ - signal(SIGQUIT, exec_restart_action); - bb_signals(0 - + (1 << SIGUSR1) /* halt */ - + (1 << SIGUSR2) /* poweroff */ - + (1 << SIGTERM) /* reboot */ - , halt_reboot_pwoff); - signal(SIGINT, ctrlaltdel_signal); - signal(SIGCONT, cont_handler); - bb_signals(0 - + (1 << SIGSTOP) - + (1 << SIGTSTP) - , stop_handler); - - /* Turn off rebooting via CTL-ALT-DEL -- we get a + /* Turn off rebooting via CTL-ALT-DEL - we get a * SIGINT on CAD so we can shut things down gracefully... */ - init_reboot(RB_DISABLE_CAD); + reboot(RB_DISABLE_CAD); /* misnomer */ } /* Figure out where the default console should be */ @@ -825,15 +844,15 @@ int init_main(int argc UNUSED_PARAM, char **argv) set_sane_term(); xchdir("/"); setsid(); - { - const char *const *e; - /* Make sure environs is set to something sane */ - for (e = environment; *e; e++) - putenv((char *) *e); - } + + /* Make sure environs is set to something sane */ + putenv((char *) "HOME=/"); + putenv((char *) bb_PATH_root_path); + putenv((char *) "SHELL=/bin/sh"); + putenv((char *) "USER=root"); /* needed? why? */ if (argv[1]) - setenv("RUNLEVEL", argv[1], 1); + xsetenv("RUNLEVEL", argv[1]); /* Hello world */ message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner); @@ -842,9 +861,9 @@ int init_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_SWAPONOFF) { struct sysinfo info; - if (!sysinfo(&info) && - (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024) - { + if (sysinfo(&info) == 0 + && (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024 + ) { message(L_CONSOLE, "Low memory, forcing swapon"); /* swapon -a requires /proc typically */ new_init_action(SYSINIT, "mount -t proc proc /proc", ""); @@ -862,11 +881,11 @@ int init_main(int argc UNUSED_PARAM, char **argv) /* Start a shell on console */ new_init_action(RESPAWN, bb_default_login_shell, ""); } else { - /* Not in single user mode -- see what inittab says */ + /* Not in single user mode - see what inittab says */ /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair + * actions(i.e., INIT_SCRIPT and a pair * of "askfirst" shells */ parse_inittab(); } @@ -885,7 +904,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) exit(EXIT_FAILURE); } } -#endif /* CONFIG_SELINUX */ +#endif /* Make the command line just say "init" - thats all, nothing else */ strncpy(argv[0], "init", strlen(argv[0])); @@ -893,48 +912,93 @@ int init_main(int argc UNUSED_PARAM, char **argv) while (*++argv) memset(*argv, 0, strlen(*argv)); - /* Now run everything that needs to be run */ + /* Set up signal handlers */ + if (!DEBUG_INIT) { + struct sigaction sa; + + bb_signals(0 + + (1 << SIGUSR1) /* halt */ + + (1 << SIGTERM) /* reboot */ + + (1 << SIGUSR2) /* poweroff */ + , halt_reboot_pwoff); + signal(SIGQUIT, restart_handler); /* re-exec another init */ + + /* Stop handler must allow only SIGCONT inside itself */ + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sigdelset(&sa.sa_mask, SIGCONT); + sa.sa_handler = stop_handler; + /* NB: sa_flags doesn't have SA_RESTART. + * It must be able to interrupt wait(). + */ + sigaction_set(SIGTSTP, &sa); /* pause */ + /* Does not work as intended, at least in 2.6.20. + * SIGSTOP is simply ignored by init: + */ + sigaction_set(SIGSTOP, &sa); /* pause */ + + /* SIGINT (Ctrl-Alt-Del) must interrupt wait(), + * setting handler without SA_RESTART flag. + */ + bb_signals_recursive_norestart((1 << SIGINT), record_signo); + } + /* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); - + check_delayed_sigs(); /* Next run anything that wants to block */ run_actions(WAIT); - + check_delayed_sigs(); /* Next run anything to be run only once */ run_actions(ONCE); - /* Redefine SIGHUP to reread /etc/inittab */ -#if ENABLE_FEATURE_USE_INITTAB - signal(SIGHUP, reload_signal); -#else - signal(SIGHUP, SIG_IGN); -#endif + /* Set up "reread /etc/inittab" handler. + * Handler is set up without SA_RESTART, it will interrupt syscalls. + */ + if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB) + bb_signals_recursive_norestart((1 << SIGHUP), record_signo); - /* Now run the looping stuff for the rest of forever */ + /* Now run the looping stuff for the rest of forever. + * NB: if delayed signal happened, avoid blocking in wait(). + */ while (1) { - /* run the respawn/askfirst stuff */ + int maybe_WNOHANG; + + maybe_WNOHANG = check_delayed_sigs(); + + /* (Re)run the respawn/askfirst stuff */ run_actions(RESPAWN | ASKFIRST); + maybe_WNOHANG |= check_delayed_sigs(); - /* Don't consume all CPU time -- sleep a bit */ + /* Don't consume all CPU time - sleep a bit */ sleep(1); + maybe_WNOHANG |= check_delayed_sigs(); - /* Wait for any child process to exit */ - wpid = wait(NULL); - while (wpid > 0) { - /* Find out who died and clean up their corpse */ - for (a = init_action_list; a; a = a->next) { - if (a->pid == wpid) { - /* Set the pid to 0 so that the process gets - * restarted by run_actions() */ - a->pid = 0; - message(L_LOG, "process '%s' (pid %d) exited. " - "Scheduling for restart.", - a->command, wpid); - } + /* Wait for any child process(es) to exit. + * NB: "delayed" signals will also interrupt this wait(), + * bb_signals_recursive_norestart() set them up for that. + * This guarantees we won't be stuck here + * till next orphan dies. + */ + if (maybe_WNOHANG) + maybe_WNOHANG = WNOHANG; + while (1) { + pid_t wpid; + struct init_action *a; + + wpid = waitpid(-1, NULL, maybe_WNOHANG); + if (wpid <= 0) + break; + + a = mark_terminated(wpid); + if (a) { + message(L_LOG, "process '%s' (pid %d) exited. " + "Scheduling for restart.", + a->command, wpid); } - /* see if anyone else is waiting to be reaped */ - wpid = wait_any_nohang(NULL); + /* See if anyone else is waiting to be reaped */ + maybe_WNOHANG = WNOHANG; } - } + } /* while (1) */ } diff --git a/release/src/router/busybox/init/mesg.c b/release/src/router/busybox/init/mesg.c index cfb517f60a..ca230f3639 100644 --- a/release/src/router/busybox/init/mesg.c +++ b/release/src/router/busybox/init/mesg.c @@ -25,7 +25,7 @@ int mesg_main(int argc, char **argv) if (--argc == 0 || (argc == 1 && ((c = **++argv) == 'y' || c == 'n')) ) { - tty = ttyname(STDERR_FILENO); + tty = xmalloc_ttyname(STDERR_FILENO); if (tty == NULL) { tty = "ttyname"; } else if (stat(tty, &sb) == 0) { diff --git a/release/src/router/busybox/libbb/Kbuild b/release/src/router/busybox/libbb/Kbuild index 7262006753..8fddabdba0 100644 --- a/release/src/router/busybox/libbb/Kbuild +++ b/release/src/router/busybox/libbb/Kbuild @@ -58,6 +58,8 @@ lib-y += make_directory.o lib-y += makedev.o lib-y += match_fstype.o lib-y += md5.o +# Alternative (disabled) implementation +#lib-y += md5prime.o lib-y += messages.o lib-y += mode_string.o lib-y += mtab_file.o @@ -75,6 +77,7 @@ lib-y += process_escape_sequence.o lib-y += procps.o lib-y += ptr_to_globals.o lib-y += read.o +lib-y += read_key.o lib-y += recursive_action.o lib-y += remove_file.o lib-y += restricted_shell.o @@ -117,9 +120,13 @@ lib-y += xrealloc_vector.o lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o lib-$(CONFIG_LOSETUP) += loop.o lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o -lib-$(CONFIG_PASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o -lib-$(CONFIG_CHPASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o -lib-$(CONFIG_CRYPTPW) += pw_encrypt.o crypt_make_salt.o +lib-$(CONFIG_ADDGROUP) += update_passwd.o +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_CHPASSWD) += pw_encrypt.o update_passwd.o +lib-$(CONFIG_CRYPTPW) += pw_encrypt.o lib-$(CONFIG_SULOGIN) += pw_encrypt.o lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o diff --git a/release/src/router/busybox/libbb/appletlib.c b/release/src/router/busybox/libbb/appletlib.c index 2bab0eba61..80380ae08b 100644 --- a/release/src/router/busybox/libbb/appletlib.c +++ b/release/src/router/busybox/libbb/appletlib.c @@ -99,7 +99,7 @@ static const char *unpack_usage_messages(void) static void full_write2_str(const char *str) { - full_write(STDERR_FILENO, str, strlen(str)); + xwrite_str(STDERR_FILENO, str); } void FAST_FUNC bb_show_usage(void) @@ -111,9 +111,9 @@ void FAST_FUNC bb_show_usage(void) const char *usage_string = p = unpack_usage_messages(); if (*p == '\b') { - full_write2_str("\nNo help available.\n\n"); + full_write2_str("No help available.\n\n"); } else { - full_write2_str("\nUsage: "SINGLE_APPLET_STR" "); + full_write2_str("Usage: "SINGLE_APPLET_STR" "); full_write2_str(p); full_write2_str("\n\n"); } diff --git a/release/src/router/busybox/libbb/bb_askpass.c b/release/src/router/busybox/libbb/bb_askpass.c index fba82a07bf..c0dcf0c5ff 100644 --- a/release/src/router/busybox/libbb/bb_askpass.c +++ b/release/src/router/busybox/libbb/bb_askpass.c @@ -8,8 +8,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include - #include "libbb.h" /* do nothing signal handler */ @@ -17,7 +15,11 @@ static void askpass_timeout(int UNUSED_PARAM ignore) { } -char* FAST_FUNC bb_askpass(int timeout, const char *prompt) +char* FAST_FUNC bb_ask_stdin(const char *prompt) +{ + return bb_ask(STDIN_FILENO, 0, prompt); +} +char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) { /* Was static char[BIGNUM] */ enum { sizeof_passwd = 128 }; @@ -32,12 +34,12 @@ char* FAST_FUNC bb_askpass(int timeout, const char *prompt) passwd = xmalloc(sizeof_passwd); memset(passwd, 0, sizeof_passwd); - tcgetattr(STDIN_FILENO, &oldtio); - tcflush(STDIN_FILENO, TCIFLUSH); + tcgetattr(fd, &oldtio); + tcflush(fd, TCIFLUSH); tio = oldtio; tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); - tcsetattr(STDIN_FILENO, TCSANOW, &tio); + tcsetattr_stdin_TCSANOW(&tio); memset(&sa, 0, sizeof(sa)); /* sa.sa_flags = 0; - no SA_RESTART! */ @@ -54,7 +56,7 @@ char* FAST_FUNC bb_askpass(int timeout, const char *prompt) ret = NULL; /* On timeout or Ctrl-C, read will hopefully be interrupted, * and we return NULL */ - if (read(STDIN_FILENO, passwd, sizeof_passwd - 1) > 0) { + if (read(fd, passwd, sizeof_passwd - 1) > 0) { ret = passwd; i = 0; /* Last byte is guaranteed to be 0 @@ -70,7 +72,7 @@ char* FAST_FUNC bb_askpass(int timeout, const char *prompt) } sigaction_set(SIGINT, &oldsa); - tcsetattr(STDIN_FILENO, TCSANOW, &oldtio); + tcsetattr_stdin_TCSANOW(&oldtio); bb_putchar('\n'); fflush(stdout); return ret; diff --git a/release/src/router/busybox/libbb/bb_pwd.c b/release/src/router/busybox/libbb/bb_pwd.c dissimilarity index 73% index 65eb69200a..d728577714 100644 --- a/release/src/router/busybox/libbb/bb_pwd.c +++ b/release/src/router/busybox/libbb/bb_pwd.c @@ -1,99 +1,112 @@ -/* vi: set sw=4 ts=4: */ -/* - * password utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - */ - -#include "libbb.h" - -#define assert(x) ((void)0) - -/* internal function for bb_getpwuid and bb_getgrgid */ -/* Hacked by Tito Ragusa (c) 2004 to make it more - * flexible: - * - * bufsize > 0: If idname is not NULL it is copied to buffer, - * and buffer is returned. Else id as string is written - * to buffer, and NULL is returned. - * - * bufsize == 0: idname is returned. - * - * bufsize < 0: If idname is not NULL it is returned. - * Else an error message is printed and the program exits. - */ -static char* bb_getug(char *buffer, int bufsize, char *idname, long id, char prefix) -{ - if (bufsize > 0) { - assert(buffer != NULL); - if (idname) { - return safe_strncpy(buffer, idname, bufsize); - } - snprintf(buffer, bufsize, "%ld", id); - } else if (bufsize < 0 && !idname) { - bb_error_msg_and_die("unknown %cid %ld", prefix, id); - } - return idname; -} - -/* bb_getpwuid, bb_getgrgid: - * bb_getXXXid(buf, bufsz, id) - copy user/group name or id - * as a string to buf, return user/group name or NULL - * bb_getXXXid(NULL, 0, id) - return user/group name or NULL - * bb_getXXXid(NULL, -1, id) - return user/group name or exit - */ -/* gets a username given a uid */ -char* FAST_FUNC bb_getpwuid(char *name, int bufsize, long uid) -{ - struct passwd *myuser = getpwuid(uid); - - return bb_getug(name, bufsize, - (myuser ? myuser->pw_name : (char*)myuser), - uid, 'u'); -} -/* gets a groupname given a gid */ -char* FAST_FUNC bb_getgrgid(char *group, int bufsize, long gid) -{ - struct group *mygroup = getgrgid(gid); - - return bb_getug(group, bufsize, - (mygroup ? mygroup->gr_name : (char*)mygroup), - gid, 'g'); -} - -/* returns a gid given a group name */ -long FAST_FUNC xgroup2gid(const char *name) -{ - struct group *mygroup; - - mygroup = getgrnam(name); - if (mygroup == NULL) - bb_error_msg_and_die("unknown group name: %s", name); - - return mygroup->gr_gid; -} - -/* returns a uid given a username */ -long FAST_FUNC xuname2uid(const char *name) -{ - struct passwd *myuser; - - myuser = getpwnam(name); - if (myuser == NULL) - bb_error_msg_and_die("unknown user %s", name); - - return myuser->pw_uid; -} - -unsigned long FAST_FUNC get_ug_id(const char *s, - long FAST_FUNC (*xname2id)(const char *)) -{ - unsigned long r; - - r = bb_strtoul(s, NULL, 10); - if (errno) - return xname2id(s); - return r; -} +/* vi: set sw=4 ts=4: */ +/* + * password utility routines. + * + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2008 by Tito Ragusa + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + */ + +#include "libbb.h" + +/* TODO: maybe change API to return malloced data? + * This will allow to stop using libc functions returning + * pointers to static data (getpwuid) + */ + +struct passwd* FAST_FUNC xgetpwnam(const char *name) +{ + struct passwd *pw = getpwnam(name); + if (!pw) + bb_error_msg_and_die("unknown user %s", name); + return pw; +} + +struct group* FAST_FUNC xgetgrnam(const char *name) +{ + struct group *gr = getgrnam(name); + if (!gr) + bb_error_msg_and_die("unknown group %s", name); + return gr; +} + + +struct passwd* FAST_FUNC xgetpwuid(uid_t uid) +{ + struct passwd *pw = getpwuid(uid); + if (!pw) + bb_error_msg_and_die("unknown uid %u", (unsigned)uid); + return pw; +} + +struct group* FAST_FUNC xgetgrgid(gid_t gid) +{ + struct group *gr = getgrgid(gid); + if (!gr) + bb_error_msg_and_die("unknown gid %u", (unsigned)gid); + return gr; +} + +char* FAST_FUNC xuid2uname(uid_t uid) +{ + struct passwd *pw = xgetpwuid(uid); + return pw->pw_name; +} + +char* FAST_FUNC xgid2group(gid_t gid) +{ + struct group *gr = xgetgrgid(gid); + return gr->gr_name; +} + +char* FAST_FUNC uid2uname(uid_t uid) +{ + struct passwd *pw = getpwuid(uid); + return (pw) ? pw->pw_name : NULL; +} + +char* FAST_FUNC gid2group(gid_t gid) +{ + struct group *gr = getgrgid(gid); + return (gr) ? gr->gr_name : NULL; +} + +char* FAST_FUNC uid2uname_utoa(long uid) +{ + char *name = uid2uname(uid); + return (name) ? name : utoa(uid); +} + +char* FAST_FUNC gid2group_utoa(long gid) +{ + char *name = gid2group(gid); + return (name) ? name : utoa(gid); +} + +long FAST_FUNC xuname2uid(const char *name) +{ + struct passwd *myuser; + + myuser = xgetpwnam(name); + return myuser->pw_uid; +} + +long FAST_FUNC xgroup2gid(const char *name) +{ + struct group *mygroup; + + mygroup = xgetgrnam(name); + return mygroup->gr_gid; +} + +unsigned long FAST_FUNC get_ug_id(const char *s, + long FAST_FUNC (*xname2id)(const char *)) +{ + unsigned long r; + + r = bb_strtoul(s, NULL, 10); + if (errno) + return xname2id(s); + return r; +} diff --git a/release/src/router/busybox/libbb/bb_strtod.c b/release/src/router/busybox/libbb/bb_strtod.c index 0515ff8678..39bdeb5e54 100644 --- a/release/src/router/busybox/libbb/bb_strtod.c +++ b/release/src/router/busybox/libbb/bb_strtod.c @@ -17,7 +17,8 @@ double FAST_FUNC bb_strtod(const char *arg, char **endp) double v; char *endptr; - if (arg[0] != '-' && NOT_DIGIT(arg[0])) + /* Allow .NN form. People want to use "sleep .15" etc */ + if (arg[0] != '-' && arg[0] != '.' && NOT_DIGIT(arg[0])) goto err; errno = 0; v = strtod(arg, &endptr); diff --git a/release/src/router/busybox/libbb/correct_password.c b/release/src/router/busybox/libbb/correct_password.c index 255b048706..6301589e6a 100644 --- a/release/src/router/busybox/libbb/correct_password.c +++ b/release/src/router/busybox/libbb/correct_password.c @@ -68,7 +68,7 @@ int FAST_FUNC correct_password(const struct passwd *pw) return 1; fake_it: - unencrypted = bb_askpass(0, "Password: "); + unencrypted = bb_ask_stdin("Password: "); if (!unencrypted) { return 0; } diff --git a/release/src/router/busybox/libbb/crc32.c b/release/src/router/busybox/libbb/crc32.c index 42079b9c59..36ac860425 100644 --- a/release/src/router/busybox/libbb/crc32.c +++ b/release/src/router/busybox/libbb/crc32.c @@ -12,6 +12,8 @@ * * endian = 1: big-endian * endian = 0: little-endian + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" diff --git a/release/src/router/busybox/libbb/create_icmp6_socket.c b/release/src/router/busybox/libbb/create_icmp6_socket.c index 20655170e4..91e478ec83 100644 --- a/release/src/router/busybox/libbb/create_icmp6_socket.c +++ b/release/src/router/busybox/libbb/create_icmp6_socket.c @@ -4,6 +4,8 @@ * * create raw socket for icmp (IPv6 version) protocol * and drop root privileges if running setuid + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" diff --git a/release/src/router/busybox/libbb/create_icmp_socket.c b/release/src/router/busybox/libbb/create_icmp_socket.c index 1fa016ab87..d75f8452d1 100644 --- a/release/src/router/busybox/libbb/create_icmp_socket.c +++ b/release/src/router/busybox/libbb/create_icmp_socket.c @@ -4,6 +4,8 @@ * * create raw socket for icmp protocol * and drop root privileges if running setuid + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" diff --git a/release/src/router/busybox/libbb/crypt_make_salt.c b/release/src/router/busybox/libbb/crypt_make_salt.c deleted file mode 100644 index 393eba5f9b..0000000000 --- a/release/src/router/busybox/libbb/crypt_make_salt.c +++ /dev/null @@ -1,45 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * crypt_make_salt - * - * i64c was also put here, this is the only function that uses it. - * - * Lifted from loginutils/passwd.c by Thomas Lundquist - * - */ - -#include "libbb.h" - -static int i64c(int i) -{ - i &= 0x3f; - if (i == 0) - return '.'; - if (i == 1) - return '/'; - if (i < 12) - return ('0' - 2 + i); - if (i < 38) - return ('A' - 12 + i); - return ('a' - 38 + i); -} - -int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) -{ - x += getpid() + time(NULL); - do { - /* x = (x*1664525 + 1013904223) % 2^32 generator is lame - * (low-order bit is not "random", etc...), - * but for our purposes it is good enough */ - x = x*1664525 + 1013904223; - /* BTW, Park and Miller's "minimal standard generator" is - * x = x*16807 % ((2^31)-1) - * It has no problem with visibly alternating lowest bit - * but is also weak in cryptographic sense + needs div, - * which needs more code (and slower) on many CPUs */ - *p++ = i64c(x >> 16); - *p++ = i64c(x >> 22); - } while (--cnt); - *p = '\0'; - return x; -} diff --git a/release/src/router/busybox/libbb/die_if_bad_username.c b/release/src/router/busybox/libbb/die_if_bad_username.c index 602aadc0cf..c1641d376a 100644 --- a/release/src/router/busybox/libbb/die_if_bad_username.c +++ b/release/src/router/busybox/libbb/die_if_bad_username.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Ckeck user and group names for illegal characters + * Check user and group names for illegal characters * * Copyright (C) 2008 Tito Ragusa * diff --git a/release/src/router/busybox/libbb/dump.c b/release/src/router/busybox/libbb/dump.c index 74c5e16917..2e777c358b 100644 --- a/release/src/router/busybox/libbb/dump.c +++ b/release/src/router/busybox/libbb/dump.c @@ -298,7 +298,7 @@ static void rewrite(priv_dumper_t *dumper, FS *fs) * if, rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ - for (fu = fs->nextfu;; fu = fu->nextfu) { + for (fu = fs->nextfu; fu; fu = fu->nextfu) { if (!fu->nextfu && fs->bcnt < dumper->blocksize && !(fu->flags & F_SETREP) && fu->bcnt ) { @@ -579,11 +579,11 @@ static void display(priv_dumper_t* dumper) switch (pr->bcnt) { case 4: - memmove(&fval, bp, sizeof(fval)); + memcpy(&fval, bp, sizeof(fval)); printf(pr->fmt, fval); break; case 8: - memmove(&dval, bp, sizeof(dval)); + memcpy(&dval, bp, sizeof(dval)); printf(pr->fmt, dval); break; } @@ -598,11 +598,11 @@ static void display(priv_dumper_t* dumper) printf(pr->fmt, (int) *bp); break; case 2: - memmove(&sval, bp, sizeof(sval)); + memcpy(&sval, bp, sizeof(sval)); printf(pr->fmt, (int) sval); break; case 4: - memmove(&ival, bp, sizeof(ival)); + memcpy(&ival, bp, sizeof(ival)); printf(pr->fmt, ival); break; } @@ -629,11 +629,11 @@ static void display(priv_dumper_t* dumper) printf(pr->fmt, (unsigned) *bp); break; case 2: - memmove(&sval, bp, sizeof(sval)); + memcpy(&sval, bp, sizeof(sval)); printf(pr->fmt, (unsigned) sval); break; case 4: - memmove(&ival, bp, sizeof(ival)); + memcpy(&ival, bp, sizeof(ival)); printf(pr->fmt, ival); break; } @@ -723,7 +723,8 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) nextfupp = &tfs->nextfu; /* take the format string and break it up into format units */ - for (p = fmt;;) { + p = fmt; + for (;;) { p = skip_whitespace(p); if (!*p) { break; diff --git a/release/src/router/busybox/libbb/fgets_str.c b/release/src/router/busybox/libbb/fgets_str.c index 8026a15da5..3fe61cdc39 100644 --- a/release/src/router/busybox/libbb/fgets_str.c +++ b/release/src/router/busybox/libbb/fgets_str.c @@ -10,7 +10,7 @@ #include "libbb.h" -static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off) +static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off, size_t *maxsz_p) { char *linebuf = NULL; const int term_length = strlen(terminating_string); @@ -18,6 +18,7 @@ static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int linebufsz = 0; int idx = 0; int ch; + size_t maxsz = *maxsz_p; while (1) { ch = fgetc(file); @@ -30,6 +31,11 @@ static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, if (idx >= linebufsz) { linebufsz += 200; linebuf = xrealloc(linebuf, linebufsz); + if (idx >= maxsz) { + linebuf[idx] = ch; + idx++; + break; + } } linebuf[idx] = ch; @@ -48,6 +54,7 @@ static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, /* Grow/shrink *first*, then store NUL */ linebuf = xrealloc(linebuf, idx + 1); linebuf[idx] = '\0'; + *maxsz_p = idx; return linebuf; } @@ -57,10 +64,23 @@ static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, * Return NULL if EOF is reached immediately. */ char* FAST_FUNC xmalloc_fgets_str(FILE *file, const char *terminating_string) { - return xmalloc_fgets_internal(file, terminating_string, 0); + size_t maxsz = INT_MAX - 4095; + return xmalloc_fgets_internal(file, terminating_string, 0, &maxsz); +} + +char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p) +{ + size_t maxsz; + + if (!maxsz_p) { + maxsz = INT_MAX - 4095; + maxsz_p = &maxsz; + } + return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p); } char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string) { - return xmalloc_fgets_internal(file, terminating_string, 1); + size_t maxsz = INT_MAX - 4095; + return xmalloc_fgets_internal(file, terminating_string, 1, &maxsz); } diff --git a/release/src/router/busybox/libbb/find_pid_by_name.c b/release/src/router/busybox/libbb/find_pid_by_name.c index 2ee423cb7b..600d4e1a89 100644 --- a/release/src/router/busybox/libbb/find_pid_by_name.c +++ b/release/src/router/busybox/libbb/find_pid_by_name.c @@ -67,15 +67,14 @@ static int comm_match(procps_status_t *p, const char *procName) return 1; } -/* find_pid_by_name() +/* This finds the pid of the specified process. + * Currently, it's implemented by rummaging through + * the proc filesystem. * - * Modified by Vladimir Oleynik for use with libbb/procps.c - * This finds the pid of the specified process. - * Currently, it's implemented by rummaging through - * the proc filesystem. + * Returns a list of all matching PIDs + * It is the caller's duty to free the returned pidlist. * - * Returns a list of all matching PIDs - * It is the caller's duty to free the returned pidlist. + * Modified by Vladimir Oleynik for use with libbb/procps.c */ pid_t* FAST_FUNC find_pid_by_name(const char *procName) { @@ -88,7 +87,7 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName) if (comm_match(p, procName) /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) - /* TOOD: we can also try /proc/NUM/exe link, do we want that? */ + /* TODO: we can also try /proc/NUM/exe link, do we want that? */ ) { pidList = xrealloc_vector(pidList, 2, i); pidList[i++] = p->pid; diff --git a/release/src/router/busybox/libbb/get_console.c b/release/src/router/busybox/libbb/get_console.c index ad56e740f7..74022b5437 100644 --- a/release/src/router/busybox/libbb/get_console.c +++ b/release/src/router/busybox/libbb/get_console.c @@ -13,7 +13,6 @@ /* From */ enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */ - static int open_a_console(const char *fnam) { int fd; @@ -37,7 +36,6 @@ static int open_a_console(const char *fnam) * We try several things because opening /dev/console will fail * if someone else used X (which does a chown on /dev/console). */ - int FAST_FUNC get_console_fd_or_die(void) { static const char *const console_names[] = { diff --git a/release/src/router/busybox/libbb/getopt32.c b/release/src/router/busybox/libbb/getopt32.c index f33ead1c6e..5190fa61a9 100644 --- a/release/src/router/busybox/libbb/getopt32.c +++ b/release/src/router/busybox/libbb/getopt32.c @@ -155,9 +155,9 @@ Special characters: Allows any arguments to be given without a dash (./program w x) as well as with a dash (./program -x). - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. + NB: getopt32() will leak a small amount of memory if you use + this option! Do not use it if there is a possibility of recursive + getopt32() calls. "--" A double dash at the beginning of opt_complementary means the argv[1] string should always be treated as options, even if it isn't @@ -165,9 +165,9 @@ Special characters: such as "ar" and "tar": tar xvf foo.tar - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. + NB: getopt32() will leak a small amount of memory if you use + this option! Do not use it if there is a possibility of recursive + getopt32() calls. "-N" A dash as the first char in a opt_complementary group followed by a single digit (0-9) means that at least N non-option @@ -510,7 +510,7 @@ getopt32(char **argv, const char *applet_opts, ...) *pargv = pp; } if (!(spec_flgs & ALL_ARGV_IS_OPTS)) - break; + break; pargv++; } } diff --git a/release/src/router/busybox/libbb/human_readable.c b/release/src/router/busybox/libbb/human_readable.c index dad26edcff..05e7d86ec7 100644 --- a/release/src/router/busybox/libbb/human_readable.c +++ b/release/src/router/busybox/libbb/human_readable.c @@ -24,6 +24,8 @@ * * Some code to omit the decimal point and tenths digit is sketched out * and "#if 0"'d below. + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" @@ -32,7 +34,9 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long size, unsigned long block_size, unsigned long display_unit) { /* The code will adjust for additional (appended) units */ - static const char zero_and_units[] ALIGN1 = { '0', 0, 'k', 'M', 'G', 'T' }; + static const char unit_chars[] ALIGN1 = { + '\0', 'K', 'M', 'G', 'T', 'P', 'E' + }; static const char fmt[] ALIGN1 = "%llu"; static const char fmt_tenths[] ALIGN1 = "%llu.%d%c"; @@ -42,26 +46,33 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long size, int frac; const char *u; const char *f; + smallint no_tenths; - u = zero_and_units; - f = fmt; - frac = 0; + if (size == 0) + return "0"; - val = size * block_size; - if (val == 0) { - return u; + /* If block_size is 0 then do not print tenths */ + no_tenths = 0; + if (block_size == 0) { + no_tenths = 1; + block_size = 1; } + u = unit_chars; + val = size * block_size; + f = fmt; + frac = 0; + if (display_unit) { val += display_unit/2; /* Deal with rounding */ val /= display_unit; /* Don't combine with the line above!!! */ + /* will just print it as ulonglong (below) */ } else { - ++u; while ((val >= 1024) - && (u < zero_and_units + sizeof(zero_and_units) - 1) + && (u < unit_chars + sizeof(unit_chars) - 1) ) { f = fmt_tenths; - ++u; + u++; frac = (((int)(val % 1024)) * 10 + 1024/2) / 1024; val /= 1024; } @@ -69,9 +80,9 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long size, ++val; frac = 0; } -#if 0 +#if 1 /* Sample code to omit decimal point and tenths digit. */ - if (/* no_tenths */ 1) { + if (no_tenths) { if (frac >= 5) { ++val; } diff --git a/release/src/router/busybox/libbb/inet_common.c b/release/src/router/busybox/libbb/inet_common.c index 3a20b4a16f..fa4d8672fe 100644 --- a/release/src/router/busybox/libbb/inet_common.c +++ b/release/src/router/busybox/libbb/inet_common.c @@ -5,7 +5,7 @@ * * Heavily modified by Manuel Novoa III Mar 12, 2001 * - * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" @@ -63,9 +63,6 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf #ifdef DEBUG res_init(); _res.options |= RES_DEBUG; -#endif - -#ifdef DEBUG bb_error_msg("gethostbyname(%s)", name); #endif hp = gethostbyname(name); diff --git a/release/src/router/busybox/libbb/info_msg.c b/release/src/router/busybox/libbb/info_msg.c index ffef05e546..8b8a1fcca2 100644 --- a/release/src/router/busybox/libbb/info_msg.c +++ b/release/src/router/busybox/libbb/info_msg.c @@ -12,6 +12,7 @@ void FAST_FUNC bb_info_msg(const char *s, ...) { +#ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE va_list p; /* va_copy is used because it is not portable * to use va_list p twice */ @@ -27,4 +28,29 @@ void FAST_FUNC bb_info_msg(const char *s, ...) vsyslog(LOG_INFO, s, p2); va_end(p2); va_end(p); +#else + int used; + char *msg; + va_list p; + + if (logmode == 0) + return; + + va_start(p, s); + used = vasprintf(&msg, s, p); + if (used < 0) + return; + + if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG)) + syslog(LOG_INFO, "%s", msg); + if (logmode & LOGMODE_STDIO) { + fflush(stdout); + /* used = strlen(msg); - must be true already */ + msg[used++] = '\n'; + full_write(STDOUT_FILENO, msg, used); + } + + free(msg); + va_end(p); +#endif } diff --git a/release/src/router/busybox/libbb/inode_hash.c b/release/src/router/busybox/libbb/inode_hash.c index 4469671ddb..b32bd26bf6 100644 --- a/release/src/router/busybox/libbb/inode_hash.c +++ b/release/src/router/busybox/libbb/inode_hash.c @@ -67,7 +67,7 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char * ino_dev_hashtable[i] = bucket; } -#if ENABLE_FEATURE_CLEAN_UP +#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP /* Clear statbuf hash table */ void FAST_FUNC reset_ino_dev_hashtable(void) { diff --git a/release/src/router/busybox/libbb/lineedit.c b/release/src/router/busybox/libbb/lineedit.c index 2388b3721f..7bcdb954c5 100644 --- a/release/src/router/busybox/libbb/lineedit.c +++ b/release/src/router/busybox/libbb/lineedit.c @@ -954,6 +954,14 @@ static void input_tab(smallint *lastWasTab) #endif /* FEATURE_COMMAND_TAB_COMPLETION */ +line_input_t* FAST_FUNC new_line_input_t(int flags) +{ + line_input_t *n = xzalloc(sizeof(*n)); + n->flags = flags; + return n; +} + + #if MAX_HISTORY > 0 static void save_command_ps_at_cur_history(void) @@ -990,56 +998,128 @@ static int get_next_history(void) } #if ENABLE_FEATURE_EDITING_SAVEHISTORY +/* We try to ensure that concurrent additions to the history + * do not overwrite each other. + * Otherwise shell users get unhappy. + * + * History file is trimmed lazily, when it grows several times longer + * than configured MAX_HISTORY lines. + */ + +static void free_line_input_t(line_input_t *n) +{ + int i = n->cnt_history; + while (i > 0) + free(n->history[--i]); + free(n); +} + /* state->flags is already checked to be nonzero */ -static void load_history(const char *fromfile) +static void load_history(line_input_t *st_parm) { + char *temp_h[MAX_HISTORY]; + char *line; FILE *fp; - int hi; + unsigned idx, i, line_len; /* NB: do not trash old history if file can't be opened */ - fp = fopen_for_read(fromfile); + fp = fopen_for_read(st_parm->hist_file); if (fp) { /* clean up old history */ - for (hi = state->cnt_history; hi > 0;) { - hi--; - free(state->history[hi]); - state->history[hi] = NULL; + for (idx = st_parm->cnt_history; idx > 0;) { + idx--; + free(st_parm->history[idx]); + st_parm->history[idx] = NULL; } - for (hi = 0; hi < MAX_HISTORY;) { - char *hl = xmalloc_fgetline(fp); - int l; - - if (!hl) - break; - l = strlen(hl); - if (l >= MAX_LINELEN) - hl[MAX_LINELEN-1] = '\0'; - if (l == 0) { - free(hl); + /* fill temp_h[], retaining only last MAX_HISTORY lines */ + memset(temp_h, 0, sizeof(temp_h)); + st_parm->cnt_history_in_file = idx = 0; + while ((line = xmalloc_fgetline(fp)) != NULL) { + if (line[0] == '\0') { + free(line); continue; } - state->history[hi++] = hl; + free(temp_h[idx]); + temp_h[idx] = line; + st_parm->cnt_history_in_file++; + idx++; + if (idx == MAX_HISTORY) + idx = 0; } fclose(fp); - state->cnt_history = hi; + + /* find first non-NULL temp_h[], if any */ + if (st_parm->cnt_history_in_file) { + while (temp_h[idx] == NULL) { + idx++; + if (idx == MAX_HISTORY) + idx = 0; + } + } + + /* copy temp_h[] to st_parm->history[] */ + for (i = 0; i < MAX_HISTORY;) { + line = temp_h[idx]; + if (!line) + break; + idx++; + if (idx == MAX_HISTORY) + idx = 0; + line_len = strlen(line); + if (line_len >= MAX_LINELEN) + line[MAX_LINELEN-1] = '\0'; + st_parm->history[i++] = line; + } + st_parm->cnt_history = i; } } /* state->flags is already checked to be nonzero */ -static void save_history(const char *tofile) +static void save_history(char *str) { - FILE *fp; + int fd; + int len, len2; - fp = fopen_for_write(tofile); - if (fp) { + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666); + if (fd < 0) + return; + xlseek(fd, 0, SEEK_END); /* paranoia */ + len = strlen(str); + str[len] = '\n'; /* we (try to) do atomic write */ + len2 = full_write(fd, str, len + 1); + str[len] = '\0'; + close(fd); + if (len2 != len + 1) + return; /* "wtf?" */ + + /* did we write so much that history file needs trimming? */ + state->cnt_history_in_file++; + if (state->cnt_history_in_file > MAX_HISTORY * 4) { + FILE *fp; + char *new_name; + line_input_t *st_temp; int i; - for (i = 0; i < state->cnt_history; i++) { - fprintf(fp, "%s\n", state->history[i]); + /* we may have concurrently written entries from others. + * load them */ + st_temp = new_line_input_t(state->flags); + st_temp->hist_file = state->hist_file; + load_history(st_temp); + + /* write out temp file and replace hist_file atomically */ + new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); + fp = fopen_for_write(new_name); + if (fp) { + for (i = 0; i < st_temp->cnt_history; i++) + fprintf(fp, "%s\n", st_temp->history[i]); + fclose(fp); + if (rename(new_name, state->hist_file) == 0) + state->cnt_history_in_file = st_temp->cnt_history; } - fclose(fp); + free(new_name); + free_line_input_t(st_temp); } } #else @@ -1047,7 +1127,7 @@ static void save_history(const char *tofile) #define save_history(a) ((void)0) #endif /* FEATURE_COMMAND_SAVEHISTORY */ -static void remember_in_history(const char *str) +static void remember_in_history(char *str) { int i; @@ -1078,7 +1158,7 @@ static void remember_in_history(const char *str) state->cnt_history = i; #if ENABLE_FEATURE_EDITING_SAVEHISTORY if ((state->flags & SAVE_HISTORY) && state->hist_file) - save_history(state->hist_file); + save_history(str); #endif USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) } @@ -1413,12 +1493,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li state = st ? st : (line_input_t*) &const_int_0; #if ENABLE_FEATURE_EDITING_SAVEHISTORY if ((state->flags & SAVE_HISTORY) && state->hist_file) - load_history(state->hist_file); + if (state->cnt_history == 0) + load_history(state); #endif -#if MAX_HISTORY > 0 if (state->flags & DO_HISTORY) state->cur_history = state->cnt_history; -#endif /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ @@ -1438,7 +1517,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #define _POSIX_VDISABLE '\0' #endif new_settings.c_cc[VINTR] = _POSIX_VDISABLE; - tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); + tcsetattr_stdin_TCSANOW(&new_settings); /* Now initialize things */ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); @@ -1862,7 +1941,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #endif /* restore initial_settings */ - tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings); + tcsetattr_stdin_TCSANOW(&initial_settings); /* restore SIGWINCH handler */ signal(SIGWINCH, previous_SIGWINCH_handler); fflush(stdout); @@ -1873,13 +1952,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li return len; /* can't return command_len, DEINIT_S() destroys it */ } -line_input_t* FAST_FUNC new_line_input_t(int flags) -{ - line_input_t *n = xzalloc(sizeof(*n)); - n->flags = flags; - return n; -} - #else #undef read_line_input diff --git a/release/src/router/busybox/libbb/llist.c b/release/src/router/busybox/libbb/llist.c index 094c652461..51b1ce6c99 100644 --- a/release/src/router/busybox/libbb/llist.c +++ b/release/src/router/busybox/libbb/llist.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Glenn McGrath * Copyright (C) 2005 Vladimir Oleynik - * Copyright (C) 2005 Bernhard Fischer + * Copyright (C) 2005 Bernhard Reutner-Fischer * Copyright (C) 2006 Rob Landley * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. @@ -25,56 +25,38 @@ void FAST_FUNC llist_add_to(llist_t **old_head, void *data) /* Add data to the end of the linked list. */ void FAST_FUNC llist_add_to_end(llist_t **list_head, void *data) { - llist_t *new_item = xmalloc(sizeof(llist_t)); - - new_item->data = data; - new_item->link = NULL; - - if (!*list_head) - *list_head = new_item; - else { - llist_t *tail = *list_head; - - while (tail->link) - tail = tail->link; - tail->link = new_item; - } + while (*list_head) + list_head = &(*list_head)->link; + *list_head = xzalloc(sizeof(llist_t)); + (*list_head)->data = data; + /*(*list_head)->link = NULL;*/ } /* Remove first element from the list and return it */ void* FAST_FUNC llist_pop(llist_t **head) { - void *data, *next; - - if (!*head) - return NULL; - - data = (*head)->data; - next = (*head)->link; - free(*head); - *head = next; + void *data = NULL; + llist_t *temp = *head; + if (temp) { + data = temp->data; + *head = temp->link; + free(temp); + } return data; } /* Unlink arbitrary given element from the list */ void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm) { - llist_t *crt; - - if (!(elm && *head)) + if (!elm) return; - - if (elm == *head) { - *head = (*head)->link; - return; - } - - for (crt = *head; crt; crt = crt->link) { - if (crt->link == elm) { - crt->link = elm->link; - return; + while (*head) { + if (*head == elm) { + *head = (*head)->link; + break; } + head = &(*head)->link; } } @@ -90,7 +72,6 @@ void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data)) } } -#ifdef UNUSED /* Reverse list order. */ llist_t* FAST_FUNC llist_rev(llist_t *list) { @@ -105,4 +86,13 @@ llist_t* FAST_FUNC llist_rev(llist_t *list) } return rev; } -#endif + +llist_t* FAST_FUNC llist_find_str(llist_t *list, const char *str) +{ + while (list) { + if (strcmp(list->data, str) == 0) + break; + list = list->link; + } + return list; +} diff --git a/release/src/router/busybox/libbb/make_directory.c b/release/src/router/busybox/libbb/make_directory.c index df0b4a13d4..391493cda8 100644 --- a/release/src/router/busybox/libbb/make_directory.c +++ b/release/src/router/busybox/libbb/make_directory.c @@ -71,7 +71,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) } /* Since the directory exists, don't attempt to change * permissions if it was the full target. Note that - * this is not an error conditon. */ + * this is not an error condition. */ if (!c) { umask(mask); return 0; diff --git a/release/src/router/busybox/libbb/match_fstype.c b/release/src/router/busybox/libbb/match_fstype.c index 99e2767848..9360e757a6 100644 --- a/release/src/router/busybox/libbb/match_fstype.c +++ b/release/src/router/busybox/libbb/match_fstype.c @@ -5,40 +5,38 @@ * This allows us to match fstypes that start with no like so * mount -at ,noddy * - * Returns 0 for a match, otherwise -1 + * Returns 1 for a match, otherwise 0 * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ #include "libbb.h" -int FAST_FUNC match_fstype(const struct mntent *mt, const char *fstype) +int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) { - int no = 0; + int match = 1; int len; - if (!mt) - return -1; + if (!t_fstype) + return match; - if (!fstype) - return 0; - - if (fstype[0] == 'n' && fstype[1] == 'o') { - no = -1; - fstype += 2; + if (t_fstype[0] == 'n' && t_fstype[1] == 'o') { + match--; + t_fstype += 2; } len = strlen(mt->mnt_type); - while (fstype) { - if (!strncmp(mt->mnt_type, fstype, len) - && (!fstype[len] || fstype[len] == ',') + while (1) { + if (strncmp(mt->mnt_type, t_fstype, len) == 0 + && (t_fstype[len] == '\0' || t_fstype[len] == ',') ) { - return no; + return match; } - fstype = strchr(fstype, ','); - if (fstype) - fstype++; + t_fstype = strchr(t_fstype, ','); + if (!t_fstype) + break; + t_fstype++; } - return -(no + 1); + return !match; } diff --git a/release/src/router/busybox/libbb/md5.c b/release/src/router/busybox/libbb/md5.c dissimilarity index 64% index 4ab06eb17b..768dfbcb78 100644 --- a/release/src/router/busybox/libbb/md5.c +++ b/release/src/router/busybox/libbb/md5.c @@ -1,446 +1,429 @@ -/* vi: set sw=4 ts=4: */ -/* - * md5.c - Compute MD5 checksum of strings according to the - * definition of MD5 in RFC 1321 from April 1992. - * - * Written by Ulrich Drepper , 1995. - * - * Copyright (C) 1995-1999 Free Software Foundation, Inc. - * Copyright (C) 2001 Manuel Novoa III - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - */ - -#include "libbb.h" - -#if CONFIG_MD5_SIZE_VS_SPEED < 0 || CONFIG_MD5_SIZE_VS_SPEED > 3 -# define MD5_SIZE_VS_SPEED 2 -#else -# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED -#endif - -/* Initialize structure containing state of computation. - * (RFC 1321, 3.3: Step 3) - */ -void FAST_FUNC md5_begin(md5_ctx_t *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->total = 0; - ctx->buflen = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - * and defined in the RFC 1321. The first function is a little bit optimized - * (as found in Colin Plumbs public domain implementation). - * #define FF(b, c, d) ((b & c) | (~b & d)) - */ -# define FF(b, c, d) (d ^ (b & (c ^ d))) -# define FG(b, c, d) FF (d, b, c) -# define FH(b, c, d) (b ^ c ^ d) -# define FI(b, c, d) (c ^ (b | ~d)) - -/* Hash a single block, 64 bytes long and 4-byte aligned. */ -static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) -{ - uint32_t correct_words[16]; - const uint32_t *words = buffer; - -# if MD5_SIZE_VS_SPEED > 0 - static const uint32_t C_array[] = { - /* round 1 */ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - /* round 2 */ - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - /* round 3 */ - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - /* round 4 */ - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - static const char P_array[] ALIGN1 = { -# if MD5_SIZE_VS_SPEED > 1 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ -# endif /* MD5_SIZE_VS_SPEED > 1 */ - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ - }; - -# if MD5_SIZE_VS_SPEED > 1 - static const char S_array[] ALIGN1 = { - 7, 12, 17, 22, - 5, 9, 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21 - }; -# endif /* MD5_SIZE_VS_SPEED > 1 */ -# endif - - uint32_t A = ctx->A; - uint32_t B = ctx->B; - uint32_t C = ctx->C; - uint32_t D = ctx->D; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - uint32_t *cwp = correct_words; - uint32_t A_save = A; - uint32_t B_save = B; - uint32_t C_save = C; - uint32_t D_save = D; - -# if MD5_SIZE_VS_SPEED > 1 -# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - const uint32_t *pc; - const char *pp; - const char *ps; - int i; - uint32_t temp; - - for (i = 0; i < 16; i++) { - cwp[i] = SWAP_LE32(words[i]); - } - words += 16; - -# if MD5_SIZE_VS_SPEED > 2 - pc = C_array; - pp = P_array; - ps = S_array - 4; - - for (i = 0; i < 64; i++) { - if ((i & 0x0f) == 0) - ps += 4; - temp = A; - switch (i >> 4) { - case 0: - temp += FF(B, C, D); - break; - case 1: - temp += FG(B, C, D); - break; - case 2: - temp += FH(B, C, D); - break; - case 3: - temp += FI(B, C, D); - } - temp += cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } -# else - pc = C_array; - pp = P_array; - ps = S_array; - - for (i = 0; i < 16; i++) { - temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - -# endif /* MD5_SIZE_VS_SPEED > 2 */ -# else - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -# define OP(a, b, c, d, s, T) \ - do { \ - a += FF (b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \ - ++words; \ - CYCLIC (a, s); \ - a += b; \ - } while (0) - - /* It is unfortunate that C does not provide an operator for - cyclic rotation. Hope the C compiler is smart enough. */ - /* gcc 2.95.4 seems to be --aaronl */ -# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - -# if MD5_SIZE_VS_SPEED == 1 - const uint32_t *pc; - const char *pp; - int i; -# endif /* MD5_SIZE_VS_SPEED */ - - /* Round 1. */ -# if MD5_SIZE_VS_SPEED == 1 - pc = C_array; - for (i = 0; i < 4; i++) { - OP(A, B, C, D, 7, *pc++); - OP(D, A, B, C, 12, *pc++); - OP(C, D, A, B, 17, *pc++); - OP(B, C, D, A, 22, *pc++); - } -# else - OP(A, B, C, D, 7, 0xd76aa478); - OP(D, A, B, C, 12, 0xe8c7b756); - OP(C, D, A, B, 17, 0x242070db); - OP(B, C, D, A, 22, 0xc1bdceee); - OP(A, B, C, D, 7, 0xf57c0faf); - OP(D, A, B, C, 12, 0x4787c62a); - OP(C, D, A, B, 17, 0xa8304613); - OP(B, C, D, A, 22, 0xfd469501); - OP(A, B, C, D, 7, 0x698098d8); - OP(D, A, B, C, 12, 0x8b44f7af); - OP(C, D, A, B, 17, 0xffff5bb1); - OP(B, C, D, A, 22, 0x895cd7be); - OP(A, B, C, D, 7, 0x6b901122); - OP(D, A, B, C, 12, 0xfd987193); - OP(C, D, A, B, 17, 0xa679438e); - OP(B, C, D, A, 22, 0x49b40821); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -# undef OP -# define OP(f, a, b, c, d, k, s, T) \ - do { \ - a += f (b, c, d) + correct_words[k] + T; \ - CYCLIC (a, s); \ - a += b; \ - } while (0) - - /* Round 2. */ -# if MD5_SIZE_VS_SPEED == 1 - pp = P_array; - for (i = 0; i < 4; i++) { - OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); - OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++); - OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++); - OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++); - } -# else - OP(FG, A, B, C, D, 1, 5, 0xf61e2562); - OP(FG, D, A, B, C, 6, 9, 0xc040b340); - OP(FG, C, D, A, B, 11, 14, 0x265e5a51); - OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP(FG, A, B, C, D, 5, 5, 0xd62f105d); - OP(FG, D, A, B, C, 10, 9, 0x02441453); - OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP(FG, D, A, B, C, 14, 9, 0xc33707d6); - OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP(FG, B, C, D, A, 8, 20, 0x455a14ed); - OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP(FG, C, D, A, B, 7, 14, 0x676f02d9); - OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* Round 3. */ -# if MD5_SIZE_VS_SPEED == 1 - for (i = 0; i < 4; i++) { - OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); - OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); - OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++); - OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++); - } -# else - OP(FH, A, B, C, D, 5, 4, 0xfffa3942); - OP(FH, D, A, B, C, 8, 11, 0x8771f681); - OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP(FH, B, C, D, A, 14, 23, 0xfde5380c); - OP(FH, A, B, C, D, 1, 4, 0xa4beea44); - OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP(FH, B, C, D, A, 6, 23, 0x04881d05); - OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* Round 4. */ -# if MD5_SIZE_VS_SPEED == 1 - for (i = 0; i < 4; i++) { - OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); - OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); - OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++); - OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++); - } -# else - OP(FI, A, B, C, D, 0, 6, 0xf4292244); - OP(FI, D, A, B, C, 7, 10, 0x432aff97); - OP(FI, C, D, A, B, 14, 15, 0xab9423a7); - OP(FI, B, C, D, A, 5, 21, 0xfc93a039); - OP(FI, A, B, C, D, 12, 6, 0x655b59c3); - OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP(FI, C, D, A, B, 10, 15, 0xffeff47d); - OP(FI, B, C, D, A, 1, 21, 0x85845dd1); - OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP(FI, C, D, A, B, 6, 15, 0xa3014314); - OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP(FI, A, B, C, D, 4, 6, 0xf7537e82); - OP(FI, D, A, B, C, 11, 10, 0xbd3af235); - OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP(FI, B, C, D, A, 9, 21, 0xeb86d391); -# endif /* MD5_SIZE_VS_SPEED == 1 */ -# endif /* MD5_SIZE_VS_SPEED > 1 */ - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} - -/* Feed data through a temporary buffer to call md5_hash_aligned_block() - * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. - * This function's internal buffer remembers previous data until it has 64 - * bytes worth to pass on. Call md5_end() to flush this buffer. */ - -void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) -{ - char *buf=(char *)buffer; - - /* RFC 1321 specifies the possible length of the file up to 2^64 bits, - * Here we only track the number of bytes. */ - - ctx->total += len; - - // Process all input. - - while (len) { - unsigned i = 64 - ctx->buflen; - - // Copy data into aligned buffer. - - if (i > len) i = len; - memcpy(ctx->buffer + ctx->buflen, buf, i); - len -= i; - ctx->buflen += i; - buf += i; - - // When buffer fills up, process it. - - if (ctx->buflen == 64) { - md5_hash_block(ctx->buffer, ctx); - ctx->buflen = 0; - } - } -} - -/* Process the remaining bytes in the buffer and put result from CTX - * in first 16 bytes following RESBUF. The result is always in little - * endian byte order, so that a byte-wise output yields to the wanted - * ASCII representation of the message digest. - * - * IMPORTANT: On some systems it is required that RESBUF is correctly - * aligned for a 32 bits value. - */ -void* FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx) -{ - char *buf = ctx->buffer; - int i; - - /* Pad data to block size. */ - - buf[ctx->buflen++] = 0x80; - memset(buf + ctx->buflen, 0, 128 - ctx->buflen); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - ctx->total <<= 3; - if (ctx->buflen > 56) buf += 64; - for (i = 0; i < 8; i++) buf[56 + i] = ctx->total >> (i*8); - - /* Process last bytes. */ - if (buf != ctx->buffer) md5_hash_block(ctx->buffer, ctx); - md5_hash_block(buf, ctx); - - /* Put result from CTX in first 16 bytes following RESBUF. The result is - * always in little endian byte order, so that a byte-wise output yields - * to the wanted ASCII representation of the message digest. - * - * IMPORTANT: On some systems it is required that RESBUF is correctly - * aligned for a 32 bits value. - */ - ((uint32_t *) resbuf)[0] = SWAP_LE32(ctx->A); - ((uint32_t *) resbuf)[1] = SWAP_LE32(ctx->B); - ((uint32_t *) resbuf)[2] = SWAP_LE32(ctx->C); - ((uint32_t *) resbuf)[3] = SWAP_LE32(ctx->D); - - return resbuf; -} - +/* vi: set sw=4 ts=4: */ +/* + * md5.c - Compute MD5 checksum of strings according to the + * definition of MD5 in RFC 1321 from April 1992. + * + * Written by Ulrich Drepper , 1995. + * + * Copyright (C) 1995-1999 Free Software Foundation, Inc. + * Copyright (C) 2001 Manuel Novoa III + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + */ + +#include "libbb.h" + +/* 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 +#else +# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED +#endif + +/* Initialize structure containing state of computation. + * (RFC 1321, 3.3: Step 3) + */ +void FAST_FUNC md5_begin(md5_ctx_t *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + ctx->total = 0; + ctx->buflen = 0; +} + +/* These are the four functions used in the four steps of the MD5 algorithm + * and defined in the RFC 1321. The first function is a little bit optimized + * (as found in Colin Plumbs public domain implementation). + * #define FF(b, c, d) ((b & c) | (~b & d)) + */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF(d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s)))) + +/* Hash a single block, 64 bytes long and 4-byte aligned. */ +static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) +{ + uint32_t correct_words[16]; + const uint32_t *words = buffer; + +#if MD5_SIZE_VS_SPEED > 0 + static const uint32_t C_array[] = { + /* round 1 */ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + /* round 2 */ + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + /* round 3 */ + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + /* round 4 */ + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + static const char P_array[] ALIGN1 = { +# if MD5_SIZE_VS_SPEED > 1 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ +# endif + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ + }; +# if MD5_SIZE_VS_SPEED > 1 + static const char S_array[] ALIGN1 = { + 7, 12, 17, 22, + 5, 9, 14, 20, + 4, 11, 16, 23, + 6, 10, 15, 21 + }; +# endif /* MD5_SIZE_VS_SPEED > 1 */ +#endif + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + +#if MD5_SIZE_VS_SPEED > 1 + const uint32_t *pc; + const char *pp; + const char *ps; + int i; + uint32_t temp; + + for (i = 0; i < 16; i++) + cwp[i] = SWAP_LE32(words[i]); + words += 16; + +# if MD5_SIZE_VS_SPEED > 2 + pc = C_array; + pp = P_array; + ps = S_array - 4; + + for (i = 0; i < 64; i++) { + if ((i & 0x0f) == 0) + ps += 4; + temp = A; + switch (i >> 4) { + case 0: + temp += FF(B, C, D); + break; + case 1: + temp += FG(B, C, D); + break; + case 2: + temp += FH(B, C, D); + break; + case 3: + temp += FI(B, C, D); + } + temp += cwp[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } +# else + pc = C_array; + pp = P_array; + ps = S_array; + + for (i = 0; i < 16; i++) { + temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + +# endif /* MD5_SIZE_VS_SPEED > 2 */ +#else + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ +# define OP(a, b, c, d, s, T) \ + do { \ + a += FF(b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \ + ++words; \ + a = rotl32(a, s); \ + a += b; \ + } while (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 + */ + +# if MD5_SIZE_VS_SPEED == 1 + const uint32_t *pc; + const char *pp; + int i; +# endif /* MD5_SIZE_VS_SPEED */ + + /* Round 1. */ +# if MD5_SIZE_VS_SPEED == 1 + pc = C_array; + for (i = 0; i < 4; i++) { + OP(A, B, C, D, 7, *pc++); + OP(D, A, B, C, 12, *pc++); + OP(C, D, A, B, 17, *pc++); + OP(B, C, D, A, 22, *pc++); + } +# else + OP(A, B, C, D, 7, 0xd76aa478); + OP(D, A, B, C, 12, 0xe8c7b756); + OP(C, D, A, B, 17, 0x242070db); + OP(B, C, D, A, 22, 0xc1bdceee); + OP(A, B, C, D, 7, 0xf57c0faf); + OP(D, A, B, C, 12, 0x4787c62a); + OP(C, D, A, B, 17, 0xa8304613); + OP(B, C, D, A, 22, 0xfd469501); + OP(A, B, C, D, 7, 0x698098d8); + OP(D, A, B, C, 12, 0x8b44f7af); + OP(C, D, A, B, 17, 0xffff5bb1); + OP(B, C, D, A, 22, 0x895cd7be); + OP(A, B, C, D, 7, 0x6b901122); + OP(D, A, B, C, 12, 0xfd987193); + OP(C, D, A, B, 17, 0xa679438e); + OP(B, C, D, A, 22, 0x49b40821); +# endif/* MD5_SIZE_VS_SPEED == 1 */ + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +# undef OP +# define OP(f, a, b, c, d, k, s, T) \ + do { \ + a += f(b, c, d) + correct_words[k] + T; \ + a = rotl32(a, s); \ + a += b; \ + } while (0) + + /* Round 2. */ +# if MD5_SIZE_VS_SPEED == 1 + pp = P_array; + for (i = 0; i < 4; i++) { + OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); + OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++); + OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++); + OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++); + } +# else + OP(FG, A, B, C, D, 1, 5, 0xf61e2562); + OP(FG, D, A, B, C, 6, 9, 0xc040b340); + OP(FG, C, D, A, B, 11, 14, 0x265e5a51); + OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP(FG, A, B, C, D, 5, 5, 0xd62f105d); + OP(FG, D, A, B, C, 10, 9, 0x02441453); + OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP(FG, D, A, B, C, 14, 9, 0xc33707d6); + OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP(FG, B, C, D, A, 8, 20, 0x455a14ed); + OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP(FG, C, D, A, B, 7, 14, 0x676f02d9); + OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); +# endif/* MD5_SIZE_VS_SPEED == 1 */ + + /* Round 3. */ +# if MD5_SIZE_VS_SPEED == 1 + for (i = 0; i < 4; i++) { + OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); + OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); + OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++); + OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++); + } +# else + OP(FH, A, B, C, D, 5, 4, 0xfffa3942); + OP(FH, D, A, B, C, 8, 11, 0x8771f681); + OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP(FH, B, C, D, A, 14, 23, 0xfde5380c); + OP(FH, A, B, C, D, 1, 4, 0xa4beea44); + OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP(FH, B, C, D, A, 6, 23, 0x04881d05); + OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); +# endif/* MD5_SIZE_VS_SPEED == 1 */ + + /* Round 4. */ +# if MD5_SIZE_VS_SPEED == 1 + for (i = 0; i < 4; i++) { + OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); + OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); + OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++); + OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++); + } +# else + OP(FI, A, B, C, D, 0, 6, 0xf4292244); + OP(FI, D, A, B, C, 7, 10, 0x432aff97); + OP(FI, C, D, A, B, 14, 15, 0xab9423a7); + OP(FI, B, C, D, A, 5, 21, 0xfc93a039); + OP(FI, A, B, C, D, 12, 6, 0x655b59c3); + OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP(FI, C, D, A, B, 10, 15, 0xffeff47d); + OP(FI, B, C, D, A, 1, 21, 0x85845dd1); + OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP(FI, C, D, A, B, 6, 15, 0xa3014314); + OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP(FI, A, B, C, D, 4, 6, 0xf7537e82); + OP(FI, D, A, B, C, 11, 10, 0xbd3af235); + OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP(FI, B, C, D, A, 9, 21, 0xeb86d391); +# endif /* MD5_SIZE_VS_SPEED == 1 */ +#endif /* MD5_SIZE_VS_SPEED > 1 */ + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + +/* Feed data through a temporary buffer to call md5_hash_aligned_block() + * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. + * This function's internal buffer remembers previous data until it has 64 + * bytes worth to pass on. Call md5_end() to flush this buffer. */ +void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) +{ + char *buf = (char *)buffer; + + /* RFC 1321 specifies the possible length of the file up to 2^64 bits, + * Here we only track the number of bytes. */ + ctx->total += len; + + /* Process all input. */ + while (len) { + unsigned i = 64 - ctx->buflen; + + /* Copy data into aligned buffer. */ + if (i > len) i = len; + memcpy(ctx->buffer + ctx->buflen, buf, i); + len -= i; + ctx->buflen += i; + buf += i; + + /* When buffer fills up, process it. */ + if (ctx->buflen == 64) { + md5_hash_block(ctx->buffer, ctx); + ctx->buflen = 0; + } + } +} + +/* Process the remaining bytes in the buffer and put result from CTX + * in first 16 bytes following RESBUF. The result is always in little + * endian byte order, so that a byte-wise output yields to the wanted + * ASCII representation of the message digest. + * + * IMPORTANT: On some systems it is required that RESBUF is correctly + * aligned for a 32 bits value. + */ +void FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx) +{ + char *buf = ctx->buffer; + int i; + + /* Pad data to block size. */ + buf[ctx->buflen++] = 0x80; + memset(buf + ctx->buflen, 0, 128 - ctx->buflen); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->total <<= 3; + if (ctx->buflen > 56) + buf += 64; + for (i = 0; i < 8; i++) + buf[56 + i] = ctx->total >> (i*8); + + /* Process last bytes. */ + if (buf != ctx->buffer) + md5_hash_block(ctx->buffer, ctx); + md5_hash_block(buf, ctx); + + /* The MD5 result is in little endian byte order. + * We (ab)use the fact that A-D are consecutive in memory. + */ +#if BB_BIG_ENDIAN + ctx->A = SWAP_LE32(ctx->A); + ctx->B = SWAP_LE32(ctx->B); + ctx->C = SWAP_LE32(ctx->C); + ctx->D = SWAP_LE32(ctx->D); +#endif + memcpy(resbuf, &ctx->A, sizeof(ctx->A) * 4); +} diff --git a/release/src/router/busybox/libbb/md5prime.c b/release/src/router/busybox/libbb/md5prime.c new file mode 100644 index 0000000000..7986f4d292 --- /dev/null +++ b/release/src/router/busybox/libbb/md5prime.c @@ -0,0 +1,460 @@ +/* This file is not used by busybox right now. + * However, the code here seems to be a tiny bit smaller + * than one in md5.c. Need to investigate which one + * is better overall... + * Hint: grep for md5prime to find places where you can switch + * md5.c/md5prime.c + */ + +/* + * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + * + * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $ + * + * This code is the same as the code published by RSA Inc. It has been + * edited for clarity and style only. + * + * ---------------------------------------------------------------------------- + * The md5_crypt() function was taken from freeBSD's libcrypt and contains + * this license: + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * + * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $ + * + * ---------------------------------------------------------------------------- + * On April 19th, 2001 md5_crypt() was modified to make it reentrant + * by Erik Andersen + * + * June 28, 2001 Manuel Novoa III + * + * "Un-inlined" code using loops and static const tables in order to + * reduce generated code size (on i386 from approx 4k to approx 2.5k). + * + * June 29, 2001 Manuel Novoa III + * + * Completely removed static PADDING array. + * + * Reintroduced the loop unrolling in md5_transform and added the + * MD5_SIZE_VS_SPEED option for configurability. Define below as: + * 0 fully unrolled loops + * 1 partially unrolled (4 ops per loop) + * 2 no unrolling -- introduces the need to swap 4 variables (slow) + * 3 no unrolling and all 4 loops merged into one with switch + * in each loop (glacial) + * On i386, sizes are roughly (-Os -fno-builtin): + * 0: 3k 1: 2.5k 2: 2.2k 3: 2k + * + * Since SuSv3 does not require crypt_r, modified again August 7, 2002 + * by Erik Andersen to remove reentrance stuff... + */ + +#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 +#else +# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED +#endif + +#if BB_LITTLE_ENDIAN +#define memcpy32_cpu2le memcpy +#define memcpy32_le2cpu memcpy +#else +/* Encodes input (uint32_t) into output (unsigned char). + * Assumes len is a multiple of 4. */ +static void +memcpy32_cpu2le(unsigned char *output, uint32_t *input, unsigned len) +{ + unsigned i, j; + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = input[i]; + output[j+1] = (input[i] >> 8); + output[j+2] = (input[i] >> 16); + output[j+3] = (input[i] >> 24); + } +} +/* Decodes input (unsigned char) into output (uint32_t). + * Assumes len is a multiple of 4. */ +static void +memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len) +{ + unsigned i, j; + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32_t)input[j]) + | (((uint32_t)input[j+1]) << 8) + | (((uint32_t)input[j+2]) << 16) + | (((uint32_t)input[j+3]) << 24); +} +#endif /* i386 */ + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* rotl32 rotates x left n bits. */ +#define rotl32(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* + * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = rotl32((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = rotl32((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = rotl32((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = rotl32((a), (s)); \ + (a) += (b); \ + } + +/* MD5 basic transformation. Transforms state based on block. */ +static void md5_transform(uint32_t state[4], const unsigned char block[64]) +{ + uint32_t a, b, c, d, x[16]; +#if MD5_SIZE_VS_SPEED > 1 + uint32_t temp; + const unsigned char *ps; + + static const unsigned char S[] = { + 7, 12, 17, 22, + 5, 9, 14, 20, + 4, 11, 16, 23, + 6, 10, 15, 21 + }; +#endif /* MD5_SIZE_VS_SPEED > 1 */ + +#if MD5_SIZE_VS_SPEED > 0 + const uint32_t *pc; + const unsigned char *pp; + int i; + + static const uint32_t C[] = { + /* round 1 */ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + /* round 2 */ + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + /* round 3 */ + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + /* round 4 */ + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + static const unsigned char P[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ + }; + +#endif /* MD5_SIZE_VS_SPEED > 0 */ + + memcpy32_le2cpu(x, block, 64); + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + +#if MD5_SIZE_VS_SPEED > 2 + pc = C; + pp = P; + ps = S - 4; + for (i = 0; i < 64; i++) { + if ((i & 0x0f) == 0) ps += 4; + temp = a; + switch (i>>4) { + case 0: + temp += F(b, c, d); + break; + case 1: + temp += G(b, c, d); + break; + case 2: + temp += H(b, c, d); + break; + case 3: + temp += I(b, c, d); + break; + } + temp += x[*pp++] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += b; + a = d; d = c; c = b; b = temp; + } +#elif MD5_SIZE_VS_SPEED > 1 + pc = C; + pp = P; + ps = S; + /* Round 1 */ + for (i = 0; i < 16; i++) { + FF(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; + temp = d; d = c; c = b; b = a; a = temp; + } + /* Round 2 */ + ps += 4; + for (; i < 32; i++) { + GG(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; + temp = d; d = c; c = b; b = a; a = temp; + } + /* Round 3 */ + ps += 4; + for (; i < 48; i++) { + HH(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; + temp = d; d = c; c = b; b = a; a = temp; + } + /* Round 4 */ + ps += 4; + for (; i < 64; i++) { + II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; + temp = d; d = c; c = b; b = a; a = temp; + } +#elif MD5_SIZE_VS_SPEED > 0 + pc = C; + pp = P; + /* Round 1 */ + for (i = 0; i < 4; i++) { + FF(a, b, c, d, x[*pp], 7, *pc); pp++; pc++; + FF(d, a, b, c, x[*pp], 12, *pc); pp++; pc++; + FF(c, d, a, b, x[*pp], 17, *pc); pp++; pc++; + FF(b, c, d, a, x[*pp], 22, *pc); pp++; pc++; + } + /* Round 2 */ + for (i = 0; i < 4; i++) { + GG(a, b, c, d, x[*pp], 5, *pc); pp++; pc++; + GG(d, a, b, c, x[*pp], 9, *pc); pp++; pc++; + GG(c, d, a, b, x[*pp], 14, *pc); pp++; pc++; + GG(b, c, d, a, x[*pp], 20, *pc); pp++; pc++; + } + /* Round 3 */ + for (i = 0; i < 4; i++) { + HH(a, b, c, d, x[*pp], 4, *pc); pp++; pc++; + HH(d, a, b, c, x[*pp], 11, *pc); pp++; pc++; + HH(c, d, a, b, x[*pp], 16, *pc); pp++; pc++; + HH(b, c, d, a, x[*pp], 23, *pc); pp++; pc++; + } + /* Round 4 */ + for (i = 0; i < 4; i++) { + II(a, b, c, d, x[*pp], 6, *pc); pp++; pc++; + II(d, a, b, c, x[*pp], 10, *pc); pp++; pc++; + II(c, d, a, b, x[*pp], 15, *pc); pp++; pc++; + II(b, c, d, a, x[*pp], 21, *pc); pp++; pc++; + } +#else + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ +#endif + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); +} + + +/* MD5 initialization. */ +void FAST_FUNC md5_begin(md5_ctx_t *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + * MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating + * the context. + */ +void FAST_FUNC md5_hash(const void *buffer, size_t inputLen, md5_ctx_t *context) +{ + unsigned i, idx, partLen; + const unsigned char *input = buffer; + + /* Compute number of bytes mod 64 */ + idx = (context->count[0] >> 3) & 0x3F; + + /* Update number of bits */ + context->count[0] += (inputLen << 3); + if (context->count[0] < (inputLen << 3)) + context->count[1]++; + context->count[1] += (inputLen >> 29); + + /* Transform as many times as possible. */ + i = 0; + partLen = 64 - idx; + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + md5_transform(context->state, context->buffer); + for (i = partLen; i + 63 < inputLen; i += 64) + md5_transform(context->state, &input[i]); + idx = 0; + } + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, + * writing the message digest. + */ +void FAST_FUNC md5_end(void *digest, md5_ctx_t *context) +{ + unsigned idx, padLen; + unsigned char bits[8]; + unsigned char padding[64]; + + /* Add padding followed by original length. */ + memset(padding, 0, sizeof(padding)); + padding[0] = 0x80; + /* save number of bits */ + memcpy32_cpu2le(bits, context->count, 8); + /* pad out to 56 mod 64 */ + idx = (context->count[0] >> 3) & 0x3f; + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + md5_hash(padding, padLen, context); + /* append length (before padding) */ + md5_hash(bits, 8, context); + + /* Store state in digest */ + memcpy32_cpu2le(digest, context->state, 16); +} diff --git a/release/src/router/busybox/libbb/parse_config.c b/release/src/router/busybox/libbb/parse_config.c index a0599d4b45..74f0524e53 100644 --- a/release/src/router/busybox/libbb/parse_config.c +++ b/release/src/router/busybox/libbb/parse_config.c @@ -5,11 +5,12 @@ * Copyright (C) 2008 by Vladimir Dronnikov * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later. */ #include "libbb.h" -#if ENABLE_PARSE +#if defined ENABLE_PARSE && ENABLE_PARSE int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int parse_main(int argc UNUSED_PARAM, char **argv) { diff --git a/release/src/router/busybox/libbb/process_escape_sequence.c b/release/src/router/busybox/libbb/process_escape_sequence.c index 4d03bd61f3..6de2cacddc 100644 --- a/release/src/router/busybox/libbb/process_escape_sequence.c +++ b/release/src/router/busybox/libbb/process_escape_sequence.c @@ -18,17 +18,20 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) { + /* bash builtin "echo -e '\ec'" interprets \e as ESC, + * but coreutils "/bin/echo -e '\ec'" does not. + * manpages tend to support coreutils way. */ static const char charmap[] ALIGN1 = { - 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0, - '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; + 'a', 'b', /*'e',*/ 'f', 'n', 'r', 't', 'v', '\\', 0, + '\a', '\b', /*27,*/ '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; const char *p; const char *q; - unsigned int num_digits; - unsigned int r; - unsigned int n; - unsigned int d; - unsigned int base; + unsigned num_digits; + unsigned r; + unsigned n; + unsigned d; + unsigned base; num_digits = n = 0; base = 8; diff --git a/release/src/router/busybox/libbb/procps.c b/release/src/router/busybox/libbb/procps.c index fd19621db0..c5e40bf885 100644 --- a/release/src/router/busybox/libbb/procps.c +++ b/release/src/router/busybox/libbb/procps.c @@ -13,7 +13,7 @@ typedef struct unsigned_to_name_map_t { - unsigned id; + long id; char name[USERNAME_MAX_SIZE]; } unsigned_to_name_map_t; @@ -52,8 +52,8 @@ static int get_cached(cache_t *cp, unsigned id) } #endif -typedef char* FAST_FUNC ug_func(char *name, int bufsize, long uid); -static char* get_cached(cache_t *cp, unsigned id, ug_func* fp) +static char* get_cached(cache_t *cp, long id, + char* FAST_FUNC x2x_utoa(long id)) { int i; for (i = 0; i < cp->size; i++) @@ -63,16 +63,16 @@ static char* get_cached(cache_t *cp, unsigned id, ug_func* fp) cp->cache = xrealloc_vector(cp->cache, 2, i); cp->cache[i].id = id; /* Never fails. Generates numeric string if name isn't found */ - fp(cp->cache[i].name, sizeof(cp->cache[i].name), id); + safe_strncpy(cp->cache[i].name, x2x_utoa(id), sizeof(cp->cache[i].name)); return cp->cache[i].name; } const char* FAST_FUNC get_cached_username(uid_t uid) { - return get_cached(&username, uid, bb_getpwuid); + return get_cached(&username, uid, uid2uname_utoa); } const char* FAST_FUNC get_cached_groupname(gid_t gid) { - return get_cached(&groupname, gid, bb_getgrgid); + return get_cached(&groupname, gid, gid2group_utoa); } @@ -219,7 +219,6 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) #if !ENABLE_FEATURE_FAST_TOP unsigned long vsz, rss; #endif - /* see proc(5) for some details on this */ strcpy(filename_tail, "/stat"); n = read_to_buf(filename, buf); @@ -247,9 +246,12 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) "%lu " /* start_time */ "%lu " /* vsize */ "%lu " /* rss */ - /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ - /* "%u %u %u %u " signal, blocked, sigignore, sigcatch */ - /* "%lu %lu %lu" wchan, nswap, cnswap */ +#if ENABLE_FEATURE_TOP_SMP_PROCESS + "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ + "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ + "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ + "%d" /*cpu last seen on*/ +#endif , sp->state, &sp->ppid, &sp->pgid, &sp->sid, &tty, @@ -257,9 +259,19 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) &tasknice, &sp->start_time, &vsz, - &rss); - if (n != 11) + &rss +#if ENABLE_FEATURE_TOP_SMP_PROCESS + , &sp->last_seen_on_cpu +#endif + ); + + if (n < 11) break; +#if ENABLE_FEATURE_TOP_SMP_PROCESS + if (n < 11+15) + sp->last_seen_on_cpu = 0; +#endif + /* vsz is in bytes and we want kb */ sp->vsz = vsz >> 10; /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ @@ -288,7 +300,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) sp->vsz = fast_strtoul_10(&cp) >> 10; /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; +#if ENABLE_FEATURE_TOP_SMP_PROCESS + /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ + /* (4): signal, blocked, sigignore, sigcatch */ + /* (4): wchan, nswap, cnswap, exit_signal */ + cp = skip_fields(cp, 14); +//FIXME: is it safe to assume this field exists? + sp->last_seen_on_cpu = fast_strtoul_10(&cp); #endif +#endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ if (sp->vsz == 0 && sp->state[0] != 'Z') sp->state[1] = 'W'; @@ -300,7 +320,6 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) sp->state[2] = 'N'; else sp->state[2] = ' '; - } #if ENABLE_FEATURE_TOPMEM diff --git a/release/src/router/busybox/libbb/pw_encrypt.c b/release/src/router/busybox/libbb/pw_encrypt.c index 469e71f6cc..6fc0ba87c7 100644 --- a/release/src/router/busybox/libbb/pw_encrypt.c +++ b/release/src/router/busybox/libbb/pw_encrypt.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Utility routine. + * Utility routines. * * Copyright (C) 1999-2004 by Erik Andersen * @@ -9,17 +9,70 @@ #include "libbb.h" +/* static const uint8_t ascii64[] = + * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + */ + +static int i64c(int i) +{ + i &= 0x3f; + if (i == 0) + return '.'; + if (i == 1) + return '/'; + if (i < 12) + return ('0' - 2 + i); + if (i < 38) + return ('A' - 12 + i); + return ('a' - 38 + i); +} + +int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) +{ + x += getpid() + time(NULL); + do { + /* x = (x*1664525 + 1013904223) % 2^32 generator is lame + * (low-order bit is not "random", etc...), + * but for our purposes it is good enough */ + x = x*1664525 + 1013904223; + /* BTW, Park and Miller's "minimal standard generator" is + * x = x*16807 % ((2^31)-1) + * It has no problem with visibly alternating lowest bit + * but is also weak in cryptographic sense + needs div, + * which needs more code (and slower) on many CPUs */ + *p++ = i64c(x >> 16); + *p++ = i64c(x >> 22); + } while (--cnt); + *p = '\0'; + return x; +} + #if ENABLE_USE_BB_CRYPT +static char* +to64(char *s, unsigned v, int n) +{ + while (--n >= 0) { + /* *s++ = ascii64[v & 0x3f]; */ + *s++ = i64c(v); + v >>= 6; + } + return s; +} + /* * DES and MD5 crypt implementations are taken from uclibc. * They were modified to not use static buffers. */ -/* Common for them */ -static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + #include "pw_encrypt_des.c" #include "pw_encrypt_md5.c" +#if ENABLE_USE_BB_CRYPT_SHA +#include "pw_encrypt_sha.c" +#endif +/* Other advanced crypt ids (TODO?): */ +/* $2$ or $2a$: Blowfish */ static struct const_des_ctx *des_cctx; static struct des_ctx *des_ctx; @@ -27,18 +80,20 @@ static struct des_ctx *des_ctx; /* my_crypt returns malloc'ed data */ static char *my_crypt(const char *key, const char *salt) { - /* First, check if we are supposed to be using the MD5 replacement - * instead of DES... */ - if (salt[0] == '$' && salt[1] == '1' && salt[2] == '$') { - return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); + /* MD5 or SHA? */ + if (salt[0] == '$' && salt[1] && salt[2] == '$') { + if (salt[1] == '1') + return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); +#if ENABLE_USE_BB_CRYPT_SHA + if (salt[1] == '5' || salt[1] == '6') + return sha_crypt((char*)key, (char*)salt); +#endif } - { - if (!des_cctx) - des_cctx = const_des_init(); - des_ctx = des_init(des_ctx, des_cctx); - return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); - } + if (!des_cctx) + des_cctx = const_des_init(); + des_ctx = des_init(des_ctx, des_cctx); + return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); } /* So far nobody wants to have it public */ @@ -54,12 +109,6 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) { char *encrypted; -#if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */ - if (strncmp(salt, "$2$", 3) == 0) { - return sha1_crypt(clear); - } -#endif - encrypted = my_crypt(clear, salt); if (cleanup) @@ -72,12 +121,6 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) { -#if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */ - if (strncmp(salt, "$2$", 3) == 0) { - return xstrdup(sha1_crypt(clear)); - } -#endif - return xstrdup(crypt(clear, salt)); } diff --git a/release/src/router/busybox/libbb/pw_encrypt_des.c b/release/src/router/busybox/libbb/pw_encrypt_des.c index cd19a63f78..52548d6239 100644 --- a/release/src/router/busybox/libbb/pw_encrypt_des.c +++ b/release/src/router/busybox/libbb/pw_encrypt_des.c @@ -696,13 +696,28 @@ do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, u #define DES_OUT_BUFSIZE 21 +static void +to64_msb_first(char *s, unsigned v) +{ +#if 0 + *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */ + *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */ + *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */ + *s = ascii64[v & 0x3f]; /* bits 5..0 */ +#endif + *s++ = i64c(v >> 18); /* bits 23..18 */ + *s++ = i64c(v >> 12); /* bits 17..12 */ + *s++ = i64c(v >> 6); /* bits 11..6 */ + *s = i64c(v); /* bits 5..0 */ +} + static char * NOINLINE des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], const unsigned char *key, const unsigned char *setting) { - uint32_t salt, l, r0, r1, keybuf[2]; - uint8_t *p, *q; + uint32_t salt, r0, r1, keybuf[2]; + uint8_t *q; /* * Copy the key, shifting each character up by one bit @@ -733,34 +748,39 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], */ output[1] = setting[1] ? setting[1] : output[0]; - p = (uint8_t *)output + 2; - setup_salt(ctx, salt); - /* - * Do it. - */ + /* Do it. */ do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); - /* - * Now encode the result... - */ - l = (r0 >> 8); - *p++ = ascii64[(l >> 18) & 0x3f]; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - + /* Now encode the result. */ +#if 0 +{ + uint32_t l = (r0 >> 8); + q = (uint8_t *)output + 2; + *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */ + *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */ + *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */ + *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */ l = ((r0 << 16) | (r1 >> 16)); - *p++ = ascii64[(l >> 18) & 0x3f]; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - + *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */ + *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */ + *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */ + *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */ l = r1 << 2; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - *p = 0; + *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */ + *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */ + *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */ + *q = 0; +} +#else + /* Each call takes low-order 24 bits and stores 4 chars */ + /* bits 31..8 of r0 */ + to64_msb_first(output + 2, (r0 >> 8)); + /* bits 7..0 of r0 and 31..16 of r1 */ + to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); + /* (bits 15..0 of r1 + 00) and NUL byte */ + to64_msb_first(output + 10, (r1 << 8)); +#endif return output; } diff --git a/release/src/router/busybox/libbb/pw_encrypt_md5.c b/release/src/router/busybox/libbb/pw_encrypt_md5.c dissimilarity index 79% index 8d0a516cf9..58964b5676 100644 --- a/release/src/router/busybox/libbb/pw_encrypt_md5.c +++ b/release/src/router/busybox/libbb/pw_encrypt_md5.c @@ -1,648 +1,161 @@ -/* - * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - * - * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All - * rights reserved. - * - * License to copy and use this software is granted provided that it - * is identified as the "RSA Data Security, Inc. MD5 Message-Digest - * Algorithm" in all material mentioning or referencing this software - * or this function. - * - * License is also granted to make and use derivative works provided - * that such works are identified as "derived from the RSA Data - * Security, Inc. MD5 Message-Digest Algorithm" in all material - * mentioning or referencing the derived work. - * - * RSA Data Security, Inc. makes no representations concerning either - * the merchantability of this software or the suitability of this - * software for any particular purpose. It is provided "as is" - * without express or implied warranty of any kind. - * - * These notices must be retained in any copies of any part of this - * documentation and/or software. - * - * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $ - * - * This code is the same as the code published by RSA Inc. It has been - * edited for clarity and style only. - * - * ---------------------------------------------------------------------------- - * The md5_crypt() function was taken from freeBSD's libcrypt and contains - * this license: - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * - * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $ - * - * ---------------------------------------------------------------------------- - * On April 19th, 2001 md5_crypt() was modified to make it reentrant - * by Erik Andersen - * - * - * June 28, 2001 Manuel Novoa III - * - * "Un-inlined" code using loops and static const tables in order to - * reduce generated code size (on i386 from approx 4k to approx 2.5k). - * - * June 29, 2001 Manuel Novoa III - * - * Completely removed static PADDING array. - * - * Reintroduced the loop unrolling in MD5_Transform and added the - * MD5_SIZE_OVER_SPEED option for configurability. Define below as: - * 0 fully unrolled loops - * 1 partially unrolled (4 ops per loop) - * 2 no unrolling -- introduces the need to swap 4 variables (slow) - * 3 no unrolling and all 4 loops merged into one with switch - * in each loop (glacial) - * On i386, sizes are roughly (-Os -fno-builtin): - * 0: 3k 1: 2.5k 2: 2.2k 3: 2k - * - * - * Since SuSv3 does not require crypt_r, modified again August 7, 2002 - * by Erik Andersen to remove reentrance stuff... - */ - -/* - * Valid values are 1 (fastest/largest) to 3 (smallest/slowest). - */ -#define MD5_SIZE_OVER_SPEED 3 - -/**********************************************************************/ - -/* MD5 context. */ -struct MD5Context { - uint32_t state[4]; /* state (ABCD) */ - uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -static void __md5_Init(struct MD5Context *); -static void __md5_Update(struct MD5Context *, const unsigned char *, unsigned int); -static void __md5_Pad(struct MD5Context *); -static void __md5_Final(unsigned char [16], struct MD5Context *); -static void __md5_Transform(uint32_t [4], const unsigned char [64]); - - -#define MD5_MAGIC_STR "$1$" -#define MD5_MAGIC_LEN (sizeof(MD5_MAGIC_STR) - 1) -static const unsigned char __md5__magic[] = MD5_MAGIC_STR; - - -#ifdef i386 -#define __md5_Encode memcpy -#define __md5_Decode memcpy -#else /* i386 */ - -/* - * __md5_Encodes input (uint32_t) into output (unsigned char). Assumes len is - * a multiple of 4. - */ -static void -__md5_Encode(unsigned char *output, uint32_t *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = input[i]; - output[j+1] = (input[i] >> 8); - output[j+2] = (input[i] >> 16); - output[j+3] = (input[i] >> 24); - } -} - -/* - * __md5_Decodes input (unsigned char) into output (uint32_t). Assumes len is - * a multiple of 4. - */ -static void -__md5_Decode(uint32_t *output, const unsigned char *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | - (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); -} -#endif /* i386 */ - -/* F, G, H and I are basic MD5 functions. */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) - -/* ROTATE_LEFT rotates x left n bits. */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* - * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - * Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. */ -static void __md5_Init(struct MD5Context *context) -{ - context->count[0] = context->count[1] = 0; - - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* - * MD5 block update operation. Continues an MD5 message-digest - * operation, processing another message block, and updating the - * context. - */ -static void __md5_Update(struct MD5Context *context, const unsigned char *input, unsigned int inputLen) -{ - unsigned int i, idx, partLen; - - /* Compute number of bytes mod 64 */ - idx = (context->count[0] >> 3) & 0x3F; - - /* Update number of bits */ - context->count[0] += (inputLen << 3); - if (context->count[0] < (inputLen << 3)) - context->count[1]++; - context->count[1] += (inputLen >> 29); - - partLen = 64 - idx; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) { - memcpy(&context->buffer[idx], input, partLen); - __md5_Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - __md5_Transform(context->state, &input[i]); - - idx = 0; - } else - i = 0; - - /* Buffer remaining input */ - memcpy(&context->buffer[idx], &input[i], inputLen - i); -} - -/* - * MD5 padding. Adds padding followed by original length. - */ -static void __md5_Pad(struct MD5Context *context) -{ - unsigned char bits[8]; - unsigned int idx, padLen; - unsigned char PADDING[64]; - - memset(PADDING, 0, sizeof(PADDING)); - PADDING[0] = 0x80; - - /* Save number of bits */ - __md5_Encode(bits, context->count, 8); - - /* Pad out to 56 mod 64. */ - idx = (context->count[0] >> 3) & 0x3f; - padLen = (idx < 56) ? (56 - idx) : (120 - idx); - __md5_Update(context, PADDING, padLen); - - /* Append length (before padding) */ - __md5_Update(context, bits, 8); -} - -/* - * MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -static void __md5_Final(unsigned char digest[16], struct MD5Context *context) -{ - /* Do padding. */ - __md5_Pad(context); - - /* Store state in digest */ - __md5_Encode(digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset(context, 0, sizeof(*context)); -} - -/* MD5 basic transformation. Transforms state based on block. */ -static void __md5_Transform(uint32_t state[4], const unsigned char block[64]) -{ - uint32_t a, b, c, d, x[16]; -#if MD5_SIZE_OVER_SPEED > 1 - uint32_t temp; - const unsigned char *ps; - - static const unsigned char S[] = { - 7, 12, 17, 22, - 5, 9, 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21 - }; -#endif /* MD5_SIZE_OVER_SPEED > 1 */ - -#if MD5_SIZE_OVER_SPEED > 0 - const uint32_t *pc; - const unsigned char *pp; - int i; - - static const uint32_t C[] = { - /* round 1 */ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - /* round 2 */ - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - /* round 3 */ - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - /* round 4 */ - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - static const unsigned char P[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ - }; - -#endif /* MD5_SIZE_OVER_SPEED > 0 */ - - __md5_Decode(x, block, 64); - - a = state[0]; b = state[1]; c = state[2]; d = state[3]; - -#if MD5_SIZE_OVER_SPEED > 2 - pc = C; pp = P; ps = S - 4; - - for (i = 0; i < 64; i++) { - if ((i & 0x0f) == 0) ps += 4; - temp = a; - switch (i>>4) { - case 0: - temp += F(b, c, d); - break; - case 1: - temp += G(b, c, d); - break; - case 2: - temp += H(b, c, d); - break; - case 3: - temp += I(b, c, d); - break; - } - temp += x[*pp++] + *pc++; - temp = ROTATE_LEFT(temp, ps[i & 3]); - temp += b; - a = d; d = c; c = b; b = temp; - } -#elif MD5_SIZE_OVER_SPEED > 1 - pc = C; pp = P; ps = S; - - /* Round 1 */ - for (i = 0; i < 16; i++) { - FF(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; - temp = d; d = c; c = b; b = a; a = temp; - } - - /* Round 2 */ - ps += 4; - for (; i < 32; i++) { - GG(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; - temp = d; d = c; c = b; b = a; a = temp; - } - /* Round 3 */ - ps += 4; - for (; i < 48; i++) { - HH(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; - temp = d; d = c; c = b; b = a; a = temp; - } - - /* Round 4 */ - ps += 4; - for (; i < 64; i++) { - II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; - temp = d; d = c; c = b; b = a; a = temp; - } -#elif MD5_SIZE_OVER_SPEED > 0 - pc = C; pp = P; - - /* Round 1 */ - for (i = 0; i < 4; i++) { - FF(a, b, c, d, x[*pp], 7, *pc); pp++; pc++; - FF(d, a, b, c, x[*pp], 12, *pc); pp++; pc++; - FF(c, d, a, b, x[*pp], 17, *pc); pp++; pc++; - FF(b, c, d, a, x[*pp], 22, *pc); pp++; pc++; - } - - /* Round 2 */ - for (i = 0; i < 4; i++) { - GG(a, b, c, d, x[*pp], 5, *pc); pp++; pc++; - GG(d, a, b, c, x[*pp], 9, *pc); pp++; pc++; - GG(c, d, a, b, x[*pp], 14, *pc); pp++; pc++; - GG(b, c, d, a, x[*pp], 20, *pc); pp++; pc++; - } - /* Round 3 */ - for (i = 0; i < 4; i++) { - HH(a, b, c, d, x[*pp], 4, *pc); pp++; pc++; - HH(d, a, b, c, x[*pp], 11, *pc); pp++; pc++; - HH(c, d, a, b, x[*pp], 16, *pc); pp++; pc++; - HH(b, c, d, a, x[*pp], 23, *pc); pp++; pc++; - } - - /* Round 4 */ - for (i = 0; i < 4; i++) { - II(a, b, c, d, x[*pp], 6, *pc); pp++; pc++; - II(d, a, b, c, x[*pp], 10, *pc); pp++; pc++; - II(c, d, a, b, x[*pp], 15, *pc); pp++; pc++; - II(b, c, d, a, x[*pp], 21, *pc); pp++; pc++; - } -#else - /* Round 1 */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 - FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 - GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 - HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ -#endif - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset(x, 0, sizeof(x)); -} - - -static char* -__md5_to64(char *s, unsigned v, int n) -{ - while (--n >= 0) { - *s++ = ascii64[v & 0x3f]; - v >>= 6; - } - return s; -} - -/* - * UNIX password - * - * Use MD5 for what it is best at... - */ -#define MD5_OUT_BUFSIZE 36 -static char * -NOINLINE -md5_crypt(char passwd[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt) -{ - const unsigned char *sp, *ep; - char *p; - unsigned char final[17]; /* final[16] exists only to aid in looping */ - int sl, pl, i, pw_len; - struct MD5Context ctx, ctx1; - - /* Refine the Salt first */ - sp = salt; - -// always true for bbox -// /* If it starts with the magic string, then skip that */ -// if (!strncmp(sp, __md5__magic, MD5_MAGIC_LEN)) - sp += MD5_MAGIC_LEN; - - /* It stops at the first '$', max 8 chars */ - for (ep = sp; *ep && *ep != '$' && ep < (sp+8); ep++) - continue; - - /* get the length of the true salt */ - sl = ep - sp; - - __md5_Init(&ctx); - - /* The password first, since that is what is most unknown */ - pw_len = strlen((char*)pw); - __md5_Update(&ctx, pw, pw_len); - - /* Then our magic string */ - __md5_Update(&ctx, __md5__magic, MD5_MAGIC_LEN); - - /* Then the raw salt */ - __md5_Update(&ctx, sp, sl); - - /* Then just as many characters of the MD5(pw, salt, pw) */ - __md5_Init(&ctx1); - __md5_Update(&ctx1, pw, pw_len); - __md5_Update(&ctx1, sp, sl); - __md5_Update(&ctx1, pw, pw_len); - __md5_Final(final, &ctx1); - for (pl = pw_len; pl > 0; pl -= 16) - __md5_Update(&ctx, final, pl > 16 ? 16 : pl); - - /* Don't leave anything around in vm they could use. */ -//TODO: the above comment seems to be wrong. final is used later. - memset(final, 0, sizeof(final)); - - /* Then something really weird... */ - for (i = pw_len; i; i >>= 1) { - __md5_Update(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1); - } - - /* Now make the output string */ - passwd[0] = '$'; - passwd[1] = '1'; - passwd[2] = '$'; - strncpy(passwd + 3, (char*)sp, sl); - passwd[sl + 3] = '$'; - - __md5_Final(final, &ctx); - - /* - * and now, just to make sure things don't run too fast - * On a 60 Mhz Pentium this takes 34 msec, so you would - * need 30 seconds to build a 1000 entry dictionary... - */ - for (i = 0; i < 1000; i++) { - __md5_Init(&ctx1); - if (i & 1) - __md5_Update(&ctx1, pw, pw_len); - else - __md5_Update(&ctx1, final, 16); - - if (i % 3) - __md5_Update(&ctx1, sp, sl); - - if (i % 7) - __md5_Update(&ctx1, pw, pw_len); - - if (i & 1) - __md5_Update(&ctx1, final, 16); - else - __md5_Update(&ctx1, pw, pw_len); - __md5_Final(final, &ctx1); - } - - p = passwd + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */ - - /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */ - final[16] = final[5]; - for (i = 0; i < 5; i++) { - unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; - p = __md5_to64(p, l, 4); - } - p = __md5_to64(p, final[11], 2); - *p = '\0'; - - /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof(final)); - - return passwd; -} - -#undef MD5_SIZE_OVER_SPEED -#undef MD5_MAGIC_STR -#undef MD5_MAGIC_LEN -#undef __md5_Encode -#undef __md5_Decode -#undef F -#undef G -#undef H -#undef I -#undef ROTATE_LEFT -#undef FF -#undef GG -#undef HH -#undef II -#undef S11 -#undef S12 -#undef S13 -#undef S14 -#undef S21 -#undef S22 -#undef S23 -#undef S24 -#undef S31 -#undef S32 -#undef S33 -#undef S34 -#undef S41 -#undef S42 -#undef S43 -#undef S44 +/* + * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + * + * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $ + * + * This code is the same as the code published by RSA Inc. It has been + * edited for clarity and style only. + * + * ---------------------------------------------------------------------------- + * The md5_crypt() function was taken from freeBSD's libcrypt and contains + * this license: + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * + * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $ + * + * ---------------------------------------------------------------------------- + * On April 19th, 2001 md5_crypt() was modified to make it reentrant + * by Erik Andersen + * + * + * June 28, 2001 Manuel Novoa III + * + * "Un-inlined" code using loops and static const tables in order to + * reduce generated code size (on i386 from approx 4k to approx 2.5k). + * + * June 29, 2001 Manuel Novoa III + * + * Completely removed static PADDING array. + * + * Reintroduced the loop unrolling in MD5_Transform and added the + * MD5_SIZE_OVER_SPEED option for configurability. Define below as: + * 0 fully unrolled loops + * 1 partially unrolled (4 ops per loop) + * 2 no unrolling -- introduces the need to swap 4 variables (slow) + * 3 no unrolling and all 4 loops merged into one with switch + * in each loop (glacial) + * On i386, sizes are roughly (-Os -fno-builtin): + * 0: 3k 1: 2.5k 2: 2.2k 3: 2k + * + * Since SuSv3 does not require crypt_r, modified again August 7, 2002 + * by Erik Andersen to remove reentrance stuff... + */ + +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ +#define MD5_OUT_BUFSIZE 36 +static char * +NOINLINE +md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt) +{ + char *p; + unsigned char final[17]; /* final[16] exists only to aid in looping */ + int sl, pl, i, pw_len; + md5_ctx_t ctx, ctx1; + + /* NB: in busybox, "$1$" in salt is always present */ + + /* Refine the Salt first */ + + /* Get the length of the salt including "$1$" */ + sl = 3; + while (salt[sl] && salt[sl] != '$' && sl < (3 + 8)) + sl++; + + /* Hash. the password first, since that is what is most unknown */ + md5_begin(&ctx); + pw_len = strlen((char*)pw); + md5_hash(pw, pw_len, &ctx); + + /* Then the salt including "$1$" */ + md5_hash(salt, sl, &ctx); + + /* Copy salt to result; skip "$1$" */ + memcpy(result, salt, sl); + result[sl] = '$'; + salt += 3; + sl -= 3; + + /* Then just as many characters of the MD5(pw, salt, pw) */ + md5_begin(&ctx1); + md5_hash(pw, pw_len, &ctx1); + md5_hash(salt, sl, &ctx1); + md5_hash(pw, pw_len, &ctx1); + md5_end(final, &ctx1); + for (pl = pw_len; pl > 0; pl -= 16) + md5_hash(final, pl > 16 ? 16 : pl, &ctx); + + /* Then something really weird... */ + memset(final, 0, sizeof(final)); + for (i = pw_len; i; i >>= 1) { + md5_hash(((i & 1) ? final : (const unsigned char *) pw), 1, &ctx); + } + md5_end(final, &ctx); + + /* And now, just to make sure things don't run too fast. + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + md5_begin(&ctx1); + if (i & 1) + md5_hash(pw, pw_len, &ctx1); + else + md5_hash(final, 16, &ctx1); + + if (i % 3) + md5_hash(salt, sl, &ctx1); + + if (i % 7) + md5_hash(pw, pw_len, &ctx1); + + if (i & 1) + md5_hash(final, 16, &ctx1); + else + md5_hash(pw, pw_len, &ctx1); + md5_end(final, &ctx1); + } + + p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */ + + /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */ + final[16] = final[5]; + for (i = 0; i < 5; i++) { + unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; + p = to64(p, l, 4); + } + p = to64(p, final[11], 2); + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof(final)); + + return result; +} diff --git a/release/src/router/busybox/libbb/pw_encrypt_sha.c b/release/src/router/busybox/libbb/pw_encrypt_sha.c new file mode 100644 index 0000000000..070e0d442c --- /dev/null +++ b/release/src/router/busybox/libbb/pw_encrypt_sha.c @@ -0,0 +1,286 @@ +/* SHA256 and SHA512-based Unix crypt implementation. + * Released into the Public Domain by Ulrich Drepper . + */ + +/* Prefix for optional rounds specification. */ +static const char str_rounds[] = "rounds=%u$"; + +/* Maximum salt string length. */ +#define SALT_LEN_MAX 16 +/* Default number of rounds if not explicitly specified. */ +#define ROUNDS_DEFAULT 5000 +/* Minimum number of rounds. */ +#define ROUNDS_MIN 1000 +/* Maximum number of rounds. */ +#define ROUNDS_MAX 999999999 + +static char * +NOINLINE +sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) +{ + void (*sha_begin)(void *ctx) FAST_FUNC; + void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC; + void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC; + int _32or64; + + char *result, *resptr; + + /* btw, sha256 needs [32] and uint32_t only */ + struct { + unsigned char alt_result[64]; + unsigned char temp_result[64]; + union { + sha256_ctx_t x; + sha512_ctx_t y; + } ctx; + union { + sha256_ctx_t x; + sha512_ctx_t y; + } alt_ctx; + } L __attribute__((__aligned__(__alignof__(uint64_t)))); +#define alt_result (L.alt_result ) +#define temp_result (L.temp_result) +#define ctx (L.ctx ) +#define alt_ctx (L.alt_ctx ) + unsigned salt_len; + unsigned key_len; + unsigned cnt; + unsigned rounds; + char *cp; + char is_sha512; + + /* Analyze salt, construct already known part of result */ + cnt = strlen(salt_data) + 1 + 43 + 1; + is_sha512 = salt_data[1]; + if (is_sha512 == '6') + cnt += 43; + result = resptr = xzalloc(cnt); /* will provide NUL terminator */ + *resptr++ = '$'; + *resptr++ = is_sha512; + *resptr++ = '$'; + rounds = ROUNDS_DEFAULT; + salt_data += 3; + if (strncmp(salt_data, str_rounds, 7) == 0) { + /* 7 == strlen("rounds=") */ + char *endp; + cnt = bb_strtou(salt_data + 7, &endp, 10); + if (*endp == '$') { + salt_data = endp + 1; + rounds = cnt; + if (rounds < ROUNDS_MIN) + rounds = ROUNDS_MIN; + if (rounds > ROUNDS_MAX) + rounds = ROUNDS_MAX; + /* add "rounds=NNNNN$" to result */ + resptr += sprintf(resptr, str_rounds, rounds); + } + } + salt_len = strchrnul(salt_data, '$') - salt_data; + if (salt_len > SALT_LEN_MAX) + salt_len = SALT_LEN_MAX; + /* xstrdup assures suitable alignment; also we will use it + as a scratch space later. */ + salt_data = xstrndup(salt_data, salt_len); + /* add "salt$" to result */ + strcpy(resptr, salt_data); + resptr += salt_len; + *resptr++ = '$'; + /* key data doesn't need much processing */ + key_len = strlen(key_data); + key_data = xstrdup(key_data); + + /* Which flavor of SHAnnn ops to use? */ + sha_begin = (void*)sha256_begin; + sha_hash = (void*)sha256_hash; + sha_end = (void*)sha256_end; + _32or64 = 32; + if (is_sha512 == '6') { + sha_begin = (void*)sha512_begin; + sha_hash = (void*)sha512_hash; + sha_end = (void*)sha512_end; + _32or64 = 64; + } + + /* Add KEY, SALT. */ + sha_begin(&ctx); + sha_hash(key_data, key_len, &ctx); + sha_hash(salt_data, salt_len, &ctx); + + /* Compute alternate SHA sum with input KEY, SALT, and KEY. + The final result will be added to the first context. */ + sha_begin(&alt_ctx); + sha_hash(key_data, key_len, &alt_ctx); + sha_hash(salt_data, salt_len, &alt_ctx); + sha_hash(key_data, key_len, &alt_ctx); + sha_end(alt_result, &alt_ctx); + + /* Add result of this to the other context. */ + /* Add for any character in the key one byte of the alternate sum. */ + for (cnt = key_len; cnt > _32or64; cnt -= _32or64) + sha_hash(alt_result, _32or64, &ctx); + sha_hash(alt_result, cnt, &ctx); + + /* Take the binary representation of the length of the key and for every + 1 add the alternate sum, for every 0 the key. */ + for (cnt = key_len; cnt != 0; cnt >>= 1) + if ((cnt & 1) != 0) + sha_hash(alt_result, _32or64, &ctx); + else + sha_hash(key_data, key_len, &ctx); + + /* Create intermediate result. */ + sha_end(alt_result, &ctx); + + /* Start computation of P byte sequence. */ + /* For every character in the password add the entire password. */ + sha_begin(&alt_ctx); + for (cnt = 0; cnt < key_len; ++cnt) + sha_hash(key_data, key_len, &alt_ctx); + sha_end(temp_result, &alt_ctx); + + /* NB: past this point, raw key_data is not used anymore */ + + /* Create byte sequence P. */ +#define p_bytes key_data /* reuse the buffer as it is of the key_len size */ + cp = p_bytes; /* was: ... = alloca(key_len); */ + for (cnt = key_len; cnt >= _32or64; cnt -= _32or64) { + cp = memcpy(cp, temp_result, _32or64); + cp += _32or64; + } + memcpy(cp, temp_result, cnt); + + /* Start computation of S byte sequence. */ + /* For every character in the password add the entire password. */ + sha_begin(&alt_ctx); + for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) + sha_hash(salt_data, salt_len, &alt_ctx); + sha_end(temp_result, &alt_ctx); + + /* NB: past this point, raw salt_data is not used anymore */ + + /* Create byte sequence S. */ +#define s_bytes salt_data /* reuse the buffer as it is of the salt_len size */ + cp = s_bytes; /* was: ... = alloca(salt_len); */ + for (cnt = salt_len; cnt >= _32or64; cnt -= _32or64) { + cp = memcpy(cp, temp_result, _32or64); + cp += _32or64; + } + memcpy(cp, temp_result, cnt); + + /* Repeatedly run the collected hash value through SHA to burn + CPU cycles. */ + for (cnt = 0; cnt < rounds; ++cnt) { + sha_begin(&ctx); + + /* Add key or last result. */ + if ((cnt & 1) != 0) + sha_hash(p_bytes, key_len, &ctx); + else + sha_hash(alt_result, _32or64, &ctx); + /* Add salt for numbers not divisible by 3. */ + if (cnt % 3 != 0) + sha_hash(s_bytes, salt_len, &ctx); + /* Add key for numbers not divisible by 7. */ + if (cnt % 7 != 0) + sha_hash(p_bytes, key_len, &ctx); + /* Add key or last result. */ + if ((cnt & 1) != 0) + sha_hash(alt_result, _32or64, &ctx); + else + sha_hash(p_bytes, key_len, &ctx); + + sha_end(alt_result, &ctx); + } + + /* Append encrypted password to result buffer */ +//TODO: replace with something like +// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); +#define b64_from_24bit(B2, B1, B0, N) \ +do { \ + unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ + resptr = to64(resptr, w, N); \ +} while (0) + if (is_sha512 == '5') { + unsigned i = 0; + while (1) { + unsigned j = i + 10; + unsigned k = i + 20; + if (j >= 30) j -= 30; + if (k >= 30) k -= 30; + b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); + if (k == 29) + break; + i = k + 1; + } + b64_from_24bit(0, alt_result[31], alt_result[30], 3); + /* was: + b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4); + b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4); + b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4); + b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4); + b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4); + b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4); + b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4); + b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4); + b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4); + b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4); + b64_from_24bit(0, alt_result[31], alt_result[30], 3); + */ + } else { + unsigned i = 0; + while (1) { + unsigned j = i + 21; + unsigned k = i + 42; + if (j >= 63) j -= 63; + if (k >= 63) k -= 63; + b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); + if (j == 20) + break; + i = j + 1; + } + b64_from_24bit(0, 0, alt_result[63], 2); + /* was: + b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4); + b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4); + b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4); + b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4); + b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4); + b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4); + b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4); + b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4); + b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4); + b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4); + b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4); + b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4); + b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4); + b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4); + b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4); + b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4); + b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4); + b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4); + b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4); + b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4); + b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4); + b64_from_24bit(0, 0, alt_result[63], 2); + */ + } + /* *resptr = '\0'; - xzalloc did it */ +#undef b64_from_24bit + + /* Clear the buffer for the intermediate result so that people + attaching to processes or reading core dumps cannot get any + information. */ + memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */ + memset(key_data, 0, key_len); /* also p_bytes */ + memset(salt_data, 0, salt_len); /* also s_bytes */ + free(key_data); + free(salt_data); +#undef p_bytes +#undef s_bytes + + return result; +#undef alt_result +#undef temp_result +#undef ctx +#undef alt_ctx +} diff --git a/release/src/router/busybox/libbb/read.c b/release/src/router/busybox/libbb/read.c index 815007c1e9..37503e84d3 100644 --- a/release/src/router/busybox/libbb/read.c +++ b/release/src/router/busybox/libbb/read.c @@ -141,7 +141,7 @@ char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) { char *p; size_t sz = buf ? strlen(buf) : 0; - size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t); + size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095); goto jump_in; while (sz < maxsz) { @@ -198,7 +198,7 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p) size_t to_read; struct stat st; - to_read = maxsz_p ? *maxsz_p : MAXINT(ssize_t); /* max to read */ + to_read = maxsz_p ? *maxsz_p : (INT_MAX - 4095); /* max to read */ /* Estimate file size */ st.st_size = 0; /* in case fstat fails, assume 0 */ @@ -262,7 +262,7 @@ void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p) len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */ if (len != (off_t)-1) { xlseek(fd, 0, SEEK_SET); - size = maxsz_p ? *maxsz_p : INT_MAX; + size = maxsz_p ? *maxsz_p : (INT_MAX - 4095); if (len < size) size = len; } diff --git a/release/src/router/busybox/libbb/read_key.c b/release/src/router/busybox/libbb/read_key.c new file mode 100644 index 0000000000..0f36d20b63 --- /dev/null +++ b/release/src/router/busybox/libbb/read_key.c @@ -0,0 +1,157 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2008 Rob Landley + * Copyright (C) 2008 Denys Vlasenko + * + * Licensed under GPL version 2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" + +int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer) +{ + struct pollfd pfd; + const char *seq; + int n; + int c; + + /* Known escape sequences for cursor and function keys */ + static const char esccmds[] ALIGN1 = { + 'O','A' |0x80,KEYCODE_UP , + 'O','B' |0x80,KEYCODE_DOWN , + 'O','C' |0x80,KEYCODE_RIGHT , + 'O','D' |0x80,KEYCODE_LEFT , + 'O','H' |0x80,KEYCODE_HOME , + 'O','F' |0x80,KEYCODE_END , +#if 0 + 'O','P' |0x80,KEYCODE_FUN1 , + /* [ESC] ESC O [2] P - [Alt-][Shift-]F1 */ + /* Ctrl- seems to not affect sequences */ + 'O','Q' |0x80,KEYCODE_FUN2 , + 'O','R' |0x80,KEYCODE_FUN3 , + 'O','S' |0x80,KEYCODE_FUN4 , +#endif + '[','A' |0x80,KEYCODE_UP , + '[','B' |0x80,KEYCODE_DOWN , + '[','C' |0x80,KEYCODE_RIGHT , + '[','D' |0x80,KEYCODE_LEFT , + '[','H' |0x80,KEYCODE_HOME , /* xterm */ + /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */ + '[','F' |0x80,KEYCODE_END , /* xterm */ + '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ + '[','2','~' |0x80,KEYCODE_INSERT , + '[','3','~' |0x80,KEYCODE_DELETE , + /* [ESC] ESC [ 3 [;2] ~ - [Alt-][Shift-]Delete */ + '[','4','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */ + '[','5','~' |0x80,KEYCODE_PAGEUP , + '[','6','~' |0x80,KEYCODE_PAGEDOWN, + '[','7','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ + '[','8','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */ +#if 0 + '[','1','1','~'|0x80,KEYCODE_FUN1 , + '[','1','2','~'|0x80,KEYCODE_FUN2 , + '[','1','3','~'|0x80,KEYCODE_FUN3 , + '[','1','4','~'|0x80,KEYCODE_FUN4 , + '[','1','5','~'|0x80,KEYCODE_FUN5 , + /* [ESC] ESC [ 1 5 [;2] ~ - [Alt-][Shift-]F5 */ + '[','1','7','~'|0x80,KEYCODE_FUN6 , + '[','1','8','~'|0x80,KEYCODE_FUN7 , + '[','1','9','~'|0x80,KEYCODE_FUN8 , + '[','2','0','~'|0x80,KEYCODE_FUN9 , + '[','2','1','~'|0x80,KEYCODE_FUN10 , + '[','2','3','~'|0x80,KEYCODE_FUN11 , + '[','2','4','~'|0x80,KEYCODE_FUN12 , +#endif + 0 + }; + + n = 0; + if (nbuffered) + n = *nbuffered; + if (n == 0) { + /* If no data, block waiting for input. If we read more + * than the minimal ESC sequence size, the "n=0" below + * would instead have to figure out how much to keep, + * resulting in larger code. */ + n = safe_read(fd, buffer, 3); + if (n <= 0) + return -1; + } + + /* Grab character to return from buffer */ + c = (unsigned char)buffer[0]; + n--; + if (n) + memmove(buffer, buffer + 1, n); + + /* Only ESC starts ESC sequences */ + if (c != 27) + goto ret; + + /* Loop through known ESC sequences */ + pfd.fd = fd; + pfd.events = POLLIN; + seq = esccmds; + while (*seq != '\0') { + /* n - position in sequence we did not read yet */ + int i = 0; /* position in sequence to compare */ + + /* Loop through chars in this sequence */ + while (1) { + /* So far escape sequence matched up to [i-1] */ + if (n <= i) { + /* Need more chars, read another one if it wouldn't block. + * Note that escape sequences come in as a unit, + * so if we block for long it's not really an escape sequence. + * Timeout is needed to reconnect escape sequences + * split up by transmission over a serial console. */ + if (safe_poll(&pfd, 1, 50) == 0) { + /* No more data! + * Array is sorted from shortest to longest, + * we can't match anything later in array, + * break out of both loops. */ + goto ret; + } + errno = 0; + if (safe_read(fd, buffer + n, 1) <= 0) { + /* If EAGAIN, then fd is O_NONBLOCK and poll lied: + * in fact, there is no data. */ + if (errno != EAGAIN) + c = -1; /* otherwise it's EOF/error */ + goto ret; + } + n++; + } + if (buffer[i] != (seq[i] & 0x7f)) { + /* This seq doesn't match, go to next */ + seq += i; + /* Forward to last char */ + while (!(*seq & 0x80)) + seq++; + /* Skip it and the keycode which follows */ + seq += 2; + break; + } + if (seq[i] & 0x80) { + /* Entire seq matched */ + c = (signed char)seq[i+1]; + n = 0; + /* n -= i; memmove(...); + * would be more correct, + * but we never read ahead that much, + * and n == i here. */ + goto ret; + } + i++; + } + } + /* We did not find matching sequence, it was a bare ESC. + * We possibly read and stored more input in buffer[] + * by now. */ + + ret: + if (nbuffered) + *nbuffered = n; + return c; +} diff --git a/release/src/router/busybox/libbb/rtc.c b/release/src/router/busybox/libbb/rtc.c index 222d977ca6..51834f8f99 100644 --- a/release/src/router/busybox/libbb/rtc.c +++ b/release/src/router/busybox/libbb/rtc.c @@ -1,5 +1,7 @@ /* * Common RTC functions + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" diff --git a/release/src/router/busybox/libbb/selinux_common.c b/release/src/router/busybox/libbb/selinux_common.c index 5fdbe9d587..275a761d29 100644 --- a/release/src/router/busybox/libbb/selinux_common.c +++ b/release/src/router/busybox/libbb/selinux_common.c @@ -3,6 +3,8 @@ * -- common SELinux utility functions * * Copyright 2007 KaiGai Kohei + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" #include diff --git a/release/src/router/busybox/libbb/sha1.c b/release/src/router/busybox/libbb/sha1.c dissimilarity index 79% index cc7edd8a79..9fa095e857 100644 --- a/release/src/router/busybox/libbb/sha1.c +++ b/release/src/router/busybox/libbb/sha1.c @@ -1,170 +1,465 @@ -/* vi: set sw=4 ts=4: */ -/* - * Based on shasum from http://www.netsw.org/crypto/hash/ - * Majorly hacked up to use Dr Brian Gladman's sha1 code - * - * Copyright (C) 2002 Dr Brian Gladman , Worcester, UK. - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * --------------------------------------------------------------------------- - * Issue Date: 10/11/2002 - * - * This is a byte oriented version of SHA1 that operates on arrays of bytes - * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor - */ - -#include "libbb.h" - -#define SHA1_BLOCK_SIZE 64 -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HASH_SIZE SHA1_DIGEST_SIZE -#define SHA2_GOOD 0 -#define SHA2_BAD 1 - -#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) - -#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) - -/* reverse byte order in 32-bit words */ -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) - -/* A normal version as set out in the FIPS. This version uses */ -/* partial loop unrolling and is optimised for the Pentium 4 */ -#define rnd(f,k) \ - do { \ - t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \ - e = d; d = c; c = rotl32(b, 30); b = t; \ - } while (0) - -static void sha1_compile(sha1_ctx_t *ctx) -{ - uint32_t w[80], i, a, b, c, d, e, t; - - /* note that words are compiled from the buffer into 32-bit */ - /* words in big-endian order so an order reversal is needed */ - /* here on little endian machines */ - for (i = 0; i < SHA1_BLOCK_SIZE / 4; ++i) - w[i] = htonl(ctx->wbuf[i]); - - for (i = SHA1_BLOCK_SIZE / 4; i < 80; ++i) - w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); - - a = ctx->hash[0]; - b = ctx->hash[1]; - c = ctx->hash[2]; - d = ctx->hash[3]; - e = ctx->hash[4]; - - for (i = 0; i < 20; ++i) { - rnd(ch, 0x5a827999); - } - - for (i = 20; i < 40; ++i) { - rnd(parity, 0x6ed9eba1); - } - - for (i = 40; i < 60; ++i) { - rnd(maj, 0x8f1bbcdc); - } - - for (i = 60; i < 80; ++i) { - rnd(parity, 0xca62c1d6); - } - - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; -} - -void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) -{ - ctx->count[0] = ctx->count[1] = 0; - ctx->hash[0] = 0x67452301; - ctx->hash[1] = 0xefcdab89; - ctx->hash[2] = 0x98badcfe; - ctx->hash[3] = 0x10325476; - ctx->hash[4] = 0xc3d2e1f0; -} - -/* SHA1 hash data in an array of bytes into hash buffer and call the */ -/* hash_compile function as required. */ -void FAST_FUNC sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx) -{ - uint32_t pos = (uint32_t) (ctx->count[0] & SHA1_MASK); - uint32_t freeb = SHA1_BLOCK_SIZE - pos; - const unsigned char *sp = data; - - if ((ctx->count[0] += length) < length) - ++(ctx->count[1]); - - while (length >= freeb) { /* tranfer whole blocks while possible */ - memcpy(((unsigned char *) ctx->wbuf) + pos, sp, freeb); - sp += freeb; - length -= freeb; - freeb = SHA1_BLOCK_SIZE; - pos = 0; - sha1_compile(ctx); - } - - memcpy(((unsigned char *) ctx->wbuf) + pos, sp, length); -} - -void* FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx) -{ - /* SHA1 Final padding and digest calculation */ -#if BB_BIG_ENDIAN - static uint32_t mask[4] = { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 }; - static uint32_t bits[4] = { 0x80000000, 0x00800000, 0x00008000, 0x00000080 }; -#else - static uint32_t mask[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; - static uint32_t bits[4] = { 0x00000080, 0x00008000, 0x00800000, 0x80000000 }; -#endif - - uint8_t *hval = resbuf; - uint32_t i, cnt = (uint32_t) (ctx->count[0] & SHA1_MASK); - - /* mask out the rest of any partial 32-bit word and then set */ - /* the next byte to 0x80. On big-endian machines any bytes in */ - /* the buffer will be at the top end of 32 bit words, on little */ - /* endian machines they will be at the bottom. Hence the AND */ - /* and OR masks above are reversed for little endian systems */ - ctx->wbuf[cnt >> 2] = - (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3]; - - /* we need 9 or more empty positions, one for the padding byte */ - /* (above) and eight for the length count. If there is not */ - /* enough space pad and empty the buffer */ - if (cnt > SHA1_BLOCK_SIZE - 9) { - if (cnt < 60) - ctx->wbuf[15] = 0; - sha1_compile(ctx); - cnt = 0; - } else /* compute a word index for the empty buffer positions */ - cnt = (cnt >> 2) + 1; - - while (cnt < 14) /* and zero pad all but last two positions */ - ctx->wbuf[cnt++] = 0; - - /* assemble the eight byte counter in the buffer in big-endian */ - /* format */ - - ctx->wbuf[14] = htonl((ctx->count[1] << 3) | (ctx->count[0] >> 29)); - ctx->wbuf[15] = htonl(ctx->count[0] << 3); - - sha1_compile(ctx); - - /* extract the hash value as bytes in case the hash buffer is */ - /* misaligned for 32-bit words */ - - for (i = 0; i < SHA1_DIGEST_SIZE; ++i) - hval[i] = (unsigned char) (ctx->hash[i >> 2] >> 8 * (~i & 3)); - - return resbuf; -} +/* vi: set sw=4 ts=4: */ +/* + * Based on shasum from http://www.netsw.org/crypto/hash/ + * Majorly hacked up to use Dr Brian Gladman's sha1 code + * + * Copyright (C) 2002 Dr Brian Gladman , Worcester, UK. + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * --------------------------------------------------------------------------- + * Issue Date: 10/11/2002 + * + * This is a byte oriented version of SHA1 that operates on arrays of bytes + * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * + * --------------------------------------------------------------------------- + * + * SHA256 and SHA512 parts are: + * Released into the Public Domain by Ulrich Drepper . + * Shrank by Denys Vlasenko. + * + * --------------------------------------------------------------------------- + * + * The best way to test random blocksizes is to go to coreutils/md5_sha1_sum.c + * and replace "4096" with something like "2000 + time(NULL) % 2097", + * then rebuild and compare "shaNNNsum bigfile" results. + */ + +#include "libbb.h" + +#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) +/* for sha512: */ +#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) +#if BB_LITTLE_ENDIAN +static inline uint64_t hton64(uint64_t v) +{ + return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); +} +#else +#define hton64(v) (v) +#endif +#define ntoh64(v) hton64(v) + +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +#if defined(__GNUC__) && __GNUC__ >= 2 +# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0) +#else +# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0) +#endif + + +static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) +{ + unsigned t; + uint32_t W[80], a, b, c, d, e; + const uint32_t *words = (uint32_t*) ctx->wbuffer; + + for (t = 0; t < 16; ++t) { + W[t] = ntohl(*words); + words++; + } + + for (/*t = 16*/; t < 80; ++t) { + uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; + W[t] = rotl32(T, 1); + } + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + +/* Reverse byte order in 32-bit words */ +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +/* A normal version as set out in the FIPS. This version uses */ +/* partial loop unrolling and is optimised for the Pentium 4 */ +#define rnd(f,k) \ + do { \ + uint32_t T = a; \ + a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ + e = d; \ + d = c; \ + c = rotl32(b, 30); \ + b = T; \ + } while (0) + + for (t = 0; t < 20; ++t) + rnd(ch, 0x5a827999); + + for (/*t = 20*/; t < 40; ++t) + rnd(parity, 0x6ed9eba1); + + for (/*t = 40*/; t < 60; ++t) + rnd(maj, 0x8f1bbcdc); + + for (/*t = 60*/; t < 80; ++t) + rnd(parity, 0xca62c1d6); +#undef ch +#undef parity +#undef maj +#undef rnd + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; +} + +/* Constants for SHA512 from FIPS 180-2:4.2.3. + * SHA256 constants from FIPS 180-2:4.2.2 + * are the most significant half of first 64 elements + * of the same array. + */ +static const uint64_t sha_K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, /* [64]+ are used for sha512 only */ + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx) +{ + unsigned t; + uint32_t W[64], a, b, c, d, e, f, g, h; + const uint32_t *words = (uint32_t*) ctx->wbuffer; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22)) +#define S1(x) (rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25)) +#define R0(x) (rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3)) +#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10)) + + /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ + for (t = 0; t < 16; ++t) { + W[t] = ntohl(*words); + words++; + } + + for (/*t = 16*/; t < 64; ++t) + W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + f = ctx->hash[5]; + g = ctx->hash[6]; + h = ctx->hash[7]; + + /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ + for (t = 0; t < 64; ++t) { + /* Need to fetch upper half of sha_K[t] + * (I hope compiler is clever enough to just fetch + * upper half) + */ + uint32_t K_t = sha_K[t] >> 32; + uint32_t T1 = h + S1(e) + Ch(e, f, g) + K_t + W[t]; + uint32_t T2 = S0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#undef Ch +#undef Maj +#undef S0 +#undef S1 +#undef R0 +#undef R1 + /* Add the starting values of the context according to FIPS 180-2:6.2.2 + step 4. */ + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} + +static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx) +{ + unsigned t; + uint64_t W[80]; + /* On i386, having assignments here (not later as sha256 does) + * produces 99 bytes smaller code with gcc 4.3.1 + */ + uint64_t a = ctx->hash[0]; + uint64_t b = ctx->hash[1]; + uint64_t c = ctx->hash[2]; + uint64_t d = ctx->hash[3]; + uint64_t e = ctx->hash[4]; + uint64_t f = ctx->hash[5]; + uint64_t g = ctx->hash[6]; + uint64_t h = ctx->hash[7]; + const uint64_t *words = (uint64_t*) ctx->wbuffer; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39)) +#define S1(x) (rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41)) +#define R0(x) (rotr64(x, 1) ^ rotr64(x, 8) ^ (x >> 7)) +#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6)) + + /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */ + for (t = 0; t < 16; ++t) { + W[t] = ntoh64(*words); + words++; + } + for (/*t = 16*/; t < 80; ++t) + W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; + + /* The actual computation according to FIPS 180-2:6.3.2 step 3. */ + for (t = 0; t < 80; ++t) { + uint64_t T1 = h + S1(e) + Ch(e, f, g) + sha_K[t] + W[t]; + uint64_t T2 = S0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#undef Ch +#undef Maj +#undef S0 +#undef S1 +#undef R0 +#undef R1 + /* Add the starting values of the context according to FIPS 180-2:6.3.2 + step 4. */ + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} + + +void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) +{ + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; + ctx->total64 = 0; + ctx->process_block = sha1_process_block64; +} + +static const uint32_t init256[] = { + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 +}; +static const uint32_t init512_lo[] = { + 0xf3bcc908, + 0x84caa73b, + 0xfe94f82b, + 0x5f1d36f1, + 0xade682d1, + 0x2b3e6c1f, + 0xfb41bd6b, + 0x137e2179 +}; + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.2) */ +void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) +{ + memcpy(ctx->hash, init256, sizeof(init256)); + ctx->total64 = 0; + ctx->process_block = sha256_process_block64; +} + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.3) */ +void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) +{ + int i; + for (i = 0; i < 8; i++) + ctx->hash[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; + ctx->total64[0] = ctx->total64[1] = 0; +} + + +/* Used also for sha256 */ +void FAST_FUNC sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx) +{ + unsigned in_buf = ctx->total64 & 63; + unsigned add = 64 - in_buf; + + ctx->total64 += len; + + while (len >= add) { /* transfer whole blocks while possible */ + memcpy(ctx->wbuffer + in_buf, buffer, add); + buffer = (const char *)buffer + add; + len -= add; + add = 64; + in_buf = 0; + ctx->process_block(ctx); + } + + memcpy(ctx->wbuffer + in_buf, buffer, len); +} + +void FAST_FUNC sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) +{ + unsigned in_buf = ctx->total64[0] & 127; + unsigned add = 128 - in_buf; + + /* First increment the byte count. FIPS 180-2 specifies the possible + length of the file up to 2^128 _bits_. + We compute the number of _bytes_ and convert to bits later. */ + ctx->total64[0] += len; + if (ctx->total64[0] < len) + ctx->total64[1]++; + + while (len >= add) { /* transfer whole blocks while possible */ + memcpy(ctx->wbuffer + in_buf, buffer, add); + buffer = (const char *)buffer + add; + len -= add; + add = 128; + in_buf = 0; + sha512_process_block128(ctx); + } + + memcpy(ctx->wbuffer + in_buf, buffer, len); +} + + +/* Used also for sha256 */ +void FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx) +{ + unsigned i, pad, in_buf; + + in_buf = ctx->total64 & 63; + /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ + ctx->wbuffer[in_buf++] = 0x80; + + /* This loop iterates either once or twice, no more, no less */ + while (1) { + pad = 64 - in_buf; + memset(ctx->wbuffer + in_buf, 0, pad); + in_buf = 0; + /* Do we have enough space for the length count? */ + if (pad >= 8) { + /* Store the 64-bit counter of bits in the buffer in BE format */ + uint64_t t = ctx->total64 << 3; + t = hton64(t); + /* wbuffer is suitably aligned for this */ + *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; + } + ctx->process_block(ctx); + if (pad >= 8) + break; + } + + in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8; + /* This way we do not impose alignment constraints on resbuf: */ +#if BB_LITTLE_ENDIAN + for (i = 0; i < in_buf; ++i) + ctx->hash[i] = htonl(ctx->hash[i]); +#endif + memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf); +} + +void FAST_FUNC sha512_end(void *resbuf, sha512_ctx_t *ctx) +{ + unsigned i, pad, in_buf; + + in_buf = ctx->total64[0] & 127; + /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... + * (FIPS 180-2:5.1.2) + */ + ctx->wbuffer[in_buf++] = 0x80; + + while (1) { + pad = 128 - in_buf; + memset(ctx->wbuffer + in_buf, 0, pad); + in_buf = 0; + if (pad >= 16) { + /* Store the 128-bit counter of bits in the buffer in BE format */ + uint64_t t; + t = ctx->total64[0] << 3; + t = hton64(t); + *(uint64_t *) (&ctx->wbuffer[128 - 8]) = t; + t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61); + t = hton64(t); + *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t; + } + sha512_process_block128(ctx); + if (pad >= 16) + break; + } + +#if BB_LITTLE_ENDIAN + for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) + ctx->hash[i] = hton64(ctx->hash[i]); +#endif + memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); +} diff --git a/release/src/router/busybox/libbb/signals.c b/release/src/router/busybox/libbb/signals.c index 959114679e..a528756fff 100644 --- a/release/src/router/busybox/libbb/signals.c +++ b/release/src/router/busybox/libbb/signals.c @@ -11,6 +11,14 @@ #include "libbb.h" +/* All known arches use small ints for signals */ +smallint bb_got_signal; + +void record_signo(int signo) +{ + bb_got_signal = signo; +} + /* Saves 2 bytes on x86! Oh my... */ int FAST_FUNC sigaction_set(int signum, const struct sigaction *act) { @@ -39,7 +47,7 @@ void FAST_FUNC bb_signals(int sigs, void (*f)(int)) } } -void FAST_FUNC bb_signals_recursive(int sigs, void (*f)(int)) +void FAST_FUNC bb_signals_recursive_norestart(int sigs, void (*f)(int)) { int sig_no = 0; int bit = 1; diff --git a/release/src/router/busybox/libbb/speed_table.c b/release/src/router/busybox/libbb/speed_table.c index 646f9146b7..05fe66c645 100644 --- a/release/src/router/busybox/libbb/speed_table.c +++ b/release/src/router/busybox/libbb/speed_table.c @@ -7,7 +7,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include #include "libbb.h" struct speed_map { diff --git a/release/src/router/busybox/libbb/strrstr.c b/release/src/router/busybox/libbb/strrstr.c index d5cd44b2a2..a803dd983f 100644 --- a/release/src/router/busybox/libbb/strrstr.c +++ b/release/src/router/busybox/libbb/strrstr.c @@ -2,7 +2,7 @@ /* * Utility routines. * - * Copyright (C) 2008 Bernhard Fischer + * Copyright (C) 2008 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file License in this tarball for details. */ diff --git a/release/src/router/busybox/libbb/update_passwd.c b/release/src/router/busybox/libbb/update_passwd.c index 88bc28ca93..35b89a5b40 100644 --- a/release/src/router/busybox/libbb/update_passwd.c +++ b/release/src/router/busybox/libbb/update_passwd.c @@ -7,8 +7,12 @@ * /etc/shadow) for a given user and password. * * Moved from loginutils/passwd.c by Alexander Shishkin + * + * Modified to be able to add or delete users, groups and users to/from groups + * by Tito Ragusa + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ - #include "libbb.h" #if ENABLE_SELINUX @@ -33,12 +37,44 @@ static void check_selinux_update_passwd(const char *username) freecon(context); } #else -#define check_selinux_update_passwd(username) ((void)0) +# define check_selinux_update_passwd(username) ((void)0) #endif -int FAST_FUNC update_passwd(const char *filename, const char *username, - const char *new_pw) +/* + 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL) + only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser + + 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL) + only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup + + 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER) + only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a' + like in addgroup and member != NULL + + 4) delete a user: update_passwd(FILE, USER, NULL, NULL) + + 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL) + + 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER) + only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL + + 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL) + only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd + or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd + + This function does not validate the arguments fed to it + so the calling program should take care of that. + + Returns number of lines changed, or -1 on error. +*/ +int FAST_FUNC update_passwd(const char *filename, + const char *name, + const char *new_passwd, + const char *member) { +#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) +#define member NULL +#endif struct stat sb; struct flock lock; FILE *old_fp; @@ -49,22 +85,25 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, int old_fd; int new_fd; int i; - int cnt = 0; + int changed_lines; int ret = -1; /* failure */ filename = xmalloc_follow_symlinks(filename); if (filename == NULL) - return -1; + return ret; - check_selinux_update_passwd(username); + check_selinux_update_passwd(name); /* New passwd file, "/etc/passwd+" for now */ fnamesfx = xasprintf("%s+", filename); sfx_char = &fnamesfx[strlen(fnamesfx)-1]; - username = xasprintf("%s:", username); - user_len = strlen(username); + name = xasprintf("%s:", name); + user_len = strlen(name); - old_fp = fopen(filename, "r+"); + if (strstr(filename, "shadow")) + old_fp = fopen(filename, "r+"); + else + old_fp = fopen_or_warn(filename, "r+"); if (!old_fp) goto free_mem; old_fd = fileno(old_fp); @@ -80,7 +119,7 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, if (errno != EEXIST) break; usleep(100000); /* 0.1 sec */ } while (--i); - bb_perror_msg("cannot create '%s'", fnamesfx); + bb_perror_msg("can't create '%s'", fnamesfx); goto close_old_fp; created: @@ -88,8 +127,10 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ fchown(new_fd, sb.st_uid, sb.st_gid); } + errno = 0; new_fp = fdopen(new_fd, "w"); if (!new_fp) { + bb_perror_nomsg(); close(new_fd); goto unlink_new; } @@ -100,7 +141,8 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, i = (unlink(fnamesfx) && errno != ENOENT); /* Create backup as a hardlink to current */ if (i || link(filename, fnamesfx)) - bb_perror_msg("warning: cannot create backup copy '%s'", fnamesfx); + bb_perror_msg("warning: can't create backup copy '%s'", + fnamesfx); *sfx_char = '+'; /* Lock the password file before updating */ @@ -109,38 +151,109 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, lock.l_start = 0; lock.l_len = 0; if (fcntl(old_fd, F_SETLK, &lock) < 0) - bb_perror_msg("warning: cannot lock '%s'", filename); + bb_perror_msg("warning: can't lock '%s'", filename); lock.l_type = F_UNLCK; /* Read current password file, write updated /etc/passwd+ */ + changed_lines = 0; while (1) { - char *line = xmalloc_fgets(old_fp); - if (!line) break; /* EOF/error */ - if (strncmp(username, line, user_len) == 0) { - /* we have a match with "username:"... */ - const char *cp = line + user_len; - /* now cp -> old passwd, skip it: */ - cp = strchrnul(cp, ':'); - /* now cp -> ':' after old passwd or -> "" */ - fprintf(new_fp, "%s%s%s", username, new_pw, cp); - cnt++; + char *cp, *line; + + line = xmalloc_fgetline(old_fp); + if (!line) /* EOF/error */ + break; + if (strncmp(name, line, user_len) != 0) { + fprintf(new_fp, "%s\n", line); + goto next; + } + + /* We have a match with "name:"... */ + cp = line + user_len; /* move past name: */ + +#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP + if (member) { + /* It's actually /etc/group+, not /etc/passwd+ */ + if (ENABLE_FEATURE_ADDUSER_TO_GROUP + && applet_name[0] == 'a' + ) { + /* Add user to group */ + fprintf(new_fp, "%s%s%s\n", line, + last_char_is(line, ':') ? "" : ",", + member); + changed_lines++; + } else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP + /* && applet_name[0] == 'd' */ + ) { + /* Delete user from group */ + char *tmp; + const char *fmt = "%s"; + + /* find the start of the member list: last ':' */ + cp = strrchr(line, ':'); + /* cut it */ + *cp++ = '\0'; + /* write the cut line name:passwd:gid: + * or name:!:: */ + fprintf(new_fp, "%s:", line); + /* parse the tokens of the member list */ + tmp = cp; + while ((cp = strsep(&tmp, ",")) != NULL) { + if (strcmp(member, cp) != 0) { + fprintf(new_fp, fmt, cp); + fmt = ",%s"; + } else { + /* found member, skip it */ + changed_lines++; + } + } + fprintf(new_fp, "\n"); + } } else - fputs(line, new_fp); +#endif + if ((ENABLE_PASSWD && applet_name[0] == 'p') + || (ENABLE_CHPASSWD && applet_name[0] == 'c') + ) { + /* Change passwd */ + cp = strchrnul(cp, ':'); /* move past old passwd */ + /* name: + new_passwd + :rest of line */ + fprintf(new_fp, "%s%s%s\n", name, new_passwd, cp); + changed_lines++; + } /* else delete user or group: skip the line */ + next: free(line); } + + if (changed_lines == 0) { +#if ENABLE_FEATURE_DEL_USER_FROM_GROUP + if (member) + bb_error_msg("can't find %s in %s", member, filename); +#endif + if ((ENABLE_ADDUSER || ENABLE_ADDGROUP) + && applet_name[0] == 'a' && !member + ) { + /* add user or group */ + fprintf(new_fp, "%s%s\n", name, new_passwd); + changed_lines++; + } + } + fcntl(old_fd, F_SETLK, &lock); /* We do want all of them to execute, thus | instead of || */ + errno = 0; if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) || rename(fnamesfx, filename) ) { /* At least one of those failed */ + bb_perror_nomsg(); goto unlink_new; } - ret = cnt; /* whee, success! */ + /* Success: ret >= 0 */ + ret = changed_lines; unlink_new: - if (ret < 0) unlink(fnamesfx); + if (ret < 0) + unlink(fnamesfx); close_old_fp: fclose(old_fp); @@ -148,6 +261,6 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, free_mem: free(fnamesfx); free((char *)filename); - free((char *)username); + free((char *)name); return ret; } diff --git a/release/src/router/busybox/libbb/vfork_daemon_rexec.c b/release/src/router/busybox/libbb/vfork_daemon_rexec.c index 17b373cd1b..f64239a96c 100644 --- a/release/src/router/busybox/libbb/vfork_daemon_rexec.c +++ b/release/src/router/busybox/libbb/vfork_daemon_rexec.c @@ -66,9 +66,9 @@ pid_t FAST_FUNC xspawn(char **argv) return pid; } -int FAST_FUNC safe_waitpid(int pid, int *wstat, int options) +pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) { - int r; + pid_t r; do r = waitpid(pid, wstat, options); @@ -76,13 +76,13 @@ int FAST_FUNC safe_waitpid(int pid, int *wstat, int options) return r; } -int FAST_FUNC wait_any_nohang(int *wstat) +pid_t FAST_FUNC wait_any_nohang(int *wstat) { return safe_waitpid(-1, wstat, WNOHANG); } // Wait for the specified child PID to exit, returning child's error return. -int FAST_FUNC wait4pid(int pid) +int FAST_FUNC wait4pid(pid_t pid) { int status; @@ -251,35 +251,33 @@ void FAST_FUNC re_exec(char **argv) bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); } -void FAST_FUNC forkexit_or_rexec(char **argv) +pid_t FAST_FUNC fork_or_rexec(char **argv) { pid_t pid; /* Maybe we are already re-execed and come here again? */ if (re_execed) - return; + return 0; /* child */ pid = vfork(); if (pid < 0) /* wtf? */ bb_perror_msg_and_die("vfork"); if (pid) /* parent */ - exit(EXIT_SUCCESS); + return pid; /* child - re-exec ourself */ re_exec(argv); } #else /* Dance around (void)...*/ -#undef forkexit_or_rexec -void FAST_FUNC forkexit_or_rexec(void) +#undef fork_or_rexec +pid_t FAST_FUNC fork_or_rexec(void) { pid_t pid; pid = fork(); if (pid < 0) /* wtf? */ bb_perror_msg_and_die("fork"); - if (pid) /* parent */ - exit(EXIT_SUCCESS); - /* child */ + return pid; } -#define forkexit_or_rexec(argv) forkexit_or_rexec() +#define fork_or_rexec(argv) fork_or_rexec() #endif /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - @@ -310,7 +308,8 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ if (!(flags & DAEMON_ONLY_SANITIZE)) { - forkexit_or_rexec(argv); + if (fork_or_rexec(argv)) + exit(EXIT_SUCCESS); /* parent */ /* if daemonizing, make sure we detach from stdio & ctty */ setsid(); dup2(fd, 0); diff --git a/release/src/router/busybox/libbb/wfopen.c b/release/src/router/busybox/libbb/wfopen.c index 4c84b3ba97..1cb871ef51 100644 --- a/release/src/router/busybox/libbb/wfopen.c +++ b/release/src/router/busybox/libbb/wfopen.c @@ -14,7 +14,7 @@ FILE* FAST_FUNC fopen_or_warn(const char *path, const char *mode) FILE *fp = fopen(path, mode); if (!fp) { bb_simple_perror_msg(path); - errno = 0; + //errno = 0; /* why? */ } return fp; } diff --git a/release/src/router/busybox/libbb/write.c b/release/src/router/busybox/libbb/write.c index e8a9eff866..116e4d1531 100644 --- a/release/src/router/busybox/libbb/write.c +++ b/release/src/router/busybox/libbb/write.c @@ -2,7 +2,7 @@ /* * Utility routines. * - * Copyright (C) 2008 Bernhard Fischer + * Copyright (C) 2008 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ @@ -10,11 +10,10 @@ #include "libbb.h" /* Open file and write string str to it, close file. - * Die on any open or write-error. */ + * Die on any open or write error. */ void FAST_FUNC xopen_xwrite_close(const char* file, const char* str) { int fd = xopen(file, O_WRONLY); - - xwrite(fd, str, strlen(str)); + xwrite_str(fd, str); close(fd); } diff --git a/release/src/router/busybox/libbb/xatonum_template.c b/release/src/router/busybox/libbb/xatonum_template.c index 2360ae88a3..5e0bb59e6b 100644 --- a/release/src/router/busybox/libbb/xatonum_template.c +++ b/release/src/router/busybox/libbb/xatonum_template.c @@ -1,4 +1,8 @@ /* + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +/* You need to define the following (example): #define type long diff --git a/release/src/router/busybox/libbb/xconnect.c b/release/src/router/busybox/libbb/xconnect.c index d48c503399..f5d7983a43 100644 --- a/release/src/router/busybox/libbb/xconnect.c +++ b/release/src/router/busybox/libbb/xconnect.c @@ -4,9 +4,11 @@ * * Connect to host at port using address resolution from getaddrinfo * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include +#include #include "libbb.h" void FAST_FUNC setsockopt_reuseaddr(int fd) @@ -17,6 +19,35 @@ int FAST_FUNC setsockopt_broadcast(int fd) { return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1)); } +int FAST_FUNC setsockopt_bindtodevice(int fd, const char *iface) +{ + int r; + struct ifreq ifr; + strncpy_IFNAMSIZ(ifr.ifr_name, iface); + /* NB: passing (iface, strlen(iface) + 1) does not work! + * (maybe it works on _some_ kernels, but not on 2.6.26) + * Actually, ifr_name is at offset 0, and in practice + * just giving char[IFNAMSIZ] instead of struct ifreq works too. + * But just in case it's not true on some obscure arch... */ + r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); + if (r) + bb_perror_msg("can't bind to interface %s", iface); + return r; +} + +len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd) +{ + len_and_sockaddr *lsa; + socklen_t len = 0; + + /* Can be optimized to do only one getsockname() */ + if (getsockname(fd, NULL, &len) != 0) + return NULL; + lsa = xzalloc(LSA_LEN_SIZE + len); + lsa->len = len; + getsockname(fd, &lsa->u.sa, &lsa->len); + return lsa; +} void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) { @@ -33,8 +64,9 @@ void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) /* Return port number for a service. * If "port" is a number use it as the port. - * If "port" is a name it is looked up in /etc/services, if it isnt found return - * default_port */ + * If "port" is a name it is looked up in /etc/services, + * if it isnt found return default_port + */ unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port) { unsigned port_nr = default_port; @@ -135,7 +167,8 @@ USE_FEATURE_IPV6(sa_family_t af,) /* Even uglier parsing of [xx]:nn */ host++; cp = strchr(host, ']'); - if (!cp || cp[1] != ':') { /* Malformed: must have [xx]:nn */ + if (!cp || (cp[1] != ':' && cp[1] != '\0')) { + /* Malformed: must be [xx]:nn or [xx] */ bb_error_msg("bad address '%s'", org_host); if (ai_flags & DIE_ON_ERROR) xfunc_die(); @@ -151,8 +184,11 @@ USE_FEATURE_IPV6(sa_family_t af,) if (cp) { /* points to ":" or "]:" */ int sz = cp - host + 1; host = safe_strncpy(alloca(sz), host, sz); - if (ENABLE_FEATURE_IPV6 && *cp != ':') + if (ENABLE_FEATURE_IPV6 && *cp != ':') { cp++; /* skip ']' */ + if (*cp == '\0') /* [xx] without port */ + goto skip; + } cp++; /* skip ':' */ port = bb_strtou(cp, NULL, 10); if (errno || (unsigned)port > 0xffff) { @@ -161,6 +197,7 @@ USE_FEATURE_IPV6(sa_family_t af,) xfunc_die(); return NULL; } + skip: ; } memset(&hint, 0 , sizeof(hint)); diff --git a/release/src/router/busybox/libbb/xfuncs.c b/release/src/router/busybox/libbb/xfuncs.c index 8ef305ba08..a86efc2981 100644 --- a/release/src/router/busybox/libbb/xfuncs.c +++ b/release/src/router/busybox/libbb/xfuncs.c @@ -40,6 +40,14 @@ int FAST_FUNC close_on_exec_on(int fd) return fcntl(fd, F_SETFD, FD_CLOEXEC); } +char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) +{ +#ifndef IFNAMSIZ + enum { IFNAMSIZ = 16 }; +#endif + return strncpy(dst, src, IFNAMSIZ); +} + /* Convert unsigned long long value into compact 4-char * representation. Examples: "1234", "1.2k", " 27M", "123T" * String is not terminated (buf[4] is untouched) */ @@ -260,6 +268,17 @@ off_t FAST_FUNC fdlength(int fd) } #endif +char* FAST_FUNC xmalloc_ttyname(int fd) +{ + char *buf = xzalloc(128); + int r = ttyname_r(fd, buf, 127); + if (r) { + free(buf); + buf = NULL; + } + return buf; +} + /* It is perfectly ok to pass in a NULL for either width or for * height, in which case that value will not be set. */ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) @@ -289,3 +308,8 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh return ret; } + +int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) +{ + return tcsetattr(STDIN_FILENO, TCSANOW, tp); +} diff --git a/release/src/router/busybox/libbb/xfuncs_printf.c b/release/src/router/busybox/libbb/xfuncs_printf.c index 108e14043f..6d0fa6e8d7 100644 --- a/release/src/router/busybox/libbb/xfuncs_printf.c +++ b/release/src/router/busybox/libbb/xfuncs_printf.c @@ -208,6 +208,10 @@ void FAST_FUNC xwrite(int fd, const void *buf, size_t count) bb_error_msg_and_die("short write"); } } +void FAST_FUNC xwrite_str(int fd, const char *str) +{ + xwrite(fd, str, strlen(str)); +} // Die with an error message if we can't lseek to the right spot. off_t FAST_FUNC xlseek(int fd, off_t offset, int whence) @@ -333,6 +337,29 @@ void FAST_FUNC xsetenv(const char *key, const char *value) bb_error_msg_and_die(bb_msg_memory_exhausted); } +/* Handles "VAR=VAL" strings, even those which are part of environ + * _right now_ + */ +void FAST_FUNC bb_unsetenv(const char *var) +{ + char *tp = strchr(var, '='); + + if (!tp) { + unsetenv(var); + return; + } + + /* In case var was putenv'ed, we can't replace '=' + * with NUL and unsetenv(var) - it won't work, + * env is modified by the replacement, unsetenv + * sees "VAR" instead of "VAR=VAL" and does not remove it! + * horror :( */ + tp = xstrndup(var, tp - var); + unsetenv(tp); + free(tp); +} + + // Die with an error message if we can't set gid. (Because resource limits may // limit this user to a given number of processes, and if that fills up the // setgid() will fail and we'll _still_be_root_, which is bad.) @@ -417,7 +444,7 @@ void FAST_FUNC xlisten(int s, int backlog) /* Die with an error message if sendto failed. * Return bytes sent otherwise */ -ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, +ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, socklen_t tolen) { ssize_t ret = sendto(s, buf, len, 0, to, tolen); diff --git a/release/src/router/busybox/libbb/xgetcwd.c b/release/src/router/busybox/libbb/xgetcwd.c index eefe1d6600..10febe32d4 100644 --- a/release/src/router/busybox/libbb/xgetcwd.c +++ b/release/src/router/busybox/libbb/xgetcwd.c @@ -5,7 +5,9 @@ * Written by David MacKenzie . * * Special function for busybox written by Vladimir Oleynik -*/ + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ #include "libbb.h" diff --git a/release/src/router/busybox/libbb/xreadlink.c b/release/src/router/busybox/libbb/xreadlink.c index 2cfc5751ca..8d232f16b6 100644 --- a/release/src/router/busybox/libbb/xreadlink.c +++ b/release/src/router/busybox/libbb/xreadlink.c @@ -1,7 +1,9 @@ /* vi: set sw=4 ts=4: */ /* - * xreadlink.c - safe implementation of readlink. - * Returns a NULL on failure... + * xreadlink.c - safe implementation of readlink. + * Returns a NULL on failure... + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" @@ -89,7 +91,11 @@ char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) char *buf = xmalloc_readlink(path); if (!buf) { /* EINVAL => "file: Invalid argument" => puzzled user */ - bb_error_msg("%s: cannot read link (not a symlink?)", path); + const char *errmsg = "not a symlink"; + int err = errno; + if (err != EINVAL) + errmsg = strerror(err); + bb_error_msg("%s: cannot read link: %s", path, errmsg); } return buf; } diff --git a/release/src/router/busybox/libpwdgrp/pwd_grp.c b/release/src/router/busybox/libpwdgrp/pwd_grp.c index 2065190849..56bfcbe913 100644 --- a/release/src/router/busybox/libpwdgrp/pwd_grp.c +++ b/release/src/router/busybox/libpwdgrp/pwd_grp.c @@ -396,6 +396,7 @@ struct spwd *getspnam(const char *name) } #endif +#ifdef THIS_ONE_IS_UNUSED /* This one doesn't use static buffers */ int getpw(uid_t uid, char *buf) { @@ -419,6 +420,7 @@ int getpw(uid_t uid, char *buf) return -1; } +#endif /**********************************************************************/ @@ -620,43 +622,63 @@ struct spwd *sgetspent(const char *string) } #endif -int initgroups(const char *user, gid_t gid) +static gid_t *getgrouplist_internal(int *ngroups_ptr, const char *user, gid_t gid) { FILE *grfile; gid_t *group_list; - int num_groups, rv; - char **m; + int ngroups; struct group group; char buff[PWD_BUFFER_SIZE]; - rv = -1; - grfile = fopen_for_read(_PATH_GROUP); - if (grfile != NULL) { - - /* We alloc space for 8 gids at a time. */ - group_list = xmalloc(8 * sizeof(gid_t *)); - *group_list = gid; - num_groups = 1; + /* We alloc space for 8 gids at a time. */ + group_list = xmalloc(8 * sizeof(group_list[0])); + group_list[0] = gid; + ngroups = 1; + grfile = fopen_for_read(_PATH_GROUP); + if (grfile) { while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) { + char **m; assert(group.gr_mem); /* Must have at least a NULL terminator. */ - if (group.gr_gid != gid) { - for (m = group.gr_mem; *m; m++) { - if (!strcmp(*m, user)) { - group_list = xrealloc_vector(group_list, 3, num_groups); - group_list[num_groups++] = group.gr_gid; - break; - } - } + if (group.gr_gid == gid) + continue; + for (m = group.gr_mem; *m; m++) { + if (strcmp(*m, user) != 0) + continue; + group_list = xrealloc_vector(group_list, 3, ngroups); + group_list[ngroups++] = group.gr_gid; + break; } } - - rv = setgroups(num_groups, group_list); - free(group_list); fclose(grfile); } + *ngroups_ptr = ngroups; + return group_list; +} - return rv; +int initgroups(const char *user, gid_t gid) +{ + int ngroups; + gid_t *group_list = getgrouplist_internal(&ngroups, user, gid); + + ngroups = setgroups(ngroups, group_list); + free(group_list); + return ngroups; +} + +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ + int ngroups_old = *ngroups; + gid_t *group_list = getgrouplist_internal(ngroups, user, gid); + + if (*ngroups <= ngroups_old) { + ngroups_old = *ngroups; + memcpy(groups, group_list, ngroups_old * sizeof(groups[0])); + } else { + ngroups_old = -1; + } + free(group_list); + return ngroups_old; } int putpwent(const struct passwd *__restrict p, FILE *__restrict f) diff --git a/release/src/router/busybox/libpwdgrp/uidgid_get.c b/release/src/router/busybox/libpwdgrp/uidgid_get.c index ebc7fc58c4..92290bfdb6 100644 --- a/release/src/router/busybox/libpwdgrp/uidgid_get.c +++ b/release/src/router/busybox/libpwdgrp/uidgid_get.c @@ -87,15 +87,12 @@ void FAST_FUNC xget_uidgid(struct bb_uidgid_t *u, const char *ug) * ":group" sets gid only * "user:" sets uid and gid (to user's primary group id) * "user:group" sets uid and gid - * ('unset' uid or gid is actually set to -1) + * ('unset' uid or gid retains the value it has on entry) */ void FAST_FUNC parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group) { char *group; - u->uid = -1; - u->gid = -1; - /* Check if there is a group name */ group = strchr(user_group, '.'); /* deprecated? */ if (!group) diff --git a/release/src/router/busybox/loginutils/Config.in b/release/src/router/busybox/loginutils/Config.in index aca85a1ba6..ddd0c80151 100644 --- a/release/src/router/busybox/loginutils/Config.in +++ b/release/src/router/busybox/loginutils/Config.in @@ -58,7 +58,7 @@ config USE_BB_SHADOW password servers and whatnot. config USE_BB_CRYPT - bool "Use internal DES and MD5 crypt functions" + bool "Use internal crypt functions" default y help Busybox has internal DES and MD5 crypt functions. @@ -79,6 +79,18 @@ config USE_BB_CRYPT In static build, it makes code _smaller_ by about 1.2k, and likely many kilobytes less of bss. +config USE_BB_CRYPT_SHA + bool "Enable SHA256/512 crypt functions" + default n + depends on USE_BB_CRYPT + help + Enable this if you have passwords starting with "$5$" or "$6$" + in your /etc/passwd or /etc/shadow files. These passwords + are hashed using SHA256 and SHA512 algorithms. Support for them + was added to glibc in 2008. + With this option off, login will fail password check for any + user which has password encrypted with these algorithms. + config ADDGROUP bool "addgroup" default n @@ -230,15 +242,16 @@ config CRYPTPW bool "cryptpw" default n help - Applet for crypting a string. + Encrypts the given password with the crypt(3) libc function + using the given salt. Debian has this utility under mkpasswd + name. Busybox provides mkpasswd as an alias for cryptpw. config CHPASSWD - bool "chpasswd" - default n - help - chpasswd reads a file of user name and password pairs from - standard input and uses this information to update a group of - existing users. + bool "chpasswd" + default n + help + Reads a file of user name and password pairs from standard input + and uses this information to update a group of existing users. config SU bool "su" diff --git a/release/src/router/busybox/loginutils/addgroup.c b/release/src/router/busybox/loginutils/addgroup.c index 89414d7381..5a0cf3ffff 100644 --- a/release/src/router/busybox/loginutils/addgroup.c +++ b/release/src/router/busybox/loginutils/addgroup.c @@ -9,7 +9,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * */ - #include "libbb.h" static void xgroup_study(struct group *g) @@ -45,8 +44,8 @@ static void xgroup_study(struct group *g) /* append a new user to the passwd file */ static void new_group(char *group, gid_t gid) { - FILE *file; struct group gr; + char *p; /* make sure gid and group haven't already been allocated */ gr.gr_gid = gid; @@ -54,67 +53,17 @@ static void new_group(char *group, gid_t gid) xgroup_study(&gr); /* add entry to group */ - file = xfopen(bb_path_group_file, "a"); - /* group:passwd:gid:userlist */ - fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid); + p = xasprintf("x:%u:", gr.gr_gid); + if (update_passwd(bb_path_group_file, group, p, NULL) < 0) + exit(EXIT_FAILURE); if (ENABLE_FEATURE_CLEAN_UP) - fclose(file); + free(p); #if ENABLE_FEATURE_SHADOWPASSWDS - file = fopen_or_warn(bb_path_gshadow_file, "a"); - if (file) { - fprintf(file, "%s:!::\n", group); - if (ENABLE_FEATURE_CLEAN_UP) - fclose(file); - } + /* Ignore errors: if file is missing we suppose admin doesn't want it */ + update_passwd(bb_path_gshadow_file, group, "!::", NULL); #endif } -#if ENABLE_FEATURE_ADDUSER_TO_GROUP -static void add_user_to_group(char **args, - const char *path, - FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) -{ - char *line; - int len = strlen(args[1]); - llist_t *plist = NULL; - FILE *group_file; - - group_file = fopen_func(path, "r"); - - if (!group_file) return; - - while ((line = xmalloc_fgetline(group_file)) != NULL) { - /* Find the group */ - if (!strncmp(line, args[1], len) - && line[len] == ':' - ) { - /* Add the new user */ - line = xasprintf("%s%s%s", line, - last_char_is(line, ':') ? "" : ",", - args[0]); - } - llist_add_to_end(&plist, line); - } - - if (ENABLE_FEATURE_CLEAN_UP) { - fclose(group_file); - group_file = fopen_func(path, "w"); - while ((line = llist_pop(&plist))) { - if (group_file) - fprintf(group_file, "%s\n", line); - free(line); - } - if (group_file) - fclose(group_file); - } else { - group_file = fopen_func(path, "w"); - if (group_file) - while ((line = llist_pop(&plist))) - fprintf(group_file, "%s\n", line); - } -} -#endif - /* * addgroup will take a login_name as its first parameter. * @@ -158,19 +107,20 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv) /* check if group and user exist */ xuname2uid(argv[0]); /* unknown user: exit */ - xgroup2gid(argv[1]); /* unknown group: exit */ + gr = xgetgrnam(argv[1]); /* unknown group: exit */ /* check if user is already in this group */ - gr = getgrnam(argv[1]); for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) { if (!strcmp(argv[0], *(gr->gr_mem))) { /* user is already in group: do nothing */ return EXIT_SUCCESS; } } - add_user_to_group(argv, bb_path_group_file, xfopen); -#if ENABLE_FEATURE_SHADOWPASSWDS - add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn); -#endif + if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) { + return EXIT_FAILURE; + } +# if ENABLE_FEATURE_SHADOWPASSWDS + update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]); +# endif } else #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ { diff --git a/release/src/router/busybox/loginutils/adduser.c b/release/src/router/busybox/loginutils/adduser.c index 3154806b61..8a5d902e6b 100644 --- a/release/src/router/busybox/loginutils/adduser.c +++ b/release/src/router/busybox/loginutils/adduser.c @@ -7,14 +7,12 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ - #include "libbb.h" #define OPT_DONT_SET_PASS (1 << 4) #define OPT_SYSTEM_ACCOUNT (1 << 5) #define OPT_DONT_MAKE_HOME (1 << 6) - /* remix */ /* recoded such that the uid may be passed in *p */ static void passwd_study(struct passwd *p) @@ -33,18 +31,17 @@ static void passwd_study(struct passwd *p) } /* check for a free uid (and maybe gid) */ - while (getpwuid(p->pw_uid) || (!p->pw_gid && getgrgid(p->pw_uid))) + while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) { p->pw_uid++; + if (p->pw_uid > max) + bb_error_msg_and_die("no free uids left"); + } - if (!p->pw_gid) { - /* new gid = uid */ - p->pw_gid = p->pw_uid; + if (p->pw_gid == (gid_t)-1) { + p->pw_gid = p->pw_uid; /* new gid = uid */ if (getgrnam(p->pw_name)) bb_error_msg_and_die("group name '%s' is in use", p->pw_name); } - - if (p->pw_uid > max) - bb_error_msg_and_die("no free uids left"); } static void addgroup_wrapper(struct passwd *p) @@ -89,7 +86,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) { struct passwd pw; const char *usegroup = NULL; - FILE *file; + char *p; #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS applet_long_options = adduser_longopts; @@ -117,35 +114,24 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) pw.pw_dir = xasprintf("/home/%s", argv[0]); } pw.pw_passwd = (char *)"x"; - pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ + pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */ /* make sure everything is kosher and setup uid && maybe gid */ passwd_study(&pw); - /* add to passwd */ - file = xfopen(bb_path_passwd_file, "a"); - //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */ - if (putpwent(&pw, file) != 0) { - bb_perror_nomsg_and_die(); + p = xasprintf("x:%u:%u:%s:%s:%s", pw.pw_uid, pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell); + if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) { + return EXIT_FAILURE; } - /* do fclose even if !ENABLE_FEATURE_CLEAN_UP. - * We will exec passwd, files must be flushed & closed before that! */ - fclose(file); + if (ENABLE_FEATURE_CLEAN_UP) + free(p); #if ENABLE_FEATURE_SHADOWPASSWDS - /* add to shadow if necessary */ - file = fopen_or_warn(bb_path_shadow_file, "a"); - if (file) { - //fseek(file, 0, SEEK_END); - fprintf(file, "%s:!:%u:0:99999:7:::\n", - pw.pw_name, /* username */ - (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */ - /*0,*/ /* sp->sp_min */ - /*99999,*/ /* sp->sp_max */ - /*7*/ /* sp->sp_warn */ - ); - fclose(file); - } + p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL) / 86400)); /* sp->sp_lstchg */ + /* ignore errors: if file is missing we suppose admin doesn't want it */ + update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL); + if (ENABLE_FEATURE_CLEAN_UP) + free(p); #endif /* add to group */ @@ -154,7 +140,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) if (!usegroup) addgroup_wrapper(&pw); - /* Clear the umask for this process so it doesn't + /* clear the umask for this process so it doesn't * screw up the permissions on the mkdir and chown. */ umask(0); if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { diff --git a/release/src/router/busybox/loginutils/chpasswd.c b/release/src/router/busybox/loginutils/chpasswd.c index c83d1dad78..4bffbe83f1 100644 --- a/release/src/router/busybox/loginutils/chpasswd.c +++ b/release/src/router/busybox/loginutils/chpasswd.c @@ -5,7 +5,6 @@ * Written for SLIND (from passwd.c) by Alexander Shishkin * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #if ENABLE_GETOPT_LONG @@ -53,10 +52,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) /* 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); + rc = update_passwd(bb_path_shadow_file, name, pass, NULL); if (rc == 0) /* no lines updated, no errors detected */ #endif - rc = update_passwd(bb_path_passwd_file, name, pass); + rc = update_passwd(bb_path_passwd_file, name, pass, NULL); /* LOGMODE_BOTH logs to syslog also */ logmode = LOGMODE_BOTH; if (rc < 0) diff --git a/release/src/router/busybox/loginutils/cryptpw.c b/release/src/router/busybox/loginutils/cryptpw.c dissimilarity index 76% index db5d95920a..47212e18a0 100644 --- a/release/src/router/busybox/loginutils/cryptpw.c +++ b/release/src/router/busybox/loginutils/cryptpw.c @@ -1,58 +1,117 @@ -/* vi: set sw=4 ts=4: */ -/* - * cryptpw.c - * - * Cooked from passwd.c by Thomas Lundquist - */ - -#include "libbb.h" - -#define TESTING 0 - -/* -set TESTING to 1 and pipe some file through this script -if you played with bbox's crypt implementation. - -while read line; do - n=`./busybox cryptpw -a des -- "$line"` - o=`./busybox_org cryptpw -a des -- "$line"` - test "$n" != "$o" && { - echo n="$n" - echo o="$o" - exit - } - n=`./busybox cryptpw -- "$line"` - o=`./busybox_org cryptpw -- "$line"` - test "$n" != "$o" && { - echo n="$n" - echo o="$o" - exit - } -done - */ - -int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int cryptpw_main(int argc UNUSED_PARAM, char **argv) -{ - char salt[sizeof("$N$XXXXXXXX")]; - char *opt_a; - - if (!getopt32(argv, "a:", &opt_a) || opt_a[0] != 'd') { - salt[0] = '$'; - salt[1] = '1'; - salt[2] = '$'; - crypt_make_salt(salt + 3, 4, 0); /* md5 */ -#if TESTING - strcpy(salt + 3, "ajg./bcf"); -#endif - } else { - crypt_make_salt(salt, 1, 0); /* des */ -#if TESTING - strcpy(salt, "a."); -#endif - } - - puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_fgetline(stdin), salt, 1)); - - return 0; -} +/* vi: set sw=4 ts=4: */ +/* + * cryptpw.c - output a crypt(3)ed password to stdout. + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * Cooked from passwd.c by Thomas Lundquist + * mkpasswd compatible options added by Bernhard Reutner-Fischer + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +/* Debian has 'mkpasswd' utility, manpage says: + +NAME + mkpasswd - Overfeatured front end to crypt(3) +SYNOPSIS + mkpasswd PASSWORD SALT +... +OPTIONS +-S, --salt=STRING + Use the STRING as salt. It must not contain prefixes such as + $1$. +-R, --rounds=NUMBER + Use NUMBER rounds. This argument is ignored if the method + choosen does not support variable rounds. For the OpenBSD Blowfish + method this is the logarithm of the number of rounds. +-m, --method=TYPE + Compute the password using the TYPE method. If TYPE is 'help' + then the available methods are printed. +-P, --password-fd=NUM + Read the password from file descriptor NUM instead of using getpass(3). + If the file descriptor is not connected to a tty then + no other message than the hashed password is printed on stdout. +-s, --stdin + Like --password-fd=0. +ENVIRONMENT + $MKPASSWD_OPTIONS + A list of options which will be evaluated before the ones + specified on the command line. +BUGS + This programs suffers of a bad case of featuritis. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Very true... + +cryptpw was in bbox before this gem, so we retain it, and alias mkpasswd +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_ptr; + const char *opt_m, *opt_S; + int len; + int fd; + +#if ENABLE_GETOPT_LONG + static const char mkpasswd_longopts[] ALIGN1 = + "stdin\0" No_argument "s" + "password-fd\0" Required_argument "P" + "salt\0" Required_argument "S" + "method\0" Required_argument "m" + ; + applet_long_options = mkpasswd_longopts; +#endif + fd = STDIN_FILENO; + opt_m = "d"; + opt_S = NULL; + /* at most two non-option arguments; -P NUM */ + opt_complementary = "?2:P+"; + getopt32(argv, "sP:S:m:a:", &fd, &opt_S, &opt_m, &opt_m); + argv += optind; + + /* have no idea how to handle -s... */ + + 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 + } + if (opt_S) + safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3); + else + crypt_make_salt(salt_ptr, len, 0); + + xmove_fd(fd, STDIN_FILENO); + + puts(pw_encrypt( + argv[0] ? argv[0] : ( + /* Only mkpasswd, and only from tty, prompts. + * Otherwise it is a plain read. */ + (isatty(STDIN_FILENO) && applet_name[0] == 'm') + ? bb_ask_stdin("Password: ") + : xmalloc_fgetline(stdin) + ), + salt, 1)); + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/loginutils/deluser.c b/release/src/router/busybox/loginutils/deluser.c dissimilarity index 85% index 56253712e1..293e324b06 100644 --- a/release/src/router/busybox/loginutils/deluser.c +++ b/release/src/router/busybox/loginutils/deluser.c @@ -1,125 +1,56 @@ -/* vi: set sw=4 ts=4: */ -/* - * deluser/delgroup implementation for busybox - * - * Copyright (C) 1999 by Lineo, inc. and John Beppu - * Copyright (C) 1999,2000,2001 by John Beppu - * Copyright (C) 2007 by Tito Ragusa - * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. - * - */ - -#include "libbb.h" - -/* Status */ -#define STATUS_OK 0 -#define NAME_NOT_FOUND 1 -#define MEMBER_NOT_FOUND 2 - -static void del_line_matching(char **args, - const char *filename, - FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) -{ - FILE *passwd; - smallint error = NAME_NOT_FOUND; - char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1]; - char *line, *del; - char *new = xzalloc(1); - - passwd = fopen_func(filename, "r"); - if (passwd) { - while ((line = xmalloc_fgets(passwd))) { - int len = strlen(name); - - if (strncmp(line, name, len) == 0 - && line[len] == ':' - ) { - error = STATUS_OK; - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) { - struct group *gr; - char *p; - if (args[2] - /* There were two args on commandline */ - && (gr = getgrnam(name)) - /* The group was not deleted in the meanwhile */ - && (p = strrchr(line, ':')) - /* We can find a pointer to the last ':' */ - ) { - error = MEMBER_NOT_FOUND; - /* Move past ':' (worst case to '\0') and cut the line */ - p[1] = '\0'; - /* Reuse p */ - for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) { - /* Add all the other group members */ - if (strcmp(args[1], *gr->gr_mem) != 0) { - del = p; - p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem); - free(del); - } else - error = STATUS_OK; - } - /* Recompose the line */ - line = xasprintf("%s%s\n", line, p); - if (ENABLE_FEATURE_CLEAN_UP) free(p); - } else - goto skip; - } - } - del = new; - new = xasprintf("%s%s", new, line); - free(del); - skip: - free(line); - } - - if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); - - if (error) { - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) { - /* Set the correct values for error message */ - filename = name; - name = args[1]; - } - bb_error_msg("can't find %s in %s", name, filename); - } else { - passwd = fopen_func(filename, "w"); - if (passwd) { - fputs(new, passwd); - if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); - } - } - } - free(new); -} - -int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int deluser_main(int argc, char **argv) -{ - if (argc == 2 - || (ENABLE_FEATURE_DEL_USER_FROM_GROUP - && (applet_name[3] == 'g' && argc == 3)) - ) { - if (geteuid()) - bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); - - if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) - || ENABLE_DELUSER - || (ENABLE_DELGROUP && ENABLE_DESKTOP) - ) { - if (ENABLE_DELUSER - && (!ENABLE_DELGROUP || applet_name[3] == 'u') - ) { - del_line_matching(argv, bb_path_passwd_file, xfopen); - if (ENABLE_FEATURE_SHADOWPASSWDS) - del_line_matching(argv, bb_path_shadow_file, fopen_or_warn); - } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) - bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); - } - del_line_matching(argv, bb_path_group_file, xfopen); - if (ENABLE_FEATURE_SHADOWPASSWDS) - del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn); - return EXIT_SUCCESS; - } else - bb_show_usage(); -} +/* vi: set sw=4 ts=4: */ +/* + * deluser/delgroup implementation for busybox + * + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Copyright (C) 2007 by Tito Ragusa + * + * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * + */ +#include "libbb.h" + +static int del_line_matching(char **args, const char *filename) +{ + if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) { + return update_passwd(filename, args[2], NULL, args[1]); + } + return update_passwd(filename, args[1], NULL, NULL); +} + +int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int deluser_main(int argc, char **argv) +{ + if (argc != 2 + && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP + || (applet_name[3] != 'g' || argc != 3)) + ) { + bb_show_usage(); + } + + if (geteuid()) + bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); + + if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) + || ENABLE_DELUSER + || (ENABLE_DELGROUP && ENABLE_DESKTOP) + ) { + if (ENABLE_DELUSER + && (!ENABLE_DELGROUP || applet_name[3] == 'u') + ) { + if (del_line_matching(argv, bb_path_passwd_file) < 0) + return EXIT_FAILURE; + if (ENABLE_FEATURE_SHADOWPASSWDS) { + del_line_matching(argv, bb_path_shadow_file); + } + } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) + bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); + } + if (del_line_matching(argv, bb_path_group_file) < 0) + return EXIT_FAILURE; + if (ENABLE_FEATURE_SHADOWPASSWDS) { + del_line_matching(argv, bb_path_gshadow_file); + } + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/loginutils/getty.c b/release/src/router/busybox/loginutils/getty.c index 358a45c7cd..24a182ff40 100644 --- a/release/src/router/busybox/loginutils/getty.c +++ b/release/src/router/busybox/loginutils/getty.c @@ -19,7 +19,7 @@ #include #if ENABLE_FEATURE_UTMP -#include +#include /* updwtmp() */ #endif /* @@ -28,10 +28,6 @@ */ #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ #include -#include -#if ENABLE_FEATURE_WTMP -extern void updwtmp(const char *filename, const struct utmp *ut); -#endif #else /* if !sysV style, wtmp/utmp code is off */ #undef ENABLE_FEATURE_UTMP #undef ENABLE_FEATURE_WTMP @@ -167,8 +163,9 @@ static void parse_speeds(struct options *op, char *arg) debug("entered parse_speeds\n"); while ((cp = strsep(&arg, ",")) != NULL) { op->speeds[op->numspeed] = bcode(cp); - if (op->speeds[op->numspeed] <= 0) + 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"); @@ -274,6 +271,7 @@ static void open_tty(const char *tty) /* 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 @@ -282,12 +280,20 @@ static void termios_init(struct termios *tp, int speed, struct options *op) */ #ifdef __linux__ /* flush input and output queues, important for modems! */ - ioctl(0, TCFLSH, TCIOFLUSH); + ioctl(0, TCFLSH, TCIOFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ #endif - - tp->c_cflag = CS8 | HUPCL | CREAD | speed; + 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 = tp->c_line = 0; tp->c_oflag = OPOST | ONLCR; @@ -300,7 +306,7 @@ static void termios_init(struct termios *tp, int speed, struct options *op) tp->c_cflag |= CRTSCTS; #endif - ioctl(0, TCSETS, tp); + tcsetattr_stdin_TCSANOW(tp); debug("term_io 2\n"); } @@ -337,7 +343,7 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ vmin = tp->c_cc[VMIN]; tp->c_cc[VMIN] = 0; /* don't block if queue empty */ - ioctl(0, TCSETS, tp); + tcsetattr_stdin_TCSANOW(tp); /* * Wait for a while, then read everything the modem has said so far and @@ -362,7 +368,7 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) /* Restore terminal settings. Errors will be dealt with later on. */ tp->c_iflag = iflag; tp->c_cc[VMIN] = vmin; - ioctl(0, TCSETS, tp); + tcsetattr_stdin_TCSANOW(tp); } /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ @@ -407,7 +413,7 @@ static char *get_logname(char *logname, unsigned size_logname, /* Flush pending input (esp. after parsing or switching the baud rate). */ sleep(1); - ioctl(0, TCFLSH, TCIFLUSH); + ioctl(0, TCFLSH, TCIFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ /* Prompt for and read a login name. */ logname[0] = '\0'; @@ -477,7 +483,7 @@ static char *get_logname(char *logname, unsigned size_logname, case CTL('D'): exit(EXIT_SUCCESS); default: - if (!isascii(ascval) || !isprint(ascval)) { + if (!isprint(ascval)) { /* ignore garbage characters */ } else if ((int)(bp - logname) >= size_logname - 1) { bb_error_msg_and_die("%s: input overrun", op->tty); @@ -555,12 +561,13 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat } #endif /* Optionally enable hardware flow control */ -#ifdef CRTSCTS +#ifdef CRTSCTS if (op->flags & F_RTSCTS) tp->c_cflag |= CRTSCTS; #endif /* Finally, make the new settings effective */ + /* It's tcsetattr_stdin_TCSANOW() + error check */ ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); } @@ -692,6 +699,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) * by patching the SunOS kernel variable "zsadtrlow" to a larger value; * 5 seconds seems to be a good value. */ + /* tcgetattr() + error check */ ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty); #ifdef __linux__ @@ -715,6 +723,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) /* Write the modem init string and DON'T flush the buffers */ if (options.flags & F_INITSTRING) { debug("writing init string\n"); + /* todo: use xwrite_str? */ full_write(STDOUT_FILENO, options.initstring, strlen(options.initstring)); } @@ -754,9 +763,9 @@ int getty_main(int argc UNUSED_PARAM, char **argv) break; /* we are here only if options.numspeed > 1 */ baud_index = (baud_index + 1) % options.numspeed; - termios.c_cflag &= ~CBAUD; - termios.c_cflag |= options.speeds[baud_index]; - ioctl(0, TCSETS, &termios); + cfsetispeed(&termios, options.speeds[baud_index]); + cfsetospeed(&termios, options.speeds[baud_index]); + tcsetattr_stdin_TCSANOW(&termios); } } diff --git a/release/src/router/busybox/loginutils/login.c b/release/src/router/busybox/loginutils/login.c index 8732b99f1e..d57d529c03 100644 --- a/release/src/router/busybox/loginutils/login.c +++ b/release/src/router/busybox/loginutils/login.c @@ -52,7 +52,7 @@ static char* short_tty; * command line flags. */ -static void read_or_build_utent(struct utmp *utptr, int picky) +static void read_or_build_utent(struct utmp *utptr, int run_by_root) { struct utmp *ut; pid_t pid = getpid(); @@ -60,30 +60,33 @@ static void read_or_build_utent(struct utmp *utptr, int picky) setutent(); /* First, try to find a valid utmp entry for this process. */ - while ((ut = getutent())) - if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && - (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) - break; + /* If there is one, just use it. */ + while ((ut = getutent()) != NULL) + if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] + && (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS) + ) { + *utptr = *ut; /* struct copy */ + if (run_by_root) /* why only for root? */ + memset(utptr->ut_host, 0, sizeof(utptr->ut_host)); + return; + } - /* If there is one, just use it, otherwise create a new one. */ - if (ut) { - *utptr = *ut; - } else { - if (picky) - bb_error_msg_and_die("no utmp entry found"); - - memset(utptr, 0, sizeof(*utptr)); - utptr->ut_type = LOGIN_PROCESS; - utptr->ut_pid = pid; - strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line)); - /* This one is only 4 chars wide. Try to fit something - * remotely meaningful by skipping "tty"... */ - strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id)); - strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user)); - utptr->ut_tv.tv_sec = time(NULL); - } - if (!picky) /* root login */ - memset(utptr->ut_host, 0, sizeof(utptr->ut_host)); +// Why? Do we require non-root to exec login from another +// former login process (e.g. login shell)? Some login's have +// login shells as children, so it won't work... +// if (!run_by_root) +// bb_error_msg_and_die("no utmp entry found"); + + /* Otherwise create a new one. */ + memset(utptr, 0, sizeof(*utptr)); + utptr->ut_type = LOGIN_PROCESS; + utptr->ut_pid = pid; + strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line)); + /* This one is only 4 chars wide. Try to fit something + * remotely meaningful by skipping "tty"... */ + strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id)); + strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user)); + utptr->ut_tv.tv_sec = time(NULL); } /* @@ -109,7 +112,7 @@ static void write_utent(struct utmp *utptr, const char *username) #endif } #else /* !ENABLE_FEATURE_UTMP */ -#define read_or_build_utent(utptr, picky) ((void)0) +#define read_or_build_utent(utptr, run_by_root) ((void)0) #define write_utent(utptr, username) ((void)0) #endif /* !ENABLE_FEATURE_UTMP */ @@ -118,18 +121,25 @@ static void die_if_nologin(void) { FILE *fp; int c; + int empty = 1; - if (access("/etc/nologin", F_OK)) + fp = fopen_for_read("/etc/nologin"); + if (!fp) /* assuming it does not exist */ return; - fp = fopen_for_read("/etc/nologin"); - if (fp) { - while ((c = getc(fp)) != EOF) - bb_putchar((c=='\n') ? '\r' : c); - fflush(stdout); - fclose(fp); - } else + while ((c = getc(fp)) != EOF) { + if (c == '\n') + bb_putchar('\r'); + bb_putchar(c); + empty = 0; + } + if (empty) puts("\r\nSystem closed for routine maintenance\r"); + + fclose(fp); + fflush(NULL); + /* Users say that they do need this prior to exit: */ + tcdrain(STDOUT_FILENO); exit(EXIT_FAILURE); } #else @@ -155,6 +165,56 @@ static int check_securetty(void) static ALWAYS_INLINE int check_securetty(void) { return 1; } #endif +#if ENABLE_SELINUX +static void initselinux(char *username, char *full_tty, + security_context_t *user_sid) +{ + security_context_t old_tty_sid, new_tty_sid; + + if (!is_selinux_enabled()) + return; + + if (get_default_context(username, NULL, user_sid)) { + bb_error_msg_and_die("cannot get SID for %s", username); + } + if (getfilecon(full_tty, &old_tty_sid) < 0) { + bb_perror_msg_and_die("getfilecon(%s) failed", full_tty); + } + if (security_compute_relabel(*user_sid, old_tty_sid, + SECCLASS_CHR_FILE, &new_tty_sid) != 0) { + bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty); + } + if (setfilecon(full_tty, new_tty_sid) != 0) { + bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid); + } +} +#endif + +#if ENABLE_LOGIN_SCRIPTS +static void run_login_script(struct passwd *pw, char *full_tty) +{ + char *t_argv[2]; + + t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT"); + if (t_argv[0]) { + t_argv[1] = NULL; + xsetenv("LOGIN_TTY", full_tty); + xsetenv("LOGIN_USER", pw->pw_name); + xsetenv("LOGIN_UID", utoa(pw->pw_uid)); + xsetenv("LOGIN_GID", utoa(pw->pw_gid)); + xsetenv("LOGIN_SHELL", pw->pw_shell); + spawn_and_wait(t_argv); /* NOMMU-friendly */ + unsetenv("LOGIN_TTY"); + unsetenv("LOGIN_USER"); + unsetenv("LOGIN_UID"); + unsetenv("LOGIN_GID"); + unsetenv("LOGIN_SHELL"); + } +} +#else +void run_login_script(struct passwd *pw, char *full_tty); +#endif + static void get_username_or_die(char *buf, int size_buf) { int c, cntdown; @@ -218,13 +278,13 @@ int login_main(int argc UNUSED_PARAM, char **argv) char *fromhost; char username[USERNAME_SIZE]; const char *tmp; - int amroot; + int run_by_root; unsigned opt; int count = 0; struct passwd *pw; char *opt_host = opt_host; /* for compiler */ char *opt_user = opt_user; /* for compiler */ - char full_tty[TTYNAME_SIZE]; + char *full_tty; USE_SELINUX(security_context_t user_sid = NULL;) USE_FEATURE_UTMP(struct utmp utent;) #if ENABLE_PAM @@ -236,13 +296,13 @@ int login_main(int argc UNUSED_PARAM, char **argv) char pwdbuf[256]; #endif - short_tty = full_tty; username[0] = '\0'; signal(SIGALRM, alarm_handler); alarm(TIMEOUT); - /* More of suid paranoia if called by non-root */ - amroot = !sanitize_env_if_suid(); /* Clear dangerous stuff, set PATH */ + /* More of suid paranoia if called by non-root: */ + /* Clear dangerous stuff, set PATH */ + run_by_root = !sanitize_env_if_suid(); /* Mandatory paranoia for suid applet: * ensure that fd# 0,1,2 are opened (at least to /dev/null) @@ -252,7 +312,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); if (opt & LOGIN_OPT_f) { - if (!amroot) + if (!run_by_root) bb_error_msg_and_die("-f is for root only"); safe_strncpy(username, opt_user, sizeof(username)); } @@ -261,30 +321,28 @@ int login_main(int argc UNUSED_PARAM, char **argv) safe_strncpy(username, argv[0], sizeof(username)); /* Let's find out and memorize our tty */ - if (!isatty(0) || !isatty(1) || !isatty(2)) + if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) return EXIT_FAILURE; /* Must be a terminal */ - safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty)); - tmp = ttyname(0); - if (tmp) { - safe_strncpy(full_tty, tmp, sizeof(full_tty)); - if (strncmp(full_tty, "/dev/", 5) == 0) - short_tty = full_tty + 5; - } + full_tty = xmalloc_ttyname(STDIN_FILENO); + if (!full_tty) + full_tty = xstrdup("UNKNOWN"); + short_tty = full_tty; + if (strncmp(full_tty, "/dev/", 5) == 0) + short_tty += 5; - read_or_build_utent(&utent, !amroot); + read_or_build_utent(&utent, run_by_root); if (opt & LOGIN_OPT_h) { - USE_FEATURE_UTMP( - safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); - ) + USE_FEATURE_UTMP(safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));) fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host); - } else + } else { fromhost = xasprintf(" on '%s'", short_tty); + } /* Was breaking "login " from shell command line: */ /*bb_setpgrp();*/ - openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); + openlog(applet_name, LOG_PID | LOG_CONS, LOG_AUTH); while (1) { /* flush away any type-ahead (as getty does) */ @@ -389,62 +447,26 @@ int login_main(int argc UNUSED_PARAM, char **argv) return EXIT_FAILURE; } username[0] = '\0'; - } + } /* while (1) */ alarm(0); - if (!amroot) + /* We can ignore /etc/nologin if we are logging in as root, + * it doesn't matter whether we are run by root or not */ + if (pw->pw_uid != 0) die_if_nologin(); write_utent(&utent, username); -#if ENABLE_SELINUX - if (is_selinux_enabled()) { - security_context_t old_tty_sid, new_tty_sid; + USE_SELINUX(initselinux(username, full_tty, &user_sid)); - if (get_default_context(username, NULL, &user_sid)) { - bb_error_msg_and_die("cannot get SID for %s", - username); - } - if (getfilecon(full_tty, &old_tty_sid) < 0) { - bb_perror_msg_and_die("getfilecon(%s) failed", - full_tty); - } - if (security_compute_relabel(user_sid, old_tty_sid, - SECCLASS_CHR_FILE, &new_tty_sid) != 0) { - bb_perror_msg_and_die("security_change_sid(%s) failed", - full_tty); - } - if (setfilecon(full_tty, new_tty_sid) != 0) { - bb_perror_msg_and_die("chsid(%s, %s) failed", - full_tty, new_tty_sid); - } - } -#endif /* Try these, but don't complain if they fail. * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ fchown(0, pw->pw_uid, pw->pw_gid); fchmod(0, 0600); /* We trust environment only if we run by root */ - if (ENABLE_LOGIN_SCRIPTS && amroot) { - char *t_argv[2]; - - t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT"); - if (t_argv[0]) { - t_argv[1] = NULL; - xsetenv("LOGIN_TTY", full_tty); - xsetenv("LOGIN_USER", pw->pw_name); - xsetenv("LOGIN_UID", utoa(pw->pw_uid)); - xsetenv("LOGIN_GID", utoa(pw->pw_gid)); - xsetenv("LOGIN_SHELL", pw->pw_shell); - spawn_and_wait(t_argv); /* NOMMU-friendly */ - unsetenv("LOGIN_TTY" ); - unsetenv("LOGIN_USER" ); - unsetenv("LOGIN_UID" ); - unsetenv("LOGIN_GID" ); - unsetenv("LOGIN_SHELL"); - } - } + if (ENABLE_LOGIN_SCRIPTS && run_by_root) + run_login_script(pw, full_tty); change_identity(pw); tmp = pw->pw_shell; @@ -457,11 +479,10 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (pw->pw_uid == 0) syslog(LOG_INFO, "root login%s", fromhost); -#if ENABLE_SELINUX + /* well, a simple setexeccon() here would do the job as well, * but let's play the game for now */ - set_current_security_context(user_sid); -#endif + USE_SELINUX(set_current_security_context(user_sid);) // util-linux login also does: // /* start new session */ @@ -472,14 +493,16 @@ int login_main(int argc UNUSED_PARAM, char **argv) // bb_setpgrp(); // If this stuff is really needed, add it and explain why! - /* set signals to defaults */ - signal(SIGALRM, SIG_DFL); + /* Set signals to defaults */ + /* Non-ignored signals revert to SIG_DFL on exec anyway */ + /*signal(SIGALRM, SIG_DFL);*/ + /* Is this correct? This way user can ctrl-c out of /etc/profile, * potentially creating security breach (tested with bash 3.0). * But without this, bash 3.0 will not enable ctrl-c either. * Maybe bash is buggy? * Need to find out what standards say about /bin/login - - * should it leave SIGINT etc enabled or disabled? */ + * should we leave SIGINT etc enabled or disabled? */ signal(SIGINT, SIG_DFL); /* Exec login shell with no additional parameters */ diff --git a/release/src/router/busybox/loginutils/passwd.c b/release/src/router/busybox/loginutils/passwd.c index 99fb76ecae..7b93713b9c 100644 --- a/release/src/router/busybox/loginutils/passwd.c +++ b/release/src/router/busybox/loginutils/passwd.c @@ -2,7 +2,6 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #include @@ -22,7 +21,7 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) if (myuid && pw->pw_passwd[0]) { char *encrypted; - orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ + orig = bb_ask_stdin("Old password:"); /* returns ptr to static */ if (!orig) goto err_ret; encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */ @@ -35,16 +34,16 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) } if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); } - orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ - newp = bb_askpass(0, "New password:"); /* returns ptr to static */ + orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ + newp = bb_ask_stdin("New password:"); /* returns ptr to static */ if (!newp) goto err_ret; - newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */ + 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) goto err_ret; /* non-root is not allowed to have weak passwd */ - cp = bb_askpass(0, "Retype password:"); + cp = bb_ask_stdin("Retype password:"); if (!cp) goto err_ret; if (strcmp(cp, newp)) { @@ -100,7 +99,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) #endif logmode = LOGMODE_BOTH; - openlog(applet_name, LOG_NOWAIT, LOG_AUTH); + openlog(applet_name, 0, LOG_AUTH); opt = getopt32(argv, "a:lud", &opt_a); //argc -= optind; argv += optind; @@ -115,12 +114,10 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); /* Will complain and die if username not found */ - myname = xstrdup(bb_getpwuid(NULL, -1, myuid)); + myname = xstrdup(xuid2uname(myuid)); name = argv[0] ? argv[0] : myname; - pw = getpwnam(name); - if (!pw) - bb_error_msg_and_die("unknown user %s", name); + pw = xgetpwnam(name); if (myuid && pw->pw_uid != myuid) { /* LOGMODE_BOTH */ bb_error_msg_and_die("%s can't change password for %s", myname, name); @@ -183,12 +180,12 @@ 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); + rc = update_passwd(bb_path_shadow_file, name, newp, NULL); if (rc == 0) /* no lines updated, no errors detected */ #endif { filename = bb_path_passwd_file; - rc = update_passwd(bb_path_passwd_file, name, newp); + rc = update_passwd(bb_path_passwd_file, name, newp, NULL); } /* LOGMODE_BOTH */ if (rc < 0) diff --git a/release/src/router/busybox/loginutils/su.c b/release/src/router/busybox/loginutils/su.c index 61039d823f..de8c18d25e 100644 --- a/release/src/router/busybox/loginutils/su.c +++ b/release/src/router/busybox/loginutils/su.c @@ -44,13 +44,11 @@ int su_main(int argc UNUSED_PARAM, char **argv) But getlogin can fail -- usually due to lack of utmp entry. in this case resort to getpwuid. */ old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : ""); - tty = ttyname(2) ? : "none"; + tty = xmalloc_ttyname(2) ? : "none"; openlog(applet_name, 0, LOG_AUTH); } - pw = getpwnam(opt_username); - if (!pw) - bb_error_msg_and_die("unknown id: %s", opt_username); + pw = xgetpwnam(opt_username); /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER is a username that is retrieved via NIS (YP), but that doesn't have diff --git a/release/src/router/busybox/loginutils/sulogin.c b/release/src/router/busybox/loginutils/sulogin.c index bfd42569ab..4ffefe933b 100644 --- a/release/src/router/busybox/loginutils/sulogin.c +++ b/release/src/router/busybox/loginutils/sulogin.c @@ -32,11 +32,12 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "t+"; /* -t N */ getopt32(argv, "t:", &timeout); + argv += optind; - if (argv[optind]) { + if (argv[0]) { close(0); close(1); - dup(xopen(argv[optind], O_RDWR)); + dup(xopen(argv[0], O_RDWR)); close(2); dup(0); } @@ -50,7 +51,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) /* Clear dangerous stuff, set PATH */ sanitize_env_if_suid(); -// bb_askpass() already handles this +// bb_ask() already handles this // signal(SIGALRM, catchalarm); pwd = getpwuid(0); @@ -76,7 +77,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) int r; /* cp points to a static buffer that is zeroed every time */ - cp = bb_askpass(timeout, + cp = bb_ask(STDIN_FILENO, timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):"); diff --git a/release/src/router/busybox/loginutils/vlock.c b/release/src/router/busybox/loginutils/vlock.c index 42ef447326..85f489c228 100644 --- a/release/src/router/busybox/loginutils/vlock.c +++ b/release/src/router/busybox/loginutils/vlock.c @@ -38,14 +38,9 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) struct termios term; struct termios oterm; struct vt_mode ovtm; - uid_t uid; struct passwd *pw; -/* XXX: xgetpwuid */ - uid = getuid(); - pw = getpwuid(uid); - if (pw == NULL) - bb_error_msg_and_die("unknown uid %d", (int)uid); + pw = xgetpwuid(getuid()); opt_complementary = "=0"; /* no params! */ getopt32(argv, "a"); @@ -87,7 +82,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) term.c_iflag |= IGNBRK; term.c_lflag &= ~ISIG; term.c_lflag &= ~(ECHO | ECHOCTL); - tcsetattr(STDIN_FILENO, TCSANOW, &term); + tcsetattr_stdin_TCSANOW(&term); do { printf("Virtual console%s locked by %s.\n", @@ -101,6 +96,6 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) } while (1); ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); - tcsetattr(STDIN_FILENO, TCSANOW, &oterm); + tcsetattr_stdin_TCSANOW(&oterm); fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/release/src/router/busybox/mailutils/Config.in b/release/src/router/busybox/mailutils/Config.in new file mode 100644 index 0000000000..519d562ae6 --- /dev/null +++ b/release/src/router/busybox/mailutils/Config.in @@ -0,0 +1,53 @@ +menu "Mail Utilities" + +config MAKEMIME + bool "makemime" + default n + help + Create MIME-formatted messages. + +config FEATURE_MIME_CHARSET + string "Default charset" + default "us-ascii" + depends on MAKEMIME || REFORMIME || SENDMAIL + help + Default charset of the message. + +config POPMAILDIR + bool "popmaildir" + default n + help + Simple yet powerful POP3 mail popper. Delivers content + of remote mailboxes to local Maildir. + +config FEATURE_POPMAILDIR_DELIVERY + bool "Allow message filters and custom delivery program" + default n + depends on POPMAILDIR + help + Allow to use a custom program to filter the content + of the message before actual delivery (-F "prog [args...]"). + Allow to use a custom program for message actual delivery + (-M "prog [args...]"). + +config REFORMIME + bool "reformime" + default n + help + Parse MIME-formatted messages. + +config FEATURE_REFORMIME_COMPAT + bool "Accept and ignore options other than -x and -X" + default y + depends on REFORMIME + help + Accept (for compatibility only) and ignore options + other than -x and -X. + +config SENDMAIL + bool "sendmail" + default n + help + Barebones sendmail. + +endmenu diff --git a/release/src/router/busybox/mailutils/Kbuild b/release/src/router/busybox/mailutils/Kbuild new file mode 100644 index 0000000000..871e879810 --- /dev/null +++ b/release/src/router/busybox/mailutils/Kbuild @@ -0,0 +1,11 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= +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 new file mode 100644 index 0000000000..68883ff42c --- /dev/null +++ b/release/src/router/busybox/mailutils/mail.c @@ -0,0 +1,248 @@ +/* vi: set sw=4 ts=4: */ +/* + * helper routines + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include "mail.h" + +static void kill_helper(void) +{ + if (G.helper_pid > 0) { + kill(G.helper_pid, SIGTERM); + G.helper_pid = 0; + } +} + +// generic signal handler +static void signal_handler(int signo) +{ +#define err signo + if (SIGALRM == signo) { + kill_helper(); + bb_error_msg_and_die("timed out"); + } + + // SIGCHLD. reap zombies + if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) { + if (WIFSIGNALED(err)) + bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err)); + if (WIFEXITED(err)) { + G.helper_pid = 0; + if (WEXITSTATUS(err)) + bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err)); + } + } +#undef err +} + +void FAST_FUNC launch_helper(const char **argv) +{ + // setup vanilla unidirectional pipes interchange + int i; + int pipes[4]; + + xpipe(pipes); + xpipe(pipes + 2); + + // NB: handler must be installed before vfork + bb_signals(0 + + (1 << SIGCHLD) + + (1 << SIGALRM) + , signal_handler); + + G.helper_pid = vfork(); + if (G.helper_pid < 0) + bb_perror_msg_and_die("vfork"); + + 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 + + if (!G.helper_pid) { + // child: try to execute connection helper + // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec + BB_EXECVP(*argv, (char **)argv); + _exit(127); + } + + // parent + // check whether child is alive + //redundant:signal_handler(SIGCHLD); + // child seems OK -> parent goes on + atexit(kill_helper); +} + +const FAST_FUNC char *command(const char *fmt, const char *param) +{ + const char *msg = fmt; + if (timeout) + alarm(timeout); + if (msg) { + msg = xasprintf(fmt, param); + printf("%s\r\n", msg); + } + fflush(stdout); + return msg; +} + +// 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) +{ + // parse [user[:pass]@]host + // return host + char *s = strchr(url, '@'); + *user = *pass = NULL; + if (s) { + *s++ = '\0'; + *user = url; + url = s; + s = strchr(*user, ':'); + if (s) { + *s++ = '\0'; + *pass = s; + } + } + return url; +} +*/ + +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 */ + DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), + }; + +#define src_buf text + FILE *fp = fp; + ssize_t len = len; + char dst_buf[DST_BUF_SIZE + 1]; + + if (fname) { + fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : (FILE *)text; + src_buf = bb_common_bufsiz1; + // N.B. strlen(NULL) segfaults! + } else if (text) { + // though we do not call uuencode(NULL, NULL) explicitly + // still we do not want to break things suddenly + len = strlen(text); + } else + return; + + while (1) { + size_t size; + if (fname) { + size = fread((char *)src_buf, 1, SRC_BUF_SIZE, fp); + if ((ssize_t)size < 0) + bb_perror_msg_and_die(bb_msg_read_error); + } else { + size = len; + if (len > SRC_BUF_SIZE) + size = SRC_BUF_SIZE; + } + if (!size) + break; + // encode the buffer we just read in + bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); + if (fname) { + printf("%s\n", eol); + } else { + src_buf += size; + len -= size; + } + fwrite(dst_buf, 1, 4 * ((size + 2) / 3), stdout); + } + if (fname && NOT_LONE_DASH(fname)) + fclose(fp); +#undef src_buf +} + +void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream) +{ + int term_count = 1; + + while (1) { + char translated[4]; + int count = 0; + + while (count < 4) { + char *table_ptr; + int ch; + + /* Get next _valid_ character. + * global vector bb_uuenc_tbl_base64[] contains this string: + * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" + */ + do { + ch = fgetc(src_stream); + if (ch == EOF) { + bb_error_msg_and_die(bb_msg_read_error); + } + // - means end of MIME section + if ('-' == ch) { + // push it back + ungetc(ch, src_stream); + return; + } + table_ptr = strchr(bb_uuenc_tbl_base64, ch); + } while (table_ptr == NULL); + + /* Convert encoded character to decimal */ + ch = table_ptr - bb_uuenc_tbl_base64; + + if (*table_ptr == '=') { + if (term_count == 0) { + translated[count] = '\0'; + break; + } + term_count++; + } else if (*table_ptr == '\n') { + /* Check for terminating line */ + if (term_count == 5) { + return; + } + term_count = 1; + continue; + } else { + translated[count] = ch; + count++; + term_count = 0; + } + } + + /* Merge 6 bit chars to 8 bit */ + if (count > 1) { + fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); + } + if (count > 2) { + fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); + } + if (count > 3) { + fputc(translated[2] << 6 | translated[3], dst_stream); + } + } +} + + +/* + * get username and password from a file descriptor + */ +void FAST_FUNC get_cred_or_die(int fd) +{ + if (isatty(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); + } + 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 new file mode 100644 index 0000000000..bb747c4c52 --- /dev/null +++ b/release/src/router/busybox/mailutils/mail.h @@ -0,0 +1,35 @@ + +struct globals { + pid_t helper_pid; + unsigned timeout; + 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 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); + +const FAST_FUNC char *command(const char *fmt, const char *param); + +void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); +void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream); diff --git a/release/src/router/busybox/mailutils/mime.c b/release/src/router/busybox/mailutils/mime.c new file mode 100644 index 0000000000..bda727b7c8 --- /dev/null +++ b/release/src/router/busybox/mailutils/mime.c @@ -0,0 +1,354 @@ +/* vi: set sw=4 ts=4: */ +/* + * makemime: create MIME-encoded message + * reformime: parse MIME-encoded message + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include "mail.h" + +/* + 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 ther 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. +*/ + +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; +#define boundary opt_output + + enum { + OPT_c = 1 << 0, // Content-Type: + 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, // COMPAT + OPT_j = 1 << 7, // COMPAT + }; + + INIT_G(); + + // parse options + opt_complementary = "a::"; + opts = getopt32(argv, + "c:e:o:C:N:a:m:j:", + &G.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("%d-%d-%d", rand(), rand(), 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 + , G.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 +} + +static const char *find_token(const char *const string_array[], const char *key, const char *defvalue) +{ + const char *r = NULL; + for (int i = 0; string_array[i] != 0; 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("header: %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) +{ + char *line, *s, *p; + const char *type; + int boundary_len = strlen(boundary); + const char *delims = " ;\"\t\r\n"; + const char *uniq; + int ntokens; + const char *tokens[32]; // 32 is enough + + // prepare unique string pattern + uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname()); + +//bb_info_msg("PARSE[%s]", terminator); + + while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) { + + // seek to start of MIME section + // N.B. to avoid false positives let us seek to the _last_ occurance + p = NULL; + s = line; + while ((s=strcasestr(s, "Content-Type:")) != NULL) + p = s++; + if (!p) + goto next; +//bb_info_msg("L[%s]", p); + + // split to tokens + // TODO: strip of comments which are of form: (comment-text) + ntokens = 0; + tokens[ntokens] = NULL; + for (s = strtok(p, delims); s; s = strtok(NULL, delims)) { + tokens[ntokens] = s; + if (ntokens < ARRAY_SIZE(tokens) - 1) + ntokens++; +//bb_info_msg("L[%d][%s]", ntokens, s); + } + tokens[ntokens] = NULL; +//bb_info_msg("N[%d]", ntokens); + + // analyse tokens + type = find_token(tokens, "Content-Type:", "text/plain"); +//bb_info_msg("T[%s]", type); + if (0 == strncasecmp(type, "multipart/", 10)) { + if (0 == strcasecmp(type+10, "mixed")) { + parse(xfind_token(tokens, "boundary="), argv); + } else + bb_error_msg_and_die("no support of content type '%s'", type); + } else { + pid_t pid = pid; + int rc; + FILE *fp; + // fetch charset + const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET); + // fetch encoding + 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)); + + // start external helper, if any + if (opts & OPT_X) { + int fd[2]; + xpipe(fd); + pid = vfork(); + if (0 == pid) { + // child reads from fd[0] + xdup2(fd[0], STDIN_FILENO); + close(fd[0]); close(fd[1]); + xsetenv("CONTENT_TYPE", type); + xsetenv("CHARSET", charset); + xsetenv("ENCODING", encoding); + xsetenv("FILENAME", filename); + BB_EXECVP(*argv, argv); + _exit(EXIT_FAILURE); + } + // parent dumps to fd[1] + close(fd[0]); + fp = fdopen(fd[1], "w"); + signal(SIGPIPE, SIG_IGN); // ignore EPIPE + // or create a file for dump + } else { + char *fname = xasprintf("%s%s", *argv, filename); + fp = xfopen_for_write(fname); + free(fname); + } + + // housekeeping + free(filename); + + // dump to fp + if (0 == strcasecmp(encoding, "base64")) { + decode_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("no support of encoding '%s'", encoding); + } else { + // N.B. we have written redundant \n. so truncate the file + // The following weird 2-tacts reading technique is due to + // we have to not write extra \n at the end of the file + // In case of -x option we could truncate the resulting file as + // fseek(fp, -1, SEEK_END); + // if (ftruncate(fileno(fp), ftell(fp))) + // bb_perror_msg("ftruncate"); + // But in case of -X we have to be much more careful. There is + // no means to truncate what we already have sent to the helper. + p = xmalloc_fgets_str(stdin, "\r\n"); + while (p) { + if ((s = xmalloc_fgets_str(stdin, "\r\n")) == NULL) + break; + if ('-' == s[0] && '-' == s[1] + && 0 == strncmp(s+2, boundary, boundary_len)) + break; + fputs(p, fp); + p = s; + } + +/* + while ((s = xmalloc_fgetline_str(stdin, "\r\n")) != NULL) { + if ('-' == s[0] && '-' == s[1] + && 0 == strncmp(s+2, boundary, boundary_len)) + break; + fprintf(fp, "%s\n", s); + } + // N.B. we have written redundant \n. so truncate the file + fseek(fp, -1, SEEK_END); + if (ftruncate(fileno(fp), ftell(fp))) + bb_perror_msg("ftruncate"); +*/ + } + fclose(fp); + + // finalize helper + if (opts & OPT_X) { + signal(SIGPIPE, SIG_DFL); + // exit if helper exited >0 + rc = wait4pid(pid); + if (rc) + return rc+20; + } + + // check multipart finalized + if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) { + free(line); + break; + } + } + next: + free(line); + } + +//bb_info_msg("ENDPARSE[%s]", boundary); + + return EXIT_SUCCESS; +} + +/* +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" USE_FEATURE_REFORMIME_COMPAT(":m::"); + opts = getopt32(argv, + "x:X" USE_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"), + &opt_prefix + USE_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) + ); + //argc -= optind; + argv += optind; + + return parse("", (opts & OPT_X) ? argv : (char **)&opt_prefix); +} diff --git a/release/src/router/busybox/mailutils/popmaildir.c b/release/src/router/busybox/mailutils/popmaildir.c new file mode 100644 index 0000000000..1a72b87c58 --- /dev/null +++ b/release/src/router/busybox/mailutils/popmaildir.c @@ -0,0 +1,235 @@ +/* vi: set sw=4 ts=4: */ +/* + * popmaildir: a simple yet powerful POP3 client + * Delivers contents of remote mailboxes to local Maildir + * + * Inspired by original utility by Nikola Vladov + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include "mail.h" + +static void pop3_checkr(const char *fmt, const char *param, char **ret) +{ + const char *msg = command(fmt, param); + char *answer = xmalloc_fgetline(stdin); + if (answer && '+' == answer[0]) { + if (timeout) + alarm(0); + if (ret) { + // skip "+OK " + memmove(answer, answer + 4, strlen(answer) - 4); + *ret = answer; + } else + free(answer); + return; + } + bb_error_msg_and_die("%s failed: %s", msg, answer); +} + +static void pop3_check(const char *fmt, const char *param) +{ + pop3_checkr(fmt, param, NULL); +} + +int popmaildir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int popmaildir_main(int argc UNUSED_PARAM, char **argv) +{ + char *buf; + unsigned nmsg; + char *hostname; + pid_t pid; + const char *retr; +#if ENABLE_FEATURE_POPMAILDIR_DELIVERY + const char *delivery; +#endif + unsigned opt_nlines = 0; + + enum { + OPT_b = 1 << 0, // -b binary mode. Ignored + OPT_d = 1 << 1, // -d,-dd,-ddd debug. Ignored + OPT_m = 1 << 2, // -m show used memory. Ignored + OPT_V = 1 << 3, // -V version. Ignored + OPT_c = 1 << 4, // -c use tcpclient. Ignored + OPT_a = 1 << 5, // -a use APOP protocol + OPT_s = 1 << 6, // -s skip authorization + OPT_T = 1 << 7, // -T get messages with TOP instead with RETR + OPT_k = 1 << 8, // -k keep retrieved messages on the server + OPT_t = 1 << 9, // -t90 set timeout to 90 sec + OPT_R = 1 << 10, // -R20000 remove old messages on the server >= 20000 bytes (requires -k). Ignored + OPT_Z = 1 << 11, // -Z11-23 remove messages from 11 to 23 (dangerous). Ignored + OPT_L = 1 << 12, // -L50000 not retrieve new messages >= 50000 bytes. Ignored + OPT_H = 1 << 13, // -H30 type first 30 lines of a message; (-L12000 -H30). Ignored + OPT_M = 1 << 14, // -M\"program arg1 arg2 ...\"; deliver by program. Treated like -F + OPT_F = 1 << 15, // -F\"program arg1 arg2 ...\"; filter by program. Treated like -M + }; + + // init global variables + INIT_G(); + + // parse options + opt_complementary = "-1:dd:t+:R+:L+:H+"; + opts = getopt32(argv, + "bdmVcasTkt:" "R:Z:L:H:" USE_FEATURE_POPMAILDIR_DELIVERY("M:F:"), + &timeout, NULL, NULL, NULL, &opt_nlines + USE_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same + ); + //argc -= optind; + argv += optind; + + // get auth info + if (!(opts & OPT_s)) + get_cred_or_die(STDIN_FILENO); + + // goto maildir + xchdir(*argv++); + + // launch connect helper, if any + if (*argv) + launch_helper((const char **)argv); + + // get server greeting + pop3_checkr(NULL, NULL, &buf); + + // authenticate (if no -s given) + if (!(opts & OPT_s)) { + // server supports APOP and we want it? + if ('<' == buf[0] && (opts & OPT_a)) { + union { // save a bit of stack + md5_ctx_t ctx; + char hex[16 * 2 + 1]; + } md5; + uint32_t res[16 / 4]; + + char *s = strchr(buf, '>'); + if (s) + s[1] = '\0'; + // get md5 sum of "password" string + md5_begin(&md5.ctx); + md5_hash(buf, strlen(buf), &md5.ctx); + md5_hash(G.pass, strlen(G.pass), &md5.ctx); + md5_end(res, &md5.ctx); + *bin2hex(md5.hex, (char*)res, 16) = '\0'; + // APOP + s = xasprintf("%s %s", G.user, md5.hex); + pop3_check("APOP %s", s); + free(s); + free(buf); + // server ignores APOP -> use simple text authentication + } else { + // USER + pop3_check("USER %s", G.user); + // PASS + pop3_check("PASS %s", G.pass); + } + } + + // get mailbox statistics + pop3_checkr("STAT", NULL, &buf); + + // prepare message filename suffix + hostname = safe_gethostname(); + pid = getpid(); + + // get messages counter + // NOTE: we don't use xatou(buf) since buf is "nmsg nbytes" + // we only need nmsg and atoi is just exactly what we need + // if atoi fails to convert buf into number it returns 0 + // in this case the following loop simply will not be executed + nmsg = atoi(buf); + free(buf); + + // loop through messages + retr = (opts & OPT_T) ? xasprintf("TOP %%u %u", opt_nlines) : "RETR %u"; + for (; nmsg; nmsg--) { + + char *filename; + char *target; + char *answer; + FILE *fp; +#if ENABLE_FEATURE_POPMAILDIR_DELIVERY + int rc; +#endif + // generate unique filename + filename = xasprintf("tmp/%llu.%u.%s", + monotonic_us(), (unsigned)pid, hostname); + + // retrieve message in ./tmp/ unless filter is specified + pop3_check(retr, (const char *)(ptrdiff_t)nmsg); + +#if ENABLE_FEATURE_POPMAILDIR_DELIVERY + // delivery helper ordered? -> setup pipe + if (opts & (OPT_F|OPT_M)) { + // helper will have $FILENAME set to filename + xsetenv("FILENAME", filename); + fp = popen(delivery, "w"); + unsetenv("FILENAME"); + if (!fp) { + bb_perror_msg("delivery helper"); + break; + } + } else +#endif + // create and open file filename + fp = xfopen_for_write(filename); + + // copy stdin to fp (either filename or delivery helper) + while ((answer = xmalloc_fgets_str(stdin, "\r\n")) != NULL) { + char *s = answer; + if ('.' == answer[0]) { + if ('.' == answer[1]) + s++; + else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) + break; + } + //*strchrnul(s, '\r') = '\n'; + fputs(s, fp); + free(answer); + } + +#if ENABLE_FEATURE_POPMAILDIR_DELIVERY + // analyse delivery status + if (opts & (OPT_F|OPT_M)) { + rc = pclose(fp); + if (99 == rc) // 99 means bail out + break; +// if (rc) // !0 means skip to the next message + goto skip; +// // 0 means continue + } else { + // close filename + fclose(fp); + } +#endif + + // delete message from server + if (!(opts & OPT_k)) + pop3_check("DELE %u", (const char*)(ptrdiff_t)nmsg); + + // atomically move message to ./new/ + target = xstrdup(filename); + strncpy(target, "new", 3); + // ... or just stop receiving on failure + if (rename_or_warn(filename, target)) + break; + free(target); + +#if ENABLE_FEATURE_POPMAILDIR_DELIVERY + skip: +#endif + free(filename); + } + + // Bye + pop3_check("QUIT", NULL); + + if (ENABLE_FEATURE_CLEAN_UP) { + free(G.user); + free(G.pass); + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/mailutils/sendmail.c b/release/src/router/busybox/mailutils/sendmail.c new file mode 100644 index 0000000000..7e57a94cf3 --- /dev/null +++ b/release/src/router/busybox/mailutils/sendmail.c @@ -0,0 +1,259 @@ +/* vi: set sw=4 ts=4: */ +/* + * bare bones sendmail + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include "mail.h" + +static int smtp_checkp(const char *fmt, const char *param, int code) +{ + char *answer; + const char *msg = command(fmt, param); + // read stdin + // if the string has a form \d\d\d- -- read next string. E.g. EHLO response + // parse first bytes to a number + // if code = -1 then just return this number + // if code != -1 then checks whether the number equals the code + // if not equal -> die saying msg + while ((answer = xmalloc_fgetline(stdin)) != NULL) + if (strlen(answer) <= 3 || '-' != answer[3]) + break; + if (answer) { + int n = atoi(answer); + if (timeout) + alarm(0); + free(answer); + if (-1 == code || n == code) + return n; + } + bb_error_msg_and_die("%s failed", msg); +} + +static int smtp_check(const char *fmt, int code) +{ + return smtp_checkp(fmt, NULL, code); +} + +// strip argument of bad chars +static char *sane_address(char *str) +{ + char *s = str; + char *p = s; + while (*s) { + if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { + *p++ = *s; + } + s++; + } + *p = '\0'; + return str; +} + +static void rcptto(const char *s) +{ + smtp_checkp("RCPT TO:<%s>", s, 250); +} + +int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sendmail_main(int argc UNUSED_PARAM, char **argv) +{ + char *opt_connect = opt_connect; + char *opt_from; + char *s; + llist_t *list = NULL; + char *domain = sane_address(safe_getdomainname()); + int code; + + enum { + //--- standard options + OPT_t = 1 << 0, // read message for recipients, append them to those on cmdline + OPT_f = 1 << 1, // sender address + OPT_o = 1 << 2, // various options. -oi IMPLIED! others are IGNORED! + //--- BB specific options + OPT_w = 1 << 3, // network timeout + OPT_H = 1 << 4, // use external connection helper + OPT_S = 1 << 5, // specify connection string + OPT_a = 1 << 6, // authentication tokens + }; + + // init global variables + INIT_G(); + + // save initial stdin since body is piped! + xdup2(STDIN_FILENO, 3); + G.fp0 = fdopen(3, "r"); + + // parse options + // -f is required. -H and -S are mutually exclusive + opt_complementary = "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:w:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); + //argc -= optind; + argv += optind; + + // process -a[upm] options + if ((opts & OPT_a) && !list) + bb_show_usage(); + while (list) { + char *a = (char *) llist_pop(&list); + if ('u' == a[0]) + G.user = xstrdup(a+1); + if ('p' == a[0]) + G.pass = xstrdup(a+1); + // N.B. we support only AUTH LOGIN so far + //if ('m' == a[0]) + // G.method = xstrdup(a+1); + } + // N.B. list == NULL here + //bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv); + + // connect to server + + // connection helper ordered? -> + if (opts & OPT_H) { + const char *args[] = { "sh", "-c", opt_connect, NULL }; + // plug it in + launch_helper(args); + // vanilla connection + } else { + int fd; + // host[:port] not explicitly specified? -> use $SMTPHOST + // no $SMTPHOST ? -> use localhost + if (!(opts & OPT_S)) { + opt_connect = getenv("SMTPHOST"); + if (!opt_connect) + opt_connect = (char *)"127.0.0.1"; + } + // do connect + fd = create_and_connect_stream_or_die(opt_connect, 25); + // 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"); + + // we should start with modern EHLO + 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) { + smtp_check("AUTH LOGIN", 334); + // we must read credentials unless they are given via -a[up] options + if (!G.user || !G.pass) + get_cred_or_die(4); + encode_base64(NULL, G.user, NULL); + smtp_check("", 334); + encode_base64(NULL, G.pass, NULL); + smtp_check("", 235); + } + + // set sender + // N.B. we have here a very loosely defined algotythm + // 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. + // 2) server can require AUTH -> + // we must provide valid username and password along with a (possibly fake) reply address. + // For the sake of security username and password are to be read either from console or from a secured file. + // Since reading from console may defeat usability, the solution is either to read from a predefined + // file descriptor (e.g. 4), or again from a secured file. + + // got no sender address? -> use system username as a resort + // N.B. we marked -f as required option! + //if (!G.user) { + // // N.B. IMHO getenv("USER") can be way easily spoofed! + // 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 + + // read recipients from message and add them to those given on cmdline. + // this means we scan stdin for To:, Cc:, Bcc: lines until an empty line + // and then use the rest of stdin as message body + code = 0; // set "analyze headers" mode + while ((s = xmalloc_fgetline(G.fp0)) != NULL) { + // put message lines doubling leading dots + if (code) { + // escape leading dots + // N.B. this feature is implied even if no -i (-oi) switch given + // N.B. we need to escape the leading dot regardless of + // whether it is single or not character on the line + if ('.' == s[0] /*&& '\0' == s[1] */) + printf("."); + // dump read line + printf("%s\r\n", s); + free(s); + continue; + } + + // analyze headers + // To: or Cc: headers add recipients + if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) { + rcptto(sane_address(s+4)); +// goto addh; + llist_add_to_end(&list, s); + // Bcc: header adds blind copy (hidden) recipient + } else if (0 == strncasecmp("Bcc: ", s, 5)) { + rcptto(sane_address(s+5)); + free(s); + // N.B. Bcc: vanishes from headers! + // other headers go verbatim + } else if (s[0]) { +// addh: + llist_add_to_end(&list, s); + // the empty line stops analyzing headers + } else { + free(s); + // put recipients specified on cmdline + while (*argv) { + s = sane_address(*argv); + rcptto(s); + llist_add_to_end(&list, xasprintf("To: %s", s)); + argv++; + } + // enter "put message" mode + smtp_check("DATA", 354); + // dump the headers + while (list) { + printf("%s\r\n", (char *) llist_pop(&list)); + } + printf("%s\r\n" + 2); // quirk for format string to be reused + // stop analyzing headers + code++; + } + } + + // finalize the message + smtp_check(".", 250); + // ... and say goodbye + smtp_check("QUIT", 221); + // cleanup + if (ENABLE_FEATURE_CLEAN_UP) + fclose(G.fp0); + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/Config.in b/release/src/router/busybox/miscutils/Config.in index 0c80ae6e9b..7feaf4a879 100644 --- a/release/src/router/busybox/miscutils/Config.in +++ b/release/src/router/busybox/miscutils/Config.in @@ -107,7 +107,7 @@ config CROND # Run daily cron jobs at 4:40 every day: 40 4 * * * /etc/cron/daily > /dev/null 2>&1 -config DEBUG_CROND_OPTION +config FEATURE_CROND_D bool "Support option -d to redirect output to stderr" depends on CROND default n @@ -121,6 +121,13 @@ config FEATURE_CROND_CALL_SENDMAIL help Support calling /usr/sbin/sendmail for send cmd outputs. +config FEATURE_CROND_DIR + string "crond spool directory" + default "/var/spool/cron" + depends on CROND || CRONTAB + help + Location of crond spool. + config CRONTAB bool "crontab" default n @@ -138,12 +145,23 @@ config DC Dc is a reverse-polish desk calculator which supports unlimited precision arithmetic. +config FEATURE_DC_LIBM + bool "Enable power and exp functions (requires libm)" + default n + depends on DC + help + Enable power and exp functions. + NOTE: This will require libm to be present for linking. + config DEVFSD bool "devfsd (obsolete)" default n select FEATURE_SYSLOG help - This is deprecated, and will be removed at the end of 2008. + This is deprecated and should NOT be used anymore. + Use linux >= 2.6 (optionally with hotplug) and mdev instead! + See docs/mdev.txt for detailed instructions on how to use mdev + instead. Provides compatibility with old device names on a devfs systems. You should set it to true if you have devfs enabled. @@ -152,7 +170,7 @@ config DEVFSD "PERMISSIONS", "EXECUTE", "COPY", "IGNORE", "MKOLDCOMPAT", "MKNEWCOMPAT","RMOLDCOMPAT", "RMNEWCOMPAT". - But only if they are written UPPERCASE!!!!!!!! + But only if they are written UPPERCASE!!!!!!!! config DEVFSD_MODLOAD bool "Adds support for MODLOAD keyword in devsfd.conf" @@ -182,12 +200,21 @@ config FEATURE_DEVFS bool "Use devfs names for all devices (obsolete)" default n help - This is obsolete and will be going away at the end of 2008.. + This is obsolete and should NOT be used anymore. + Use linux >= 2.6 (optionally with hotplug) and mdev instead! - This tells busybox to look for names like /dev/loop/0 instead of + For legacy systems -- if there is no way around devfsd -- this + tells busybox to look for names like /dev/loop/0 instead of /dev/loop0. If your /dev directory has normal names instead of devfs names, you don't want this. +config DEVMEM + bool "devmem" + default n + help + devmem is a small program that reads and writes from physical + memory using /dev/mem. + config EJECT bool "eject" default n @@ -223,6 +250,20 @@ config FBSPLASH "NN" (ASCII decimal number) - percentage to show on progress bar "exit" - well you guessed it +config FLASH_ERASEALL + bool "flash_eraseall" + default n + help + The flash_eraseall binary from mtd-utils as of git head c4c6a59eb. + This utility is used to erase the whole MTD device. + +config IONICE + bool "ionice" + default n + help + Set/set program io scheduling class and priority + Requires kernel >= 2.6.13 + config INOTIFYD bool "inotifyd" default n @@ -285,14 +326,6 @@ config FEATURE_LESS_FLAGS The -M flag enables a more sophisticated status line. The -m flag enables a simpler status line with a percentage. -config FEATURE_LESS_FLAGCS - bool "Enable flag changes" - default n - depends on LESS - help - This enables the ability to change command-line flags within - less itself. - config FEATURE_LESS_MARKS bool "Enable marks" default n @@ -307,6 +340,28 @@ config FEATURE_LESS_REGEXP help Enable regular expressions, allowing complex file searches. +config FEATURE_LESS_WINCH + bool "Enable automatic resizing on window size changes" + default n + depends on LESS + help + Makes less track window size changes. + +config FEATURE_LESS_DASHCMD + bool "Enable flag changes ('-' command)" + default n + 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 n + depends on FEATURE_LESS_DASHCMD + help + Enable "-N" command. + config HDPARM bool "hdparm" default n @@ -359,12 +414,11 @@ config FEATURE_HDPARM_HDIO_TRISTATE_HWIF stuff, so you should probably say N. config FEATURE_HDPARM_HDIO_GETSET_DMA - bool "Get/set using_dma flag (DANGEROUS)" + bool "Get/set using_dma flag" default n depends on HDPARM help Enables the 'hdparm -d' option to get/set using_dma flag. - This is dangerous stuff, so you should probably say N. config MAKEDEVS bool "makedevs" @@ -500,6 +554,13 @@ config TIME When the command finishes, time writes a message to standard output giving timing statistics about this program run. +config TIMEOUT + bool "timeout" + default n + help + Runs a program and watches it. If it does not terminate in + specified number of seconds, it is sent a signal. + config TTYSIZE bool "ttysize" default n diff --git a/release/src/router/busybox/miscutils/Kbuild b/release/src/router/busybox/miscutils/Kbuild index c12b12d423..23d7d8d497 100644 --- a/release/src/router/busybox/miscutils/Kbuild +++ b/release/src/router/busybox/miscutils/Kbuild @@ -13,8 +13,11 @@ lib-$(CONFIG_CROND) += crond.o lib-$(CONFIG_CRONTAB) += crontab.o lib-$(CONFIG_DC) += dc.o lib-$(CONFIG_DEVFSD) += devfsd.o +lib-$(CONFIG_DEVMEM) += devmem.o lib-$(CONFIG_EJECT) += eject.o lib-$(CONFIG_FBSPLASH) += fbsplash.o +lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o +lib-$(CONFIG_IONICE) += ionice.o lib-$(CONFIG_HDPARM) += hdparm.o lib-$(CONFIG_INOTIFYD) += inotifyd.o lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o @@ -33,5 +36,6 @@ lib-$(CONFIG_SETSID) += setsid.o lib-$(CONFIG_STRINGS) += strings.o lib-$(CONFIG_TASKSET) += taskset.o lib-$(CONFIG_TIME) += time.o +lib-$(CONFIG_TIMEOUT) += timeout.o lib-$(CONFIG_TTYSIZE) += ttysize.o lib-$(CONFIG_WATCHDOG) += watchdog.o diff --git a/release/src/router/busybox/miscutils/chat.c b/release/src/router/busybox/miscutils/chat.c index d550c7c90a..3ffd7b228f 100644 --- a/release/src/router/busybox/miscutils/chat.c +++ b/release/src/router/busybox/miscutils/chat.c @@ -9,16 +9,6 @@ */ #include "libbb.h" -/* -#define ENABLE_FEATURE_CHAT_NOFAIL 1 // +126 bytes -#define ENABLE_FEATURE_CHAT_TTY_HIFI 0 // + 70 bytes -#define ENABLE_FEATURE_CHAT_IMPLICIT_CR 1 // + 44 bytes -#define ENABLE_FEATURE_CHAT_SEND_ESCAPES 0 // +103 bytes -#define ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 0 // + 70 bytes -#define ENABLE_FEATURE_CHAT_CLR_ABORT 0 // +113 bytes -#define ENABLE_FEATURE_CHAT_SWALLOW_OPTS 0 // + 23 bytes -*/ - // default timeout: 45 sec #define DEFAULT_CHAT_TIMEOUT 45*1000 // max length of "abort string", @@ -37,8 +27,7 @@ enum { }; // exit code -// N.B> 10 bytes for volatile. Why all these signals?! -static /*volatile*/ smallint exitcode; +#define exitcode bb_got_signal // trap for critical signals static void signal_handler(UNUSED_PARAM int signo) @@ -101,13 +90,10 @@ static size_t unescape(char *s, int *nocr) return p - start; } - int chat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chat_main(int argc UNUSED_PARAM, char **argv) { -// should we dump device output? to what fd? by default no. -// this can be controlled later via ECHO {ON|OFF} chat directive -// int echo_fd; + int record_fd = -1; bool echo = 0; // collection of device replies which cause unconditional termination llist_t *aborts = NULL; @@ -132,6 +118,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) DIR_TIMEOUT, DIR_ECHO, DIR_SAY, + DIR_RECORD, }; // make x* functions fail with correct exitcode @@ -166,14 +153,14 @@ int chat_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_CHAT_CLR_ABORT "CLR_ABORT\0" #endif - "TIMEOUT\0" "ECHO\0" "SAY\0" + "TIMEOUT\0" "ECHO\0" "SAY\0" "RECORD\0" , *argv ); if (key >= 0) { // cache directive value char *arg = *++argv; - // ON -> 1, anything else -> 0 - bool onoff = !strcmp("ON", arg); + // OFF -> 0, anything else -> 1 + bool onoff = (0 != strcmp("OFF", arg)); // process directive if (DIR_HANGUP == key) { // turn SIGHUP on/off @@ -217,14 +204,20 @@ int chat_main(int argc UNUSED_PARAM, char **argv) timeout = DEFAULT_CHAT_TIMEOUT; } else if (DIR_ECHO == key) { // turn echo on/off - // N.B. echo means dumping output - // from stdin (device) to stderr + // N.B. echo means dumping device input/output to stderr echo = onoff; -//TODO? echo_fd = onoff * STDERR_FILENO; -//TODO? echo_fd = xopen(arg, O_WRONLY|O_CREAT|O_TRUNC); + } else if (DIR_RECORD == key) { + // turn record on/off + // N.B. record means dumping device input to a file + // close previous record_fd + if (record_fd > 0) + close(record_fd); + // N.B. do we have to die here on open error? + record_fd = (onoff) ? xopen(arg, O_WRONLY|O_CREAT|O_TRUNC) : -1; } else if (DIR_SAY == key) { // just print argument verbatim - fprintf(stderr, arg); + // TODO: should we use full_write() to avoid unistd/stdio conflict? + bb_error_msg("%s", arg); } // next, please! argv++; @@ -288,12 +281,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv) // read next char from device if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { - // dump device output if ECHO ON or RECORD fname -//TODO? if (echo_fd > 0) { -//TODO? full_write(echo_fd, buf+buf_len, 1); -//TODO? } - if (echo > 0) + // dump device input if RECORD fname + if (record_fd > 0) { + full_write(record_fd, buf+buf_len, 1); + } + // dump device input if ECHO ON + if (echo > 0) { +// if (buf[buf_len] < ' ') { +// full_write(STDERR_FILENO, "^", 1); +// buf[buf_len] += '@'; +// } full_write(STDERR_FILENO, buf+buf_len, 1); + } buf_len++; // move input frame if we've reached higher bound if (buf_len > COMMON_BUFSIZE) { @@ -320,7 +319,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) goto expect_done; #undef buf - } + } /* while (have data) */ // device timed out or unexpected reply received exitcode = ERR_TIMEOUT; @@ -365,21 +364,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv) trim(++buf); buf = loaded = xmalloc_xopen_read_close(buf, NULL); } - // expand escape sequences in command len = unescape(buf, &nocr); // send command -#if ENABLE_FEATURE_CHAT_SEND_ESCAPES + alarm(timeout); pfd.fd = STDOUT_FILENO; pfd.events = POLLOUT; while (len && !exitcode - && poll(&pfd, 1, timeout) > 0 + && poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLOUT) ) { - // ugly! ugly! ugly! - // gotta send char by char to achieve this! - // Brrr... +#if ENABLE_FEATURE_CHAT_SEND_ESCAPES // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay // "\\K" means send BREAK char c = *buf; @@ -389,31 +385,28 @@ int chat_main(int argc UNUSED_PARAM, char **argv) sleep(1); len--; continue; - } else if ('p' == c) { + } + if ('p' == c) { usleep(10000); len--; continue; - } else if ('K' == c) { + } + if ('K' == c) { tcsendbreak(STDOUT_FILENO, 0); len--; continue; - } else { - buf--; } + buf--; } - if (safe_write(STDOUT_FILENO, buf, 1) > 0) { - len--; - buf++; - } else + if (safe_write(STDOUT_FILENO, buf, 1) != 1) break; - } + len--; + buf++; #else -// if (len) { - alarm(timeout); len -= full_write(STDOUT_FILENO, buf, len); - alarm(0); -// } #endif + } /* while (can write) */ + alarm(0); // report I/O error if there still exists at least one non-sent char if (len) @@ -427,14 +420,12 @@ int chat_main(int argc UNUSED_PARAM, char **argv) else if (!nocr) xwrite(STDOUT_FILENO, "\r", 1); #endif - // bail out unless we sent command successfully if (exitcode) break; - - } + } /* if (*argv) */ } - } + } /* while (*argv) */ #if ENABLE_FEATURE_CHAT_TTY_HIFI tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); diff --git a/release/src/router/busybox/miscutils/chrt.c b/release/src/router/busybox/miscutils/chrt.c index 23ef58c4d2..cc5660be7b 100644 --- a/release/src/router/busybox/miscutils/chrt.c +++ b/release/src/router/busybox/miscutils/chrt.c @@ -1,7 +1,7 @@ /* vi: set sw=4 ts=4: */ /* * chrt - manipulate real-time attributes of a process - * Copyright (c) 2006-2007 Bernhard Fischer + * Copyright (c) 2006-2007 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/miscutils/crond.c b/release/src/router/busybox/miscutils/crond.c index 2f0bf6ea8e..804fe0b292 100644 --- a/release/src/router/busybox/miscutils/crond.c +++ b/release/src/router/busybox/miscutils/crond.c @@ -23,12 +23,8 @@ #endif -#ifndef CRONTABS -#define CRONTABS "/var/spool/cron/crontabs" -#endif -#ifndef TMPDIR -#define TMPDIR "/var/spool/cron" -#endif +#define TMPDIR CONFIG_FEATURE_CROND_DIR +#define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" #ifndef SENDMAIL #define SENDMAIL "sendmail" #endif @@ -59,7 +55,7 @@ typedef struct CronLine { #if ENABLE_FEATURE_CROND_CALL_SENDMAIL int cl_MailPos; /* 'empty file' size */ smallint cl_MailFlag; /* running pid is for mail */ - char *cl_MailTo; /* whom to mail results */ + char *cl_MailTo; /* whom to mail results */ #endif /* ordered by size, not in natural order. makes code smaller: */ char cl_Dow[7]; /* 0-6, beginning sunday */ @@ -80,9 +76,9 @@ enum { OPT_b = (1 << 3), OPT_S = (1 << 4), OPT_c = (1 << 5), - OPT_d = (1 << 6) * ENABLE_DEBUG_CROND_OPTION, + OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, }; -#if ENABLE_DEBUG_CROND_OPTION +#if ENABLE_FEATURE_CROND_D #define DebugOpt (option_mask32 & OPT_d) #else #define DebugOpt 0 @@ -146,7 +142,7 @@ static void crondlog(const char *ctl, ...) /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ if (!DebugOpt && LogFile) { /* Otherwise (log to file): we reopen log file at every write: */ - int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600); + int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); if (logfd >= 0) xmove_fd(logfd, STDERR_FILENO); } @@ -166,11 +162,11 @@ int crond_main(int argc UNUSED_PARAM, char **argv) INIT_G(); /* "-b after -f is ignored", and so on for every pair a-b */ - opt_complementary = "f-b:b-f:S-L:L-S" USE_DEBUG_CROND_OPTION(":d-l") + opt_complementary = "f-b:b-f:S-L:L-S" USE_FEATURE_CROND_D(":d-l") ":l+:d+"; /* -l and -d have numeric param */ - opt = getopt32(argv, "l:L:fbSc:" USE_DEBUG_CROND_OPTION("d:"), + opt = getopt32(argv, "l:L:fbSc:" USE_FEATURE_CROND_D("d:"), &LogLevel, &LogFile, &CDir - USE_DEBUG_CROND_OPTION(,&LogLevel)); + USE_FEATURE_CROND_D(,&LogLevel)); /* both -d N and -l N set the same variable: LogLevel */ if (!(opt & OPT_f)) { @@ -187,7 +183,7 @@ int crond_main(int argc UNUSED_PARAM, char **argv) xchdir(CDir); //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ - setenv("SHELL", DEFAULT_SHELL, 1); /* once, for all future children */ + xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel); SynchronizeDir(); @@ -252,14 +248,12 @@ int crond_main(int argc UNUSED_PARAM, char **argv) /* We set environment *before* vfork (because we want to use vfork), * so we cannot use setenv() - repeated calls to setenv() may leak memory! * Using putenv(), and freeing memory after unsetenv() won't leak */ -static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, int len*/) +static void safe_setenv(char **pvar_val, const char *var, const char *val) { - const int len = 4; /* both var names are 4 char long */ char *var_val = *pvar_val; if (var_val) { - var_val[len] = '\0'; /* nuke '=' */ - unsetenv(var_val); + bb_unsetenv(var_val); free(var_val); } *pvar_val = xasprintf("%s=%s", var, val); @@ -270,13 +264,13 @@ static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, i static void SetEnv(struct passwd *pas) { #if SETENV_LEAKS - safe_setenv4(&env_var_user, "USER", pas->pw_name); - safe_setenv4(&env_var_home, "HOME", pas->pw_dir); + safe_setenv(&env_var_user, "USER", pas->pw_name); + safe_setenv(&env_var_home, "HOME", pas->pw_dir); /* if we want to set user's shell instead: */ - /*safe_setenv(env_var_user, "SHELL", pas->pw_shell, 5);*/ + /*safe_setenv(env_var_user, "SHELL", pas->pw_shell);*/ #else - setenv("USER", pas->pw_name, 1); - setenv("HOME", pas->pw_dir, 1); + xsetenv("USER", pas->pw_name); + xsetenv("HOME", pas->pw_dir); #endif /* currently, we use constant one: */ /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ @@ -779,7 +773,9 @@ ForkJob(const char *user, CronLine *line, int mailFd, xmove_fd(mailFd, mail_filename ? 1 : 0); dup2(1, 2); } - execlp(prog, prog, cmd, arg, NULL); + /* crond 3.0pl1-100 puts tasks in separate process groups */ + bb_setpgrp(); + execlp(prog, prog, cmd, arg, (char *) NULL); crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); if (mail_filename) { fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); @@ -914,7 +910,9 @@ static void RunJob(const char *user, CronLine *line) if (DebugOpt) { crondlog(LVL5 "child running %s", DEFAULT_SHELL); } - execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL); + /* crond 3.0pl1-100 puts tasks in separate process groups */ + bb_setpgrp(); + execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, (char *) NULL); crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, DEFAULT_SHELL, "-c", line->cl_Shell); _exit(EXIT_SUCCESS); diff --git a/release/src/router/busybox/miscutils/crontab.c b/release/src/router/busybox/miscutils/crontab.c index 01656cc6e7..34b80ea37a 100644 --- a/release/src/router/busybox/miscutils/crontab.c +++ b/release/src/router/busybox/miscutils/crontab.c @@ -12,18 +12,16 @@ #include "libbb.h" -#ifndef CRONTABS -#define CRONTABS "/var/spool/cron/crontabs" -#endif +#define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" #ifndef CRONUPDATE #define CRONUPDATE "cron.update" #endif static void change_user(const struct passwd *pas) { - setenv("USER", pas->pw_name, 1); - setenv("HOME", pas->pw_dir, 1); - setenv("SHELL", DEFAULT_SHELL, 1); + xsetenv("USER", pas->pw_name); + xsetenv("HOME", pas->pw_dir); + xsetenv("SHELL", DEFAULT_SHELL); /* initgroups, setgid, setuid */ change_identity(pas); @@ -126,15 +124,9 @@ int crontab_main(int argc UNUSED_PARAM, char **argv) } if (opt_ler & OPT_u) { - pas = getpwnam(user_name); - if (!pas) - bb_error_msg_and_die("user %s is not known", user_name); + pas = xgetpwnam(user_name); } else { -/* XXX: xgetpwuid */ - uid_t my_uid = getuid(); - pas = getpwuid(my_uid); - if (!pas) - bb_perror_msg_and_die("unknown uid %d", (int)my_uid); + pas = xgetpwuid(getuid()); } #define user_name DONT_USE_ME_BEYOND_THIS_POINT diff --git a/release/src/router/busybox/miscutils/dc.c b/release/src/router/busybox/miscutils/dc.c index 47ec060c80..ff2bc3bcef 100644 --- a/release/src/router/busybox/miscutils/dc.c +++ b/release/src/router/busybox/miscutils/dc.c @@ -19,7 +19,9 @@ enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof( #define pointer (G.pointer ) #define base (G.base ) #define stack (G.stack ) -#define INIT_G() do { } while (0) +#define INIT_G() do { \ + base = 10; \ +} while (0) static void push(double a) @@ -53,12 +55,14 @@ static void mul(void) push(pop() * pop()); } +#if ENABLE_FEATURE_DC_LIBM static void power(void) { double topower = pop(); push(pow(pop(), topower)); } +#endif static void divide(void) { @@ -96,19 +100,45 @@ static void not(void) static void set_output_base(void) { - base = (unsigned)pop(); - if ((base != 10) && (base != 16)) { - bb_error_msg("error, base %d is not supported", base); + static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 }; + unsigned b = (unsigned)pop(); + + base = *strchrnul(bases, b); + if (base == 0) { + bb_error_msg("error, base %u is not supported", b); base = 10; } } static void print_base(double print) { - if (base == 16) - printf("%x\n", (unsigned)print); - else + unsigned x, i; + + if (base == 10) { printf("%g\n", print); + return; + } + + x = (unsigned)print; + switch (base) { + case 16: + printf("%x\n", x); + break; + case 8: + printf("%o\n", x); + break; + default: /* base 2 */ + i = (unsigned)INT_MAX + 1; + do { + if (x & i) break; + i >>= 1; + } while (i > 1); + do { + bb_putchar('1' - !(x & i)); + i >>= 1; + } while (i); + bb_putchar('\n'); + } } static void print_stack_no_pop(void) @@ -137,9 +167,11 @@ static const struct op operators[] = { {"mul", mul}, {"/", divide}, {"div", divide}, +#if ENABLE_FEATURE_DC_LIBM {"**", power}, {"exp", power}, {"pow", power}, +#endif {"%", mod}, {"mod", mod}, {"and", and}, diff --git a/release/src/router/busybox/miscutils/devmem.c b/release/src/router/busybox/miscutils/devmem.c new file mode 100644 index 0000000000..e13dedc0a5 --- /dev/null +++ b/release/src/router/busybox/miscutils/devmem.c @@ -0,0 +1,128 @@ +/* + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * Copyright (C) 2008, BusyBox Team. -solar 4/26/08 + */ + +#include "libbb.h" + +int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int devmem_main(int argc UNUSED_PARAM, char **argv) +{ + void *map_base, *virt_addr; + uint64_t read_result; + uint64_t writeval = writeval; /* for compiler */ + off_t target; + unsigned page_size = getpagesize(); + int fd; + int width = 8 * sizeof(int); + + /* devmem ADDRESS [WIDTH [VALUE]] */ +// TODO: options? +// -r: read and output only the value in hex, with 0x prefix +// -w: write only, no reads before or after, and no output +// or make this behavior default? +// Let's try this and see how users react. + + /* ADDRESS */ + if (!argv[1]) + bb_show_usage(); + errno = 0; + target = bb_strtoull(argv[1], NULL, 0); /* allows hex, oct etc */ + + /* WIDTH */ + if (argv[2]) { + if (isdigit(argv[2][0]) || argv[2][1]) + width = xatou(argv[2]); + else { + static const char bhwl[] ALIGN1 = "bhwl"; + static const uint8_t sizes[] ALIGN1 = { + 8 * sizeof(char), + 8 * sizeof(short), + 8 * sizeof(int), + 8 * sizeof(long), + 0 /* bad */ + }; + width = strchrnul(bhwl, (argv[2][0] | 0x20)) - bhwl; + width = sizes[width]; + } + /* VALUE */ + if (argv[3]) + writeval = bb_strtoull(argv[3], NULL, 0); + } else { /* argv[2] == NULL */ + /* make argv[3] to be a valid thing to use */ + argv--; + } + if (errno) + bb_show_usage(); /* bb_strtouXX failed */ + + fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC)); + map_base = mmap(NULL, + page_size * 2 /* in case value spans page */, + argv[3] ? (PROT_READ | PROT_WRITE) : PROT_READ, + MAP_SHARED, + fd, + target & ~(off_t)(page_size - 1)); + if (map_base == MAP_FAILED) + bb_perror_msg_and_die("mmap"); + +// printf("Memory mapped at address %p.\n", map_base); + + virt_addr = (char*)map_base + (target & (page_size - 1)); + + if (!argv[3]) { + switch (width) { + case 8: + read_result = *(volatile uint8_t*)virt_addr; + break; + case 16: + read_result = *(volatile uint16_t*)virt_addr; + break; + case 32: + read_result = *(volatile uint32_t*)virt_addr; + break; + case 64: + read_result = *(volatile uint64_t*)virt_addr; + break; + default: + bb_error_msg_and_die("bad width"); + } +// printf("Value at address 0x%"OFF_FMT"X (%p): 0x%llX\n", +// target, virt_addr, +// (unsigned long long)read_result); + /* Zero-padded output shows the width of access just done */ + printf("0x%0*llX\n", (width >> 2), (unsigned long long)read_result); + } else { + switch (width) { + case 8: + *(volatile uint8_t*)virt_addr = writeval; +// read_result = *(volatile uint8_t*)virt_addr; + break; + case 16: + *(volatile uint16_t*)virt_addr = writeval; +// read_result = *(volatile uint16_t*)virt_addr; + break; + case 32: + *(volatile uint32_t*)virt_addr = writeval; +// read_result = *(volatile uint32_t*)virt_addr; + break; + case 64: + *(volatile uint64_t*)virt_addr = writeval; +// read_result = *(volatile uint64_t*)virt_addr; + break; + default: + bb_error_msg_and_die("bad width"); + } +// printf("Written 0x%llX; readback 0x%llX\n", +// (unsigned long long)writeval, +// (unsigned long long)read_result); + } + + if (ENABLE_FEATURE_CLEAN_UP) { + if (munmap(map_base, page_size * 2) == -1) + bb_perror_msg_and_die("munmap"); + close(fd); + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/fbsplash.c b/release/src/router/busybox/miscutils/fbsplash.c index f8289c3d11..ec0f092dcb 100644 --- a/release/src/router/busybox/miscutils/fbsplash.c +++ b/release/src/router/busybox/miscutils/fbsplash.c @@ -1,7 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Copyright (C) 2008 Michele Sanges , - * + * Copyright (C) 2008 Michele Sanges * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * @@ -88,7 +87,7 @@ static void fb_open(const char *strfb_device) * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/ , PROT_WRITE, MAP_SHARED, fbfd, 0); if (G.addr == MAP_FAILED) - bb_perror_msg_and_die("can't mmap %s", strfb_device); + bb_perror_msg_and_die("mmap"); close(fbfd); } @@ -122,7 +121,7 @@ static void fb_drawrectangle(void) // vertical lines ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL); - cnt = G.nbar_posy + G.nbar_height - 1 - G.nbar_posy; + cnt = G.nbar_height - 1 /* HUH?! G.nbar_posy + G.nbar_height - 1 - G.nbar_posy*/; do { *ptr1 = thispix; ptr1 += G.scr_var.xres; *ptr2 = thispix; ptr2 += G.scr_var.xres; @@ -217,36 +216,50 @@ static void fb_drawprogressbar(unsigned percent) */ static void fb_drawimage(void) { - char head[256]; - char s[80]; + char *head, *ptr; FILE *theme_file; unsigned char *pixline; unsigned i, j, width, height, line_size; - memset(head, 0, sizeof(head)); theme_file = xfopen_stdin(G.image_filename); - - // parse ppm header + head = xmalloc(256); + + /* parse ppm header + * - A ppm image’s magic number is the two characters "P6". + * - Whitespace (blanks, TABs, CRs, LFs). + * - A width, formatted as ASCII characters in decimal. + * - Whitespace. + * - A height, again in ASCII decimal. + * - Whitespace. + * - The maximum color value (Maxval), again in ASCII decimal. Must be + * less than 65536. + * - Newline or other single whitespace character. + * - A raster of Width * Height pixels in triplets of rgb + * in pure binary by 1 (or not implemented 2) bytes. + */ while (1) { - if (fgets(s, sizeof(s), theme_file) == NULL) - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); - - if (s[0] == '#') - continue; - - if (strlen(head) + strlen(s) >= sizeof(head)) - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); - - strcat(head, s); - if (head[0] != 'P' || head[1] != '6') + if (fgets(head, 256, theme_file) == NULL + /* do not overrun the buffer */ + || strlen(bb_common_bufsiz1) >= sizeof(bb_common_bufsiz1) - 256) bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); + ptr = memchr(skip_whitespace(head), '#', 256); + if (ptr != NULL) + *ptr = 0; /* ignore comments */ + strcat(bb_common_bufsiz1, head); // width, height, max_color_val - if (sscanf(head, "P6 %u %u %u", &width, &height, &i) == 3) + if (sscanf(bb_common_bufsiz1, "P6 %u %u %u", &width, &height, &i) == 3 + && i <= 255) break; -// TODO: i must be <= 255! + /* If we do not find a signature throughout the whole file then + we will diagnose this via EOF on read in the head of the loop. */ } + if (ENABLE_FEATURE_CLEAN_UP) + free(head); + if (width != G.scr_var.xres || height != G.scr_var.yres) + bb_error_msg_and_die("PPM %dx%d does not match screen %dx%d", + width, height, G.scr_var.xres, G.scr_var.yres); line_size = width*3; if (width > G.scr_var.xres) width = G.scr_var.xres; @@ -269,7 +282,8 @@ static void fb_drawimage(void) pixel += 3; } } - free(pixline); + if (ENABLE_FEATURE_CLEAN_UP) + free(pixline); fclose(theme_file); } @@ -295,7 +309,7 @@ static void init(const char *cfg_filename) unsigned val = xatoi_u(token[1]); int i = index_in_strings(param_names, token[0]); if (i < 0) - bb_error_msg_and_die("syntax error: '%s'", token[0]); + bb_error_msg_and_die("syntax error: %s", token[0]); if (i >= 0 && i < 7) G.ns[i] = val; #if DEBUG diff --git a/release/src/router/busybox/miscutils/flash_eraseall.c b/release/src/router/busybox/miscutils/flash_eraseall.c new file mode 100644 index 0000000000..3e0c06ffd8 --- /dev/null +++ b/release/src/router/busybox/miscutils/flash_eraseall.c @@ -0,0 +1,194 @@ +/* vi: set sw=4 ts=4: */ +/* eraseall.c -- erase the whole of a MTD device + * + * Ported to busybox from mtd-utils. + * + * Copyright (C) 2000 Arcom Control System Ltd + * + * Renamed to flash_eraseall.c + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include +#include + +#define OPTION_J (1 << 0) +#define OPTION_Q (1 << 1) +#define IS_NAND (1 << 2) +#define BBTEST (1 << 3) + +struct globals { + /* This is used in the cpu_to_je/je_to_cpu macros in jffs2_user.h */ + int tgt_endian; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define target_endian (G.tgt_endian) +#define INIT_G() do { \ + target_endian = __BYTE_ORDER; \ +} while (0) + +static uint32_t crc32(uint32_t val, const void *ss, int len, + uint32_t *crc32_table) +{ + const unsigned char *s = ss; + while (--len >= 0) + val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + return val; +} + +static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) +{ + printf("\rErasing %d Kibyte @ %x -- %2llu %% complete.", + (unsigned)meminfo->erasesize / 1024, erase->start, + (unsigned long long) erase->start * 100 / meminfo->size); + fflush(stdout); +} + +int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) +{ + struct jffs2_unknown_node cleanmarker; + mtd_info_t meminfo; + int fd, clmpos, clmlen; + erase_info_t erase; + struct stat st; + unsigned int flags; + char *mtd_name; + + INIT_G(); + opt_complementary = "=1"; + flags = BBTEST | getopt32(argv, "jq"); + + mtd_name = argv[optind]; + xstat(mtd_name, &st); + if (!S_ISCHR(st.st_mode)) + bb_error_msg_and_die("%s: not a char device", mtd_name); + + fd = xopen(mtd_name, O_RDWR); + + xioctl(fd, MEMGETINFO, &meminfo); + erase.length = meminfo.erasesize; + if (meminfo.type == MTD_NANDFLASH) + flags |= IS_NAND; + + clmpos = 0; + clmlen = 8; + if (flags & OPTION_J) { + uint32_t *crc32_table; + + crc32_table = crc32_filltable(NULL, 0); + + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); + if (!(flags & IS_NAND)) + cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node)); + else { + struct nand_oobinfo oobinfo; + + xioctl(fd, MEMGETOOBSEL, &oobinfo); + + /* Check for autoplacement */ + if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { + /* Get the position of the free bytes */ + clmpos = oobinfo.oobfree[0][0]; + clmlen = oobinfo.oobfree[0][1]; + if (clmlen > 8) + clmlen = 8; + if (clmlen == 0) + bb_error_msg_and_die("Autoplacement selected and no empty space in oob"); + } else { + /* Legacy mode */ + switch (meminfo.oobsize) { + case 8: + clmpos = 6; + clmlen = 2; + break; + case 16: + clmpos = 8; + /*clmlen = 8;*/ + break; + case 64: + clmpos = 16; + /*clmlen = 8;*/ + break; + } + } + cleanmarker.totlen = cpu_to_je32(8); + } + + cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, + crc32_table)); + } + + /* Don't want to destroy progress indicator by bb_error_msg's */ + applet_name = xasprintf("\n%s: %s", applet_name, mtd_name); + + for (erase.start = 0; erase.start < meminfo.size; + erase.start += meminfo.erasesize) { + if (flags & BBTEST) { + int ret; + loff_t offset = erase.start; + + ret = ioctl(fd, MEMGETBADBLOCK, &offset); + if (ret > 0) { + if (!(flags & OPTION_Q)) + bb_info_msg("\nSkipping bad block at 0x%08x", erase.start); + continue; + } + if (ret < 0) { + /* Black block table is not available on certain flash + * types e.g. NOR + */ + if (errno == EOPNOTSUPP) { + flags &= ~BBTEST; + if (flags & IS_NAND) + bb_error_msg_and_die("bad block check not available"); + } else { + bb_perror_msg_and_die("MEMGETBADBLOCK error"); + } + } + } + + if (!(flags & OPTION_Q)) + show_progress(&meminfo, &erase); + + xioctl(fd, MEMERASE, &erase); + + /* format for JFFS2 ? */ + if (!(flags & OPTION_J)) + continue; + + /* write cleanmarker */ + if (flags & IS_NAND) { + struct mtd_oob_buf oob; + + oob.ptr = (unsigned char *) &cleanmarker; + oob.start = erase.start + clmpos; + oob.length = clmlen; + xioctl(fd, MEMWRITEOOB, &oob); + } else { + xlseek(fd, erase.start, SEEK_SET); + /* if (lseek(fd, erase.start, SEEK_SET) < 0) { + bb_perror_msg("MTD %s failure", "seek"); + continue; + } */ + xwrite(fd, &cleanmarker, sizeof(cleanmarker)); + /* if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) { + bb_perror_msg("MTD %s failure", "write"); + continue; + } */ + } + if (!(flags & OPTION_Q)) + printf(" Cleanmarker written at %x.", erase.start); + } + if (!(flags & OPTION_Q)) { + show_progress(&meminfo, &erase); + bb_putchar('\n'); + } + + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/hdparm.c b/release/src/router/busybox/miscutils/hdparm.c index b75da16ece..de5d68a043 100644 --- a/release/src/router/busybox/miscutils/hdparm.c +++ b/release/src/router/busybox/miscutils/hdparm.c @@ -59,7 +59,7 @@ #define ADV_PIO_MODES 64 /* advanced PIO modes supported */ /* multiword DMA xfer cycle time: */ #define DMA_TIME_MIN 65 /* - minimum */ -#define DMA_TIME_NORM 66 /* - manufacturer's recommended */ +#define DMA_TIME_NORM 66 /* - manufacturer's recommended */ /* minimum PIO xfer cycle time: */ #define PIO_NO_FLOW 67 /* - without flow control */ #define PIO_FLOW 68 /* - with IORDY flow control */ @@ -82,7 +82,7 @@ #define ENH_ERASE_TIME 90 /* - enhanced */ #define ADV_PWR 91 /* current advanced power management level in low byte, 0x40 in high byte. */ -#define PSWD_CODE 92 /* master password revision code */ +#define PSWD_CODE 92 /* master password revision code */ #define HWRST_RSLT 93 /* hardware reset result */ #define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */ #define LBA_LSB 100 /* LBA: maximum. Currently only 48 */ @@ -1759,7 +1759,7 @@ static void process_dev(char *devname) } } if (get_unmask) { - if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm)) + if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm)) print_value_on_off("unmaskirq", parm); } @@ -1777,25 +1777,25 @@ static void process_dev(char *devname) #endif #ifdef HDIO_GET_QDMA if (get_dma_q) { - if(!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm)) + if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm)) print_value_on_off("queue_depth", parm); } #endif if (get_keep) { - if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm)) + if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm)) print_value_on_off("keepsettings", parm); } if (get_nowerr) { - if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm)) + if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm)) print_value_on_off("nowerr", parm); } if (get_readonly) { - if(!ioctl_or_warn(fd, BLKROGET, &parm)) + if (!ioctl_or_warn(fd, BLKROGET, &parm)) print_value_on_off("readonly", parm); } if (get_readahead) { - if(!ioctl_or_warn(fd, BLKRAGET, &parm)) + if (!ioctl_or_warn(fd, BLKRAGET, &parm)) print_value_on_off("readahead", parm); } if (get_geom) { diff --git a/release/src/router/busybox/miscutils/inotifyd.c b/release/src/router/busybox/miscutils/inotifyd.c index 2a1a153489..d6b5d246bc 100644 --- a/release/src/router/busybox/miscutils/inotifyd.c +++ b/release/src/router/busybox/miscutils/inotifyd.c @@ -28,14 +28,7 @@ */ #include "libbb.h" -#include - -static volatile smallint signalled; - -static void signal_handler(int signo) -{ - signalled = signo; -} +#include static const char mask_names[] ALIGN1 = "a" // 0x00000001 File was accessed @@ -50,73 +43,96 @@ static const char mask_names[] ALIGN1 = "d" // 0x00000200 Subfile was deleted "D" // 0x00000400 Self was deleted "M" // 0x00000800 Self was moved + "\0" // 0x00001000 (unused) + // Kernel events, always reported: + "u" // 0x00002000 Backing fs was unmounted + "o" // 0x00004000 Event queued overflowed + "x" // 0x00008000 File is no longer watched (usually deleted) ; - -extern int inotify_init(void); -extern int inotify_add_watch(int fd, const char *path, uint32_t mask); +enum { + MASK_BITS = sizeof(mask_names) - 1 +}; int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int inotifyd_main(int argc UNUSED_PARAM, char **argv) +int inotifyd_main(int argc, char **argv) { - unsigned mask = IN_ALL_EVENTS; // assume we want all events + int n; + unsigned mask; struct pollfd pfd; - char **watched = ++argv; // watched name list - const char *args[] = { *argv, NULL, NULL, NULL, NULL }; + char **watches; // names of files being watched + const char *args[5]; // sanity check: agent and at least one watch must be given - if (!argv[1]) + if (!argv[1] || !argv[2]) bb_show_usage(); + argv++; + // inotify_add_watch will number watched files + // starting from 1, thus watches[0] is unimportant, + // and 1st file name is watches[1]. + watches = argv; + args[0] = *argv; + args[4] = NULL; + argc -= 2; // number of files we watch + // open inotify pfd.fd = inotify_init(); if (pfd.fd < 0) bb_perror_msg_and_die("no kernel support"); - // setup watched + // setup watches while (*++argv) { char *path = *argv; char *masks = strchr(path, ':'); - int wd; // watch descriptor + + mask = 0x0fff; // assuming we want all non-kernel events // if mask is specified -> if (masks) { *masks = '\0'; // split path and mask // convert mask names to mask bitset mask = 0; while (*++masks) { - int i = strchr(mask_names, *masks) - mask_names; - if (i >= 0) { - mask |= (1 << i); - } + const char *found; + found = memchr(mask_names, *masks, MASK_BITS); + if (found) + mask |= (1 << (found - mask_names)); } } // add watch - wd = inotify_add_watch(pfd.fd, path, mask); - if (wd < 0) { + n = inotify_add_watch(pfd.fd, path, mask); + if (n < 0) bb_perror_msg_and_die("add watch (%s) failed", path); -// } else { -// bb_error_msg("added %d [%s]:%4X", wd, path, mask); - } + //bb_error_msg("added %d [%s]:%4X", n, path, mask); } // setup signals - bb_signals(0 - + (1 << SIGHUP) - + (1 << SIGINT) - + (1 << SIGTERM) - + (1 << SIGPIPE) - , signal_handler); + bb_signals(BB_FATAL_SIGS, record_signo); // do watch - -// pfd.fd = fd; pfd.events = POLLIN; - - while (!signalled && poll(&pfd, 1, -1) > 0) { - ssize_t len; + while (1) { + int len; void *buf; struct inotify_event *ie; + again: + if (bb_got_signal) + break; + n = poll(&pfd, 1, -1); + // Signal interrupted us? + if (n < 0 && errno == EINTR) + goto again; + // Under Linux, above if() is not necessary. + // Non-fatal signals, e.g. SIGCHLD, when set to SIG_DFL, + // are not interrupting poll(). + // Thus we can just break if n <= 0 (see below), + // because EINTR will happen only on SIGTERM et al. + // But this might be not true under other Unixes, + // and is generally way too subtle to depend on. + if (n <= 0) // strange error? + break; // read out all pending events + // (NB: len must be int, not ssize_t or long!) xioctl(pfd.fd, FIONREAD, &len); #define eventbuf bb_common_bufsiz1 ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len); @@ -124,21 +140,29 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) // process events. N.B. events may vary in length while (len > 0) { int i; - char events[12]; - char *s = events; - unsigned m = ie->mask; - - for (i = 0; i < 12; ++i, m >>= 1) { - if (m & 1) { - *s++ = mask_names[i]; + // cache relevant events mask + unsigned m = ie->mask & ((1 << MASK_BITS) - 1); + if (m) { + char events[MASK_BITS + 1]; + char *s = events; + for (i = 0; i < MASK_BITS; ++i, m >>= 1) { + if ((m & 1) && (mask_names[i] != '\0')) + *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; + wait4pid(xspawn((char **)args)); + // we are done if all files got final x event + if (ie->mask & 0x8000) { + if (--argc <= 0) + goto done; + inotify_rm_watch(pfd.fd, ie->wd); } } - *s = '\0'; -// bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); - args[1] = events; - args[2] = watched[ie->wd]; - args[3] = ie->len ? ie->name : NULL; - xspawn((char **)args); // next event i = sizeof(struct inotify_event) + ie->len; len -= i; @@ -146,7 +170,7 @@ int inotifyd_main(int argc UNUSED_PARAM, char **argv) } if (eventbuf != buf) free(buf); - } - - return EXIT_SUCCESS; + } // while (1) + done: + return bb_got_signal; } diff --git a/release/src/router/busybox/miscutils/ionice.c b/release/src/router/busybox/miscutils/ionice.c new file mode 100644 index 0000000000..361c141b82 --- /dev/null +++ b/release/src/router/busybox/miscutils/ionice.c @@ -0,0 +1,99 @@ +/* vi: set sw=4 ts=4: */ +/* + * ionice implementation for busybox based on linux-utils-ng 2.14 + * + * Copyright (C) 2008 by + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include +#include +#include "libbb.h" + +static int ioprio_set(int which, int who, int ioprio) +{ + return syscall(SYS_ioprio_set, which, who, ioprio); +} + +static int ioprio_get(int which, int who) +{ + return syscall(SYS_ioprio_get, which, who); +} + +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER +}; + +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE +}; + +static const char to_prio[] = "none\0realtime\0best-effort\0idle"; + +#define IOPRIO_CLASS_SHIFT 13 + +int ionice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ionice_main(int argc UNUSED_PARAM, char **argv) +{ + /* Defaults */ + int ioclass = 0; + int pri = 0; + int pid = 0; /* affect own porcess */ + int opt; + enum { + OPT_n = 1, + OPT_c = 2, + OPT_p = 4, + }; + + /* Numeric params */ + opt_complementary = "n+:c+:p+"; + /* '+': stop at first non-option */ + opt = getopt32(argv, "+n:c:p:", &pri, &ioclass, &pid); + argv += optind; + + if (opt & OPT_c) { + if (ioclass > 3) + bb_error_msg_and_die("bad class %d", ioclass); +// Do we need this (compat?)? +// if (ioclass == IOPRIO_CLASS_NONE) +// ioclass = IOPRIO_CLASS_BE; +// if (ioclass == IOPRIO_CLASS_IDLE) { +// //if (opt & OPT_n) +// // bb_error_msg("ignoring priority for idle class"); +// pri = 7; +// } + } + + if (!(opt & (OPT_n|OPT_c))) { + if (!(opt & OPT_p) && *argv) + pid = xatoi_u(*argv); + + pri = ioprio_get(IOPRIO_WHO_PROCESS, pid); + if (pri == -1) + bb_perror_msg_and_die("ioprio_%cet", 'g'); + + ioclass = (pri >> IOPRIO_CLASS_SHIFT) & 0x3; + pri &= 0xff; + printf((ioclass == IOPRIO_CLASS_IDLE) ? "%s\n" : "%s: prio %d\n", + nth_string(to_prio, ioclass), pri); + } else { +//printf("pri=%d class=%d val=%x\n", +//pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT)); + pri |= (ioclass << IOPRIO_CLASS_SHIFT); + if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) + bb_perror_msg_and_die("ioprio_%cet", 's'); + if (*argv) { + BB_EXECVP(*argv, argv); + bb_simple_perror_msg_and_die(*argv); + } + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/miscutils/less.c b/release/src/router/busybox/miscutils/less.c index 530a40a8c8..27855bbe8b 100644 --- a/release/src/router/busybox/miscutils/less.c +++ b/release/src/router/busybox/miscutils/less.c @@ -28,10 +28,6 @@ #include "xregex.h" #endif -/* FIXME: currently doesn't work right */ -#undef ENABLE_FEATURE_LESS_FLAGCS -#define ENABLE_FEATURE_LESS_FLAGCS 0 - /* The escape codes for highlighted and normal text */ #define HIGHLIGHT "\033[7m" #define NORMAL "\033[0m" @@ -40,45 +36,22 @@ /* The escape code to clear to end of line */ #define CLEAR_2_EOL "\033[K" -/* These are the escape sequences corresponding to special keys */ enum { - REAL_KEY_UP = 'A', - REAL_KEY_DOWN = 'B', - REAL_KEY_RIGHT = 'C', - REAL_KEY_LEFT = 'D', - REAL_PAGE_UP = '5', - REAL_PAGE_DOWN = '6', - REAL_KEY_HOME = '7', // vt100? linux vt? or what? - REAL_KEY_END = '8', - REAL_KEY_HOME_ALT = '1', // ESC [1~ (vt100? linux vt? or what?) - REAL_KEY_END_ALT = '4', // ESC [4~ - REAL_KEY_HOME_XTERM = 'H', - REAL_KEY_END_XTERM = 'F', - -/* These are the special codes assigned by this program to the special keys */ - KEY_UP = 20, - KEY_DOWN = 21, - KEY_RIGHT = 22, - KEY_LEFT = 23, - PAGE_UP = 24, - PAGE_DOWN = 25, - KEY_HOME = 26, - KEY_END = 27, - /* Absolute max of lines eaten */ MAXLINES = CONFIG_FEATURE_LESS_MAXLINES, - /* This many "after the end" lines we will show (at max) */ TILDES = 1, }; /* Command line options */ enum { - FLAG_E = 1, + FLAG_E = 1 << 0, FLAG_M = 1 << 1, FLAG_m = 1 << 2, FLAG_N = 1 << 3, FLAG_TILDE = 1 << 4, + FLAG_I = 1 << 5, + FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_DASHCMD, /* hijack command line options variable for internal state vars */ LESS_STATE_MATCH_BACKWARDS = 1 << 15, }; @@ -92,11 +65,14 @@ struct globals { int kbd_fd; /* fd to get input from */ int less_gets_pos; /* last position in last line, taking into account tabs */ - size_t linepos; - unsigned max_displayed_line; + size_t last_line_pos; unsigned max_fline; unsigned max_lineno; /* this one tracks linewrap */ + unsigned max_displayed_line; unsigned width; +#if ENABLE_FEATURE_LESS_WINCH + unsigned winch_counter; +#endif ssize_t eof_error; /* eof if 0, error if < 0 */ ssize_t readpos; ssize_t readeof; /* must be signed */ @@ -120,17 +96,22 @@ struct globals { smallint pattern_valid; #endif smallint terminated; + smalluint kbd_input_size; struct termios term_orig, term_less; + char kbd_input[KEYCODE_BUFFER_SIZE]; }; #define G (*ptr_to_globals) #define cur_fline (G.cur_fline ) #define kbd_fd (G.kbd_fd ) #define less_gets_pos (G.less_gets_pos ) -#define linepos (G.linepos ) -#define max_displayed_line (G.max_displayed_line) +#define last_line_pos (G.last_line_pos ) #define max_fline (G.max_fline ) #define max_lineno (G.max_lineno ) +#define max_displayed_line (G.max_displayed_line) #define width (G.width ) +#define winch_counter (G.winch_counter ) +/* This one is 100% not cached by compiler on read access */ +#define WINCH_COUNTER (*(volatile unsigned *)&winch_counter) #define eof_error (G.eof_error ) #define readpos (G.readpos ) #define readeof (G.readeof ) @@ -154,6 +135,8 @@ struct globals { #define terminated (G.terminated ) #define term_orig (G.term_orig ) #define term_less (G.term_less ) +#define kbd_input_size (G.kbd_input_size ) +#define kbd_input (G.kbd_input ) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ less_gets_pos = -1; \ @@ -165,6 +148,14 @@ struct globals { USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \ } while (0) +/* flines[] are lines read from stdin, each in malloc'ed buffer. + * Line numbers are stored as uint32_t prepended to each line. + * Pointer is adjusted so that flines[i] points directly past + * line number. Accesor: */ +#define MEMPTR(p) ((char*)(p) - 4) +#define LINENO(p) (*(uint32_t*)((p) - 4)) + + /* Reset terminal input to normal */ static void set_tty_cooked(void) { @@ -205,6 +196,92 @@ static void less_exit(int code) exit(code); } +#if (ENABLE_FEATURE_LESS_DASHCMD && ENABLE_FEATURE_LESS_LINENUMS) \ + || ENABLE_FEATURE_LESS_WINCH +static void re_wrap(void) +{ + int w = width; + int new_line_pos; + int src_idx; + int dst_idx; + int new_cur_fline = 0; + uint32_t lineno; + char linebuf[w + 1]; + const char **old_flines = flines; + const char *s; + char **new_flines = NULL; + char *d; + + if (option_mask32 & FLAG_N) + w -= 8; + + src_idx = 0; + dst_idx = 0; + s = old_flines[0]; + lineno = LINENO(s); + d = linebuf; + new_line_pos = 0; + while (1) { + *d = *s; + if (*d != '\0') { + new_line_pos++; + if (*d == '\t') /* tab */ + new_line_pos += 7; + s++; + d++; + if (new_line_pos >= w) { + int sz; + /* new line is full, create next one */ + *d = '\0'; + next_new: + sz = (d - linebuf) + 1; /* + 1: NUL */ + d = ((char*)xmalloc(sz + 4)) + 4; + LINENO(d) = lineno; + memcpy(d, linebuf, sz); + new_flines = xrealloc_vector(new_flines, 8, dst_idx); + new_flines[dst_idx] = d; + dst_idx++; + if (new_line_pos < w) { + /* if we came here thru "goto next_new" */ + if (src_idx > max_fline) + break; + lineno = LINENO(s); + } + d = linebuf; + new_line_pos = 0; + } + continue; + } + /* *d == NUL: old line ended, go to next old one */ + free(MEMPTR(old_flines[src_idx])); + /* btw, convert cur_fline... */ + if (cur_fline == src_idx) + new_cur_fline = dst_idx; + src_idx++; + /* no more lines? finish last new line (and exit the loop) */ + if (src_idx > max_fline) + goto next_new; + s = old_flines[src_idx]; + if (lineno != LINENO(s)) { + /* this is not a continuation line! + * create next _new_ line too */ + goto next_new; + } + } + + free(old_flines); + flines = (const char **)new_flines; + + max_fline = dst_idx - 1; + last_line_pos = new_line_pos; + cur_fline = new_cur_fline; + /* max_lineno is screen-size independent */ +#if ENABLE_FEATURE_LESS_REGEXP + pattern_valid = 0; +#endif +} +#endif + #if ENABLE_FEATURE_LESS_REGEXP static void fill_match_lines(unsigned pos); #else @@ -230,7 +307,7 @@ static void fill_match_lines(unsigned pos); * on line wrap, only on "real" new lines. * readbuf[0..readeof-1] - small preliminary buffer. * readbuf[readpos] - next character to add to current line. - * linepos - screen line position of next char to be read + * last_line_pos - screen line position of next char to be read * (takes into account tabs and backspaces) * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error */ @@ -251,18 +328,16 @@ static void read_lines(void) USE_FEATURE_LESS_REGEXP(again0:) - p = current_line = xmalloc(w); + p = current_line = ((char*)xmalloc(w + 4)) + 4; max_fline += last_terminated; if (!last_terminated) { const char *cp = flines[max_fline]; - if (option_mask32 & FLAG_N) - cp += 8; - strcpy(current_line, cp); + strcpy(p, cp); p += strlen(current_line); - free((char*)flines[max_fline]); - /* linepos is still valid from previous read_lines() */ + free(MEMPTR(flines[max_fline])); + /* last_line_pos is still valid from previous read_lines() */ } else { - linepos = 0; + last_line_pos = 0; } while (1) { /* read lines until we reach cur_fline or wanted_match */ @@ -284,28 +359,28 @@ static void read_lines(void) /* backspace? [needed for manpages] */ /* is (a) insane and */ /* (b) harder to do correctly, so we refuse to do it */ - if (c == '\x8' && linepos && p[-1] != '\t') { + if (c == '\x8' && last_line_pos && p[-1] != '\t') { readpos++; /* eat it */ - linepos--; + last_line_pos--; /* was buggy (p could end up <= current_line)... */ *--p = '\0'; continue; } { - size_t new_linepos = linepos + 1; + size_t new_last_line_pos = last_line_pos + 1; if (c == '\t') { - new_linepos += 7; - new_linepos &= (~7); + new_last_line_pos += 7; + new_last_line_pos &= (~7); } - if ((int)new_linepos >= w) + if ((int)new_last_line_pos >= w) break; - linepos = new_linepos; + last_line_pos = new_last_line_pos; } /* ok, we will eat this char */ readpos++; if (c == '\n') { terminated = 1; - linepos = 0; + last_line_pos = 0; break; } /* NUL is substituted by '\n'! */ @@ -323,22 +398,21 @@ static void read_lines(void) reached_eof: last_terminated = terminated; flines = xrealloc_vector(flines, 8, max_fline); - if (option_mask32 & FLAG_N) { - /* Width of 7 preserves tab spacing in the text */ - flines[max_fline] = xasprintf( - (max_lineno <= 9999999) ? "%7u %s" : "%07u %s", - max_lineno % 10000000, current_line); - free(current_line); - if (terminated) - max_lineno++; - } else { - flines[max_fline] = xrealloc(current_line, strlen(current_line) + 1); - } + + flines[max_fline] = (char*)xrealloc(MEMPTR(current_line), strlen(current_line) + 1 + 4) + 4; + LINENO(flines[max_fline]) = max_lineno; + if (terminated) + max_lineno++; + if (max_fline >= MAXLINES) { eof_error = 0; /* Pretend we saw EOF */ break; } - if (max_fline > cur_fline + max_displayed_line) { + if (!(option_mask32 & FLAG_S) + ? (max_fline > cur_fline + max_displayed_line) + : (max_fline >= cur_fline + && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line) + ) { #if !ENABLE_FEATURE_LESS_REGEXP break; #else @@ -379,9 +453,9 @@ static void read_lines(void) #endif } max_fline++; - current_line = xmalloc(w); + current_line = ((char*)xmalloc(w + 4)) + 4; p = current_line; - linepos = 0; + last_line_pos = 0; } /* end of "read lines until we reach cur_fline" loop */ fill_match_lines(old_max_fline); #if ENABLE_FEATURE_LESS_REGEXP @@ -486,6 +560,30 @@ static const char ctrlconv[] ALIGN1 = "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f" "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"; +static void lineno_str(char *nbuf9, const char *line) +{ + nbuf9[0] = '\0'; + if (option_mask32 & FLAG_N) { + const char *fmt; + unsigned n; + + if (line == empty_line_marker) { + memset(nbuf9, ' ', 8); + nbuf9[8] = '\0'; + return; + } + /* Width of 7 preserves tab spacing in the text */ + fmt = "%7u "; + n = LINENO(line) + 1; + if (n > 9999999) { + n %= 10000000; + fmt = "%07u "; + } + sprintf(nbuf9, fmt, n); + } +} + + #if ENABLE_FEATURE_LESS_REGEXP static void print_found(const char *line) { @@ -495,6 +593,7 @@ static void print_found(const char *line) regmatch_t match_structs; char buf[width]; + char nbuf9[9]; const char *str = line; char *p = buf; size_t n; @@ -531,7 +630,8 @@ static void print_found(const char *line) match_structs.rm_so, str, match_structs.rm_eo - match_structs.rm_so, str + match_structs.rm_so); - free(growline); growline = new; + free(growline); + growline = new; str += match_structs.rm_eo; line += match_structs.rm_eo; eflags = REG_NOTBOL; @@ -543,11 +643,12 @@ static void print_found(const char *line) match_status = 1; } + lineno_str(nbuf9, line); if (!growline) { - printf(CLEAR_2_EOL"%s\n", str); + printf(CLEAR_2_EOL"%s%s\n", nbuf9, str); return; } - printf(CLEAR_2_EOL"%s%s\n", growline, str); + printf(CLEAR_2_EOL"%s%s%s\n", nbuf9, growline, str); free(growline); } #else @@ -557,10 +658,13 @@ void print_found(const char *line); static void print_ascii(const char *str) { char buf[width]; + char nbuf9[9]; char *p; size_t n; - printf(CLEAR_2_EOL); + lineno_str(nbuf9, str); + printf(CLEAR_2_EOL"%s", nbuf9); + while (*str) { n = strcspn(str, controls); if (n) { @@ -604,9 +708,32 @@ static void buffer_print(void) static void buffer_fill_and_print(void) { unsigned i; +#if ENABLE_FEATURE_LESS_DASHCMD + int fpos = cur_fline; + + if (option_mask32 & FLAG_S) { + /* Go back to the beginning of this line */ + while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1])) + fpos--; + } + + i = 0; + while (i <= max_displayed_line && fpos <= max_fline) { + int lineno = LINENO(flines[fpos]); + buffer[i] = flines[fpos]; + i++; + do { + fpos++; + } while ((fpos <= max_fline) + && (option_mask32 & FLAG_S) + && lineno == LINENO(flines[fpos]) + ); + } +#else for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) { buffer[i] = flines[cur_fline + i]; } +#endif for (; i <= max_displayed_line; i++) { buffer[i] = empty_line_marker; } @@ -647,9 +774,7 @@ static void buffer_line(int linenum) static void open_file_and_read_lines(void) { if (filename) { - int fd = xopen(filename, O_RDONLY); - dup2(fd, 0); - if (fd) close(fd); + xmove_fd(xopen(filename, O_RDONLY), STDIN_FILENO); } else { /* "less" with no arguments in argv[] */ /* For status line only */ @@ -657,7 +782,7 @@ static void open_file_and_read_lines(void) } readpos = 0; readeof = 0; - linepos = 0; + last_line_pos = 0; terminated = 1; read_lines(); } @@ -669,7 +794,7 @@ static void reinitialize(void) if (flines) { for (i = 0; i <= max_fline; i++) - free((void*)(flines[i])); + free(MEMPTR(flines[i])); free(flines); flines = NULL; } @@ -681,9 +806,9 @@ static void reinitialize(void) buffer_fill_and_print(); } -static ssize_t getch_nowait(char* input, int sz) +static ssize_t getch_nowait(void) { - ssize_t rd; + int rd; struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; @@ -699,25 +824,49 @@ static ssize_t getch_nowait(char* input, int sz) * (switch fd into O_NONBLOCK'ed mode to avoid it) */ rd = 1; - if (max_fline <= cur_fline + max_displayed_line - && eof_error > 0 /* did NOT reach eof yet */ + /* Are we interested in stdin? */ +//TODO: reuse code for determining this + if (!(option_mask32 & FLAG_S) + ? !(max_fline > cur_fline + max_displayed_line) + : !(max_fline >= cur_fline + && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line) ) { - /* We are interested in stdin */ - rd = 0; + if (eof_error > 0) /* did NOT reach eof yet */ + rd = 0; /* yes, we are interested in stdin */ } - /* position cursor if line input is done */ + /* Position cursor if line input is done */ if (less_gets_pos >= 0) move_cursor(max_displayed_line + 2, less_gets_pos + 1); fflush(stdout); - safe_poll(pfd + rd, 2 - rd, -1); - input[0] = '\0'; - rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */ - if (rd < 0 && errno == EAGAIN) { - /* No keyboard input -> we have input on stdin! */ - read_lines(); - buffer_fill_and_print(); - goto again; + if (kbd_input_size == 0) { +#if ENABLE_FEATURE_LESS_WINCH + while (1) { + int r; + /* NB: SIGWINCH interrupts poll() */ + r = poll(pfd + rd, 2 - rd, -1); + if (/*r < 0 && errno == EINTR &&*/ winch_counter) + return '\\'; /* anything which has no defined function */ + if (r) break; + } +#else + safe_poll(pfd + rd, 2 - rd, -1); +#endif + } + + /* 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_size, kbd_input); + if (rd == -1) { + if (errno == EAGAIN) { + /* No keyboard input available. Since poll() did return, + * we should have input on stdin */ + read_lines(); + buffer_fill_and_print(); + goto again; + } + /* EOF/error (ssh session got killed etc) */ + less_exit(0); } set_tty_cooked(); return rd; @@ -728,51 +877,29 @@ static ssize_t getch_nowait(char* input, int sz) * special return codes. Note that this function works best with raw input. */ static int less_getch(int pos) { - unsigned char input[16]; - unsigned i; + int i; again: less_gets_pos = pos; - memset(input, 0, sizeof(input)); - getch_nowait((char *)input, sizeof(input)); + i = getch_nowait(); less_gets_pos = -1; - /* Detect escape sequences (i.e. arrow keys) and handle - * them accordingly */ - if (input[0] == '\033' && input[1] == '[') { - i = input[2] - REAL_KEY_UP; - if (i < 4) - return 20 + i; - i = input[2] - REAL_PAGE_UP; - if (i < 4) - return 24 + i; - if (input[2] == REAL_KEY_HOME_XTERM) - return KEY_HOME; - if (input[2] == REAL_KEY_HOME_ALT) - return KEY_HOME; - if (input[2] == REAL_KEY_END_XTERM) - return KEY_END; - if (input[2] == REAL_KEY_END_ALT) - return KEY_END; - return 0; - } - /* Reject almost all control chars */ - i = input[0]; - if (i < ' ' && i != 0x0d && i != 8) + /* Discard Ctrl-something chars */ + if (i >= 0 && i < ' ' && i != 0x0d && i != 8) goto again; return i; } static char* less_gets(int sz) { - char c; + int c; unsigned i = 0; char *result = xzalloc(1); while (1) { c = '\0'; less_gets_pos = sz + i; - getch_nowait(&c, 1); + c = getch_nowait(); if (c == 0x0d) { result[i] = '\0'; less_gets_pos = -1; @@ -784,7 +911,7 @@ static char* less_gets(int sz) printf("\x8 \x8"); i--; } - if (c < ' ') + if (c < ' ') /* filters out KEYCODE_xxx too (<0) */ continue; if (i >= width - sz - 1) continue; /* len limit */ @@ -965,7 +1092,8 @@ static void regex_process(void) } /* Compile the regex and check for errors */ - err = regcomp_or_errmsg(&pattern, uncomp_regex, 0); + err = regcomp_or_errmsg(&pattern, uncomp_regex, + (option_mask32 & FLAG_I) ? REG_ICASE : 0); free(uncomp_regex); if (err) { print_statusline(err); @@ -995,8 +1123,8 @@ static void number_process(int first_digit) { unsigned i; int num; + int keypress; char num_input[sizeof(int)*4]; /* more than enough */ - char keypress; num_input[0] = first_digit; @@ -1007,15 +1135,14 @@ static void number_process(int first_digit) /* Receive input until a letter is given */ i = 1; while (i < sizeof(num_input)-1) { - num_input[i] = less_getch(i + 1); - if (!num_input[i] || !isdigit(num_input[i])) + keypress = less_getch(i + 1); + if ((unsigned)keypress > 255 || !isdigit(num_input[i])) break; - bb_putchar(num_input[i]); + num_input[i] = keypress; + bb_putchar(keypress); i++; } - /* Take the final letter out of the digits string */ - keypress = num_input[i]; num_input[i] = '\0'; num = bb_strtou(num_input, NULL, 10); /* on format error, num == -1 */ @@ -1026,10 +1153,10 @@ static void number_process(int first_digit) /* We now know the number and the letter entered, so we process them */ switch (keypress) { - case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015': + case KEYCODE_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015': buffer_down(num); break; - case KEY_UP: case 'b': case 'w': case 'y': case 'u': + case KEYCODE_UP: case 'b': case 'w': case 'y': case 'u': buffer_up(num); break; case 'g': case '<': case 'G': case '>': @@ -1059,7 +1186,7 @@ static void number_process(int first_digit) } } -#if ENABLE_FEATURE_LESS_FLAGCS +#if ENABLE_FEATURE_LESS_DASHCMD static void flag_change(void) { int keypress; @@ -1081,9 +1208,21 @@ static void flag_change(void) case '~': option_mask32 ^= FLAG_TILDE; break; + case 'S': + option_mask32 ^= FLAG_S; + buffer_fill_and_print(); + break; +#if ENABLE_FEATURE_LESS_LINENUMS + case 'N': + option_mask32 ^= FLAG_N; + re_wrap(); + buffer_fill_and_print(); + break; +#endif } } +#ifdef BLOAT static void show_flag_status(void) { int keypress; @@ -1119,6 +1258,8 @@ static void show_flag_status(void) } #endif +#endif /* ENABLE_FEATURE_LESS_DASHCMD */ + static void save_input_to_file(void) { const char *msg = ""; @@ -1246,16 +1387,16 @@ static void match_left_bracket(char bracket) static void keypress_process(int keypress) { switch (keypress) { - case KEY_DOWN: case 'e': case 'j': case 0x0d: + case KEYCODE_DOWN: case 'e': case 'j': case 0x0d: buffer_down(1); break; - case KEY_UP: case 'y': case 'k': + case KEYCODE_UP: case 'y': case 'k': buffer_up(1); break; - case PAGE_DOWN: case ' ': case 'z': case 'f': + case KEYCODE_PAGEDOWN: case ' ': case 'z': case 'f': buffer_down(max_displayed_line + 1); break; - case PAGE_UP: case 'w': case 'b': + case KEYCODE_PAGEUP: case 'w': case 'b': buffer_up(max_displayed_line + 1); break; case 'd': @@ -1264,10 +1405,10 @@ static void keypress_process(int keypress) case 'u': buffer_up((max_displayed_line + 1) / 2); break; - case KEY_HOME: case 'g': case 'p': case '<': case '%': + case KEYCODE_HOME: case 'g': case 'p': case '<': case '%': buffer_line(0); break; - case KEY_END: case 'G': case '>': + case KEYCODE_END: case 'G': case '>': cur_fline = MAXLINES; read_lines(); buffer_line(cur_fline); @@ -1318,15 +1459,17 @@ static void keypress_process(int keypress) regex_process(); break; #endif -#if ENABLE_FEATURE_LESS_FLAGCS +#if ENABLE_FEATURE_LESS_DASHCMD case '-': flag_change(); buffer_print(); break; +#ifdef BLOAT case '_': show_flag_status(); break; #endif +#endif #if ENABLE_FEATURE_LESS_BRACKETS case '{': case '(': case '[': match_right_bracket(keypress); @@ -1349,6 +1492,13 @@ static void sig_catcher(int sig) less_exit(- sig); } +#if ENABLE_FEATURE_LESS_WINCH +static void sigwinch_handler(int sig UNUSED_PARAM) +{ + winch_counter++; +} +#endif + int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int less_main(int argc, char **argv) { @@ -1359,7 +1509,7 @@ int less_main(int argc, char **argv) /* TODO: -x: do not interpret backspace, -xx: tab also */ /* -xxx: newline also */ /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */ - getopt32(argv, "EMmN~"); + getopt32(argv, "EMmN~I" USE_FEATURE_LESS_DASHCMD("S")); argc -= optind; argv += optind; num_files = argc; @@ -1369,10 +1519,6 @@ int less_main(int argc, char **argv) * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); - kbd_fd = open(CURRENT_TTY, O_RDONLY); - if (kbd_fd < 0) - return bb_cat(argv); - ndelay_on(kbd_fd); if (!num_files) { if (isatty(STDIN_FILENO)) { @@ -1380,19 +1526,18 @@ int less_main(int argc, char **argv) bb_error_msg("missing filename"); bb_show_usage(); } - } else + } else { filename = xstrdup(files[0]); + } - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); - /* 20: two tabstops + 4 */ - if (width < 20 || max_displayed_line < 3) - return bb_cat(argv); - max_displayed_line -= 2; - - buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); if (option_mask32 & FLAG_TILDE) empty_line_marker = ""; + kbd_fd = open(CURRENT_TTY, O_RDONLY); + if (kbd_fd < 0) + return bb_cat(argv); + ndelay_on(kbd_fd); + tcgetattr(kbd_fd, &term_orig); term_less = term_orig; term_less.c_lflag &= ~(ICANON | ECHO); @@ -1401,12 +1546,254 @@ 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); + /* 20: two tabstops + 4 */ + if (width < 20 || max_displayed_line < 3) + return bb_cat(argv); + max_displayed_line -= 2; + /* We want to restore term_orig on exit */ bb_signals(BB_FATAL_SIGS, sig_catcher); +#if ENABLE_FEATURE_LESS_WINCH + signal(SIGWINCH, sigwinch_handler); +#endif + buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); reinitialize(); while (1) { +#if ENABLE_FEATURE_LESS_WINCH + while (WINCH_COUNTER) { + again: + winch_counter--; + get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + /* 20: two tabstops + 4 */ + if (width < 20) + width = 20; + if (max_displayed_line < 3) + max_displayed_line = 3; + max_displayed_line -= 2; + free(buffer); + buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); + /* Avoid re-wrap and/or redraw if we already know + * we need to do it again. These ops are expensive */ + if (WINCH_COUNTER) + goto again; + re_wrap(); + if (WINCH_COUNTER) + goto again; + buffer_fill_and_print(); + /* This took some time. Loop back and check, + * were there another SIGWINCH? */ + } +#endif keypress = less_getch(-1); /* -1: do not position cursor */ keypress_process(keypress); } } + +/* +Help text of less version 418 is below. +If you are implementing something, keeping +key and/or command line switch compatibility is a good idea: + + + SUMMARY OF LESS COMMANDS + + Commands marked with * may be preceded by a number, N. + Notes in parentheses indicate the behavior if N is given. + h H Display this help. + q :q Q :Q ZZ Exit. + --------------------------------------------------------------------------- + MOVING + e ^E j ^N CR * Forward one line (or N lines). + y ^Y k ^K ^P * Backward one line (or N lines). + f ^F ^V SPACE * Forward one window (or N lines). + b ^B ESC-v * Backward one window (or N lines). + z * Forward one window (and set window to N). + w * Backward one window (and set window to N). + ESC-SPACE * Forward one window, but don't stop at end-of-file. + d ^D * Forward one half-window (and set half-window to N). + u ^U * Backward one half-window (and set half-window to N). + ESC-) RightArrow * Left one half screen width (or N positions). + ESC-( LeftArrow * Right one half screen width (or N positions). + F Forward forever; like "tail -f". + r ^R ^L Repaint screen. + R Repaint screen, discarding buffered input. + --------------------------------------------------- + Default "window" is the screen height. + Default "half-window" is half of the screen height. + --------------------------------------------------------------------------- + SEARCHING + /pattern * Search forward for (N-th) matching line. + ?pattern * Search backward for (N-th) matching line. + n * Repeat previous search (for N-th occurrence). + N * Repeat previous search in reverse direction. + ESC-n * Repeat previous search, spanning files. + ESC-N * Repeat previous search, reverse dir. & spanning files. + ESC-u Undo (toggle) search highlighting. + --------------------------------------------------- + Search patterns may be modified by one or more of: + ^N or ! Search for NON-matching lines. + ^E or * Search multiple files (pass thru END OF FILE). + ^F or @ Start search at FIRST file (for /) or last file (for ?). + ^K Highlight matches, but don't move (KEEP position). + ^R Don't use REGULAR EXPRESSIONS. + --------------------------------------------------------------------------- + JUMPING + g < ESC-< * Go to first line in file (or line N). + G > ESC-> * Go to last line in file (or line N). + p % * Go to beginning of file (or N percent into file). + t * Go to the (N-th) next tag. + T * Go to the (N-th) previous tag. + { ( [ * Find close bracket } ) ]. + } ) ] * Find open bracket { ( [. + ESC-^F * Find close bracket . + ESC-^B * Find open bracket + --------------------------------------------------- + Each "find close bracket" command goes forward to the close bracket + matching the (N-th) open bracket in the top line. + Each "find open bracket" command goes backward to the open bracket + matching the (N-th) close bracket in the bottom line. + m Mark the current position with . + ' Go to a previously marked position. + '' Go to the previous position. + ^X^X Same as '. + --------------------------------------------------- + A mark is any upper-case or lower-case letter. + Certain marks are predefined: + ^ means beginning of the file + $ means end of the file + --------------------------------------------------------------------------- + CHANGING FILES + :e [file] Examine a new file. + ^X^V Same as :e. + :n * Examine the (N-th) next file from the command line. + :p * Examine the (N-th) previous file from the command line. + :x * Examine the first (or N-th) file from the command line. + :d Delete the current file from the command line list. + = ^G :f Print current file name. + --------------------------------------------------------------------------- + MISCELLANEOUS COMMANDS + - Toggle a command line option [see OPTIONS below]. + -- Toggle a command line option, by name. + _ Display the setting of a command line option. + __ Display the setting of an option, by name. + +cmd Execute the less cmd each time a new file is examined. + !command Execute the shell command with $SHELL. + |Xcommand Pipe file between current pos & mark X to shell command. + v Edit the current file with $VISUAL or $EDITOR. + V Print version number of "less". + --------------------------------------------------------------------------- + OPTIONS + Most options may be changed either on the command line, + or from within less by using the - or -- command. + Options may be given in one of two forms: either a single + character preceded by a -, or a name preceeded by --. + -? ........ --help + Display help (from command line). + -a ........ --search-skip-screen + Forward search skips current screen. + -b [N] .... --buffers=[N] + Number of buffers. + -B ........ --auto-buffers + Don't automatically allocate buffers for pipes. + -c ........ --clear-screen + Repaint by clearing rather than scrolling. + -d ........ --dumb + Dumb terminal. + -D [xn.n] . --color=xn.n + Set screen colors. (MS-DOS only) + -e -E .... --quit-at-eof --QUIT-AT-EOF + Quit at end of file. + -f ........ --force + Force open non-regular files. + -F ........ --quit-if-one-screen + Quit if entire file fits on first screen. + -g ........ --hilite-search + Highlight only last match for searches. + -G ........ --HILITE-SEARCH + Don't highlight any matches for searches. + -h [N] .... --max-back-scroll=[N] + Backward scroll limit. + -i ........ --ignore-case + Ignore case in searches that do not contain uppercase. + -I ........ --IGNORE-CASE + Ignore case in all searches. + -j [N] .... --jump-target=[N] + Screen position of target lines. + -J ........ --status-column + Display a status column at left edge of screen. + -k [file] . --lesskey-file=[file] + Use a lesskey file. + -L ........ --no-lessopen + Ignore the LESSOPEN environment variable. + -m -M .... --long-prompt --LONG-PROMPT + Set prompt style. + -n -N .... --line-numbers --LINE-NUMBERS + Don't use line numbers. + -o [file] . --log-file=[file] + Copy to log file (standard input only). + -O [file] . --LOG-FILE=[file] + Copy to log file (unconditionally overwrite). + -p [pattern] --pattern=[pattern] + Start at pattern (from command line). + -P [prompt] --prompt=[prompt] + Define new prompt. + -q -Q .... --quiet --QUIET --silent --SILENT + Quiet the terminal bell. + -r -R .... --raw-control-chars --RAW-CONTROL-CHARS + Output "raw" control characters. + -s ........ --squeeze-blank-lines + Squeeze multiple blank lines. + -S ........ --chop-long-lines + Chop long lines. + -t [tag] .. --tag=[tag] + Find a tag. + -T [tagsfile] --tag-file=[tagsfile] + Use an alternate tags file. + -u -U .... --underline-special --UNDERLINE-SPECIAL + Change handling of backspaces. + -V ........ --version + Display the version number of "less". + -w ........ --hilite-unread + Highlight first new line after forward-screen. + -W ........ --HILITE-UNREAD + Highlight first new line after any forward movement. + -x [N[,...]] --tabs=[N[,...]] + Set tab stops. + -X ........ --no-init + Don't use termcap init/deinit strings. + --no-keypad + Don't use termcap keypad init/deinit strings. + -y [N] .... --max-forw-scroll=[N] + Forward scroll limit. + -z [N] .... --window=[N] + Set size of window. + -" [c[c]] . --quotes=[c[c]] + Set shell quote characters. + -~ ........ --tilde + Don't display tildes after end of file. + -# [N] .... --shift=[N] + Horizontal scroll amount (0 = one half screen width) + + --------------------------------------------------------------------------- + LINE EDITING + These keys can be used to edit text being entered + on the "command line" at the bottom of the screen. + RightArrow ESC-l Move cursor right one character. + LeftArrow ESC-h Move cursor left one character. + CNTL-RightArrow ESC-RightArrow ESC-w Move cursor right one word. + CNTL-LeftArrow ESC-LeftArrow ESC-b Move cursor left one word. + HOME ESC-0 Move cursor to start of line. + END ESC-$ Move cursor to end of line. + BACKSPACE Delete char to left of cursor. + DELETE ESC-x Delete char under cursor. + CNTL-BACKSPACE ESC-BACKSPACE Delete word to left of cursor. + CNTL-DELETE ESC-DELETE ESC-X Delete word under cursor. + CNTL-U ESC (MS-DOS only) Delete entire line. + UpArrow ESC-k Retrieve previous command line. + DownArrow ESC-j Retrieve next command line. + TAB Complete filename & cycle. + SHIFT-TAB ESC-TAB Complete filename & reverse cycle. + CNTL-L Complete filename, list all. +*/ diff --git a/release/src/router/busybox/miscutils/man.c b/release/src/router/busybox/miscutils/man.c index e6824ebc86..672ddb1c8e 100644 --- a/release/src/router/busybox/miscutils/man.c +++ b/release/src/router/busybox/miscutils/man.c @@ -168,10 +168,12 @@ int man_main(int argc UNUSED_PARAM, char **argv) sec_list = xstrdup("1:2:3:4:5:6:7:8:9"); /* Last valid man_path_list[] is [0x10] */ - man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); count_mp = 0; - man_path_list[0] = xstrdup(getenv("MANPATH")); - if (man_path_list[0]) + man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); + man_path_list[0] = getenv("MANPATH"); + if (!man_path_list[0]) /* default, may be overridden by /etc/man.conf */ + man_path_list[0] = (char*)"/usr/man"; + else count_mp++; pager = getenv("MANPAGER"); if (!pager) { @@ -181,16 +183,40 @@ int man_main(int argc UNUSED_PARAM, char **argv) } /* Parse man.conf */ - parser = config_open("/etc/man.conf"); + parser = config_open2("/etc/man.conf", fopen_for_read); while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) { if (!token[1]) continue; if (strcmp("MANPATH", token[0]) == 0) { - man_path_list = xrealloc_vector(man_path_list, 4, count_mp); - man_path_list[count_mp] = xstrdup(token[1]); - count_mp++; - /* man_path_list is NULL terminated */ - /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */ + char *path = token[1]; + while (*path) { + char *next_path; + char **path_element; + + next_path = strchr(path, ':'); + if (next_path) { + *next_path = '\0'; + if (next_path++ == path) /* "::"? */ + goto next; + } + /* Do we already have path? */ + path_element = man_path_list; + while (*path_element) { + if (strcmp(*path_element, path) == 0) + goto skip; + path_element++; + } + man_path_list = xrealloc_vector(man_path_list, 4, count_mp); + man_path_list[count_mp] = xstrdup(path); + count_mp++; + /* man_path_list is NULL terminated */ + /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */ + skip: + if (!next_path) + break; + next: + path = next_path; + } } if (strcmp("MANSECT", token[0]) == 0) { free(sec_list); @@ -210,41 +236,34 @@ int man_main(int argc UNUSED_PARAM, char **argv) } while ((cur_path = man_path_list[cur_mp++]) != NULL) { /* for each MANPATH */ - do { /* for each MANPATH item */ - char *next_path = strchrnul(cur_path, ':'); - int path_len = next_path - cur_path; - cur_sect = sec_list; - do { /* for each section */ - char *next_sect = strchrnul(cur_sect, ':'); - int sect_len = next_sect - cur_sect; - char *man_filename; - int cat0man1 = 0; - - /* Search for cat, then man page */ - while (cat0man1 < 2) { - int found_here; - man_filename = xasprintf("%.*s/%s%.*s/%s.%.*s" Z_SUFFIX, - path_len, cur_path, - "cat\0man" + (cat0man1 * 4), - sect_len, cur_sect, - *argv, - sect_len, cur_sect); - found_here = show_manpage(pager, man_filename, cat0man1, 0); - found |= found_here; - cat0man1 += found_here + 1; - free(man_filename); - } - - if (found && !(opt & OPT_a)) - goto next_arg; - cur_sect = next_sect; - while (*cur_sect == ':') - cur_sect++; - } while (*cur_sect); - cur_path = next_path; - while (*cur_path == ':') - cur_path++; - } while (*cur_path); + cur_sect = sec_list; + do { /* for each section */ + char *next_sect = strchrnul(cur_sect, ':'); + int sect_len = next_sect - cur_sect; + char *man_filename; + int cat0man1 = 0; + + /* Search for cat, then man page */ + while (cat0man1 < 2) { + int found_here; + man_filename = xasprintf("%s/%s%.*s/%s.%.*s" Z_SUFFIX, + cur_path, + "cat\0man" + (cat0man1 * 4), + sect_len, cur_sect, + *argv, + sect_len, cur_sect); + found_here = show_manpage(pager, man_filename, cat0man1, 0); + found |= found_here; + cat0man1 += found_here + 1; + free(man_filename); + } + + if (found && !(opt & OPT_a)) + goto next_arg; + cur_sect = next_sect; + while (*cur_sect == ':') + cur_sect++; + } while (*cur_sect); } check_found: if (!found) { diff --git a/release/src/router/busybox/miscutils/microcom.c b/release/src/router/busybox/miscutils/microcom.c index ac3e5514f3..a322197b83 100644 --- a/release/src/router/busybox/miscutils/microcom.c +++ b/release/src/router/busybox/miscutils/microcom.c @@ -9,14 +9,6 @@ */ #include "libbb.h" -/* All known arches use small ints for signals */ -static volatile smallint signalled; - -static void signal_handler(int signo) -{ - signalled = signo; -} - // set raw tty mode static void xget1(int fd, struct termios *t, struct termios *oldt) { @@ -91,10 +83,10 @@ int microcom_main(int argc UNUSED_PARAM, char **argv) + (1 << SIGINT) + (1 << SIGTERM) + (1 << SIGPIPE) - , signal_handler); + , record_signo); // error exit code if we fail to open the device - signalled = 1; + bb_got_signal = 1; // open device sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK); @@ -123,9 +115,9 @@ int microcom_main(int argc UNUSED_PARAM, char **argv) pfd[1].fd = STDIN_FILENO; pfd[1].events = POLLIN; - signalled = 0; + bb_got_signal = 0; nfd = 2; - while (!signalled && safe_poll(pfd, nfd, timeout) > 0) { + while (!bb_got_signal && safe_poll(pfd, nfd, timeout) > 0) { if (nfd > 1 && pfd[1].revents) { char c; // read from stdin -> write to device @@ -159,7 +151,7 @@ skip_write: ; full_write(STDOUT_FILENO, iobuf, len); else { // EOF/error -> bail out - signalled = SIGHUP; + bb_got_signal = SIGHUP; break; } } @@ -175,5 +167,5 @@ done: if (device_lock_file) unlink(device_lock_file); - return signalled; + return bb_got_signal; } diff --git a/release/src/router/busybox/miscutils/mountpoint.c b/release/src/router/busybox/miscutils/mountpoint.c dissimilarity index 71% index 5647e4c5b2..b541ce28c3 100644 --- a/release/src/router/busybox/miscutils/mountpoint.c +++ b/release/src/router/busybox/miscutils/mountpoint.c @@ -1,66 +1,72 @@ -/* vi: set sw=4 ts=4: */ -/* - * mountpoint implementation for busybox - * - * Copyright (C) 2005 Bernhard Fischer - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - * - * Based on sysvinit's mountpoint - */ - -#include "libbb.h" - -int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int mountpoint_main(int argc, char **argv) -{ - struct stat st; - char *arg; - int opt = getopt32(argv, "qdx"); -#define OPT_q (1) -#define OPT_d (2) -#define OPT_x (4) - - if (optind != argc - 1) - bb_show_usage(); - - arg = argv[optind]; - - if ( (opt & OPT_x && stat(arg, &st) == 0) || (lstat(arg, &st) == 0) ) { - if (opt & OPT_x) { - if (S_ISBLK(st.st_mode)) { - printf("%u:%u\n", major(st.st_rdev), - minor(st.st_rdev)); - return EXIT_SUCCESS; - } else { - if (opt & OPT_q) - bb_putchar('\n'); - else - bb_error_msg("%s: not a block device", arg); - } - return EXIT_FAILURE; - } else - if (S_ISDIR(st.st_mode)) { - dev_t st_dev = st.st_dev; - ino_t st_ino = st.st_ino; - char *p = xasprintf("%s/..", arg); - - if (stat(p, &st) == 0) { - int ret = (st_dev != st.st_dev) || - (st_dev == st.st_dev && st_ino == st.st_ino); - if (opt & OPT_d) - printf("%u:%u\n", major(st_dev), minor(st_dev)); - else if (!(opt & OPT_q)) - printf("%s is %sa mountpoint\n", arg, ret?"":"not "); - return !ret; - } - } else { - if (!(opt & OPT_q)) - bb_error_msg("%s: not a directory", arg); - return EXIT_FAILURE; - } - } - if (!(opt & OPT_q)) - bb_simple_perror_msg(arg); - return EXIT_FAILURE; -} +/* vi: set sw=4 ts=4: */ +/* + * mountpoint implementation for busybox + * + * Copyright (C) 2005 Bernhard Reutner-Fischer + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * + * Based on sysvinit's mountpoint + */ + +#include "libbb.h" + +int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mountpoint_main(int argc UNUSED_PARAM, char **argv) +{ + struct stat st; + const char *msg; + char *arg; + int rc, opt; + + opt_complementary = "=1"; /* must have one argument */ + opt = getopt32(argv, "qdxn"); +#define OPT_q (1) +#define OPT_d (2) +#define OPT_x (4) +#define OPT_n (8) + arg = argv[optind]; + msg = "%s"; + + rc = (opt & OPT_x) ? stat(arg, &st) : lstat(arg, &st); + if (rc != 0) + goto err; + + if (opt & OPT_x) { + if (S_ISBLK(st.st_mode)) { + printf("%u:%u\n", major(st.st_rdev), + minor(st.st_rdev)); + return EXIT_SUCCESS; + } + errno = 0; /* make perror_msg work as error_msg */ + msg = "%s: not a block device"; + goto err; + } + + errno = ENOTDIR; + if (S_ISDIR(st.st_mode)) { + dev_t st_dev = st.st_dev; + ino_t st_ino = st.st_ino; + char *p = xasprintf("%s/..", arg); + + if (stat(p, &st) == 0) { + //int is_mnt = (st_dev != st.st_dev) || (st_dev == st.st_dev && st_ino == st.st_ino); + int is_not_mnt = (st_dev == st.st_dev) && (st_ino != st.st_ino); + + if (opt & OPT_d) + printf("%u:%u\n", major(st_dev), minor(st_dev)); + if (opt & OPT_n) + printf("%s %s\n", find_block_device(arg), arg); + if (!(opt & (OPT_q | OPT_d | OPT_n))) + printf("%s is %sa mountpoint\n", arg, is_not_mnt ? "not " : ""); + return is_not_mnt; + } + arg = p; + /* else: stat had set errno, just fall through */ + } + + err: + if (!(opt & OPT_q)) + bb_perror_msg(msg, arg); + return EXIT_FAILURE; +} diff --git a/release/src/router/busybox/miscutils/raidautorun.c b/release/src/router/busybox/miscutils/raidautorun.c index 2766245dba..a2a852bbf2 100644 --- a/release/src/router/busybox/miscutils/raidautorun.c +++ b/release/src/router/busybox/miscutils/raidautorun.c @@ -2,7 +2,7 @@ /* * raidautorun implementation for busybox * - * Copyright (C) 2006 Bernhard Fischer + * Copyright (C) 2006 Bernhard Reutner-Fischer * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. * diff --git a/release/src/router/busybox/miscutils/runlevel.c b/release/src/router/busybox/miscutils/runlevel.c index 04064ee73d..6e10d9cbb1 100644 --- a/release/src/router/busybox/miscutils/runlevel.c +++ b/release/src/router/busybox/miscutils/runlevel.c @@ -9,7 +9,7 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. * - * initially busyboxified by Bernhard Fischer + * initially busyboxified by Bernhard Reutner-Fischer */ #include diff --git a/release/src/router/busybox/miscutils/setsid.c b/release/src/router/busybox/miscutils/setsid.c index 127adf6f28..d7de1f1497 100644 --- a/release/src/router/busybox/miscutils/setsid.c +++ b/release/src/router/busybox/miscutils/setsid.c @@ -26,7 +26,8 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) * Otherwise our PID serves as PGID of some existing process group * and cannot be used as PGID of a new process group. */ if (getpgrp() == getpid()) - forkexit_or_rexec(argv); + if (fork_or_rexec(argv)) + exit(EXIT_SUCCESS); /* parent */ setsid(); /* no error possible */ diff --git a/release/src/router/busybox/miscutils/strings.c b/release/src/router/busybox/miscutils/strings.c index 3e02b53afd..fea9edbed5 100644 --- a/release/src/router/busybox/miscutils/strings.c +++ b/release/src/router/busybox/miscutils/strings.c @@ -2,7 +2,7 @@ /* * strings implementation for busybox * - * Copyright Tito Ragusa + * Copyright 2003 Tito Ragusa * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ @@ -18,7 +18,6 @@ int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int strings_main(int argc UNUSED_PARAM, char **argv) { int n, c, status = EXIT_SUCCESS; - unsigned opt; unsigned count; off_t offset; FILE *file; @@ -26,7 +25,7 @@ int strings_main(int argc UNUSED_PARAM, char **argv) const char *fmt = "%s: "; const char *n_arg = "4"; - opt = getopt32(argv, "afon:", &n_arg); + getopt32(argv, "afon:", &n_arg); /* -a is our default behaviour */ /*argc -= optind;*/ argv += optind; @@ -56,10 +55,10 @@ int strings_main(int argc UNUSED_PARAM, char **argv) } else { string[count] = c; if (count == n) { - if (opt & PRINT_NAME) { + if (option_mask32 & PRINT_NAME) { printf(fmt, *argv); } - if (opt & PRINT_OFFSET) { + if (option_mask32 & PRINT_OFFSET) { printf("%7"OFF_FMT"o ", offset - n); } fputs(string, stdout); diff --git a/release/src/router/busybox/miscutils/taskset.c b/release/src/router/busybox/miscutils/taskset.c index b43d42e905..a0bbf0aa19 100644 --- a/release/src/router/busybox/miscutils/taskset.c +++ b/release/src/router/busybox/miscutils/taskset.c @@ -1,7 +1,7 @@ /* vi: set sw=4 ts=4: */ /* * taskset - retrieve or set a processes' CPU affinity - * Copyright (c) 2006 Bernhard Fischer + * Copyright (c) 2006 Bernhard Reutner-Fischer * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/release/src/router/busybox/miscutils/time.c b/release/src/router/busybox/miscutils/time.c index dbc92d12ff..30298fe324 100644 --- a/release/src/router/busybox/miscutils/time.c +++ b/release/src/router/busybox/miscutils/time.c @@ -89,7 +89,7 @@ static void printargv(char *const *argv) This is funky since the pagesize could be less than 1K. Note: Some machines express getrusage statistics in terms of K, others in terms of pages. */ -static unsigned long ptok(unsigned pagesize, unsigned long pages) +static unsigned long ptok(const unsigned pagesize, const unsigned long pages) { unsigned long tmp; @@ -303,7 +303,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) printf("%lu", ptok(pagesize, (UL) resp->ru.ru_ixrss) / cpu_ticks); break; case 'Z': /* Page size. */ - printf("%u", getpagesize()); + printf("%u", pagesize); break; case 'c': /* Involuntary context switches. */ printf("%lu", resp->ru.ru_nivcsw); diff --git a/release/src/router/busybox/miscutils/timeout.c b/release/src/router/busybox/miscutils/timeout.c new file mode 100644 index 0000000000..83ae56e69e --- /dev/null +++ b/release/src/router/busybox/miscutils/timeout.c @@ -0,0 +1,115 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * COPYING NOTES + * + * timeout.c -- a timeout handler for shell commands + * + * Copyright (C) 2005-6, Roberto A. Foglietta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * REVISION NOTES: + * released 17-11-2005 by Roberto A. Foglietta + * talarm 04-12-2005 by Roberto A. Foglietta + * modified 05-12-2005 by Roberto A. Foglietta + * sizerdct 06-12-2005 by Roberto A. Foglietta + * splitszf 12-05-2006 by Roberto A. Foglietta + * rewrite 14-11-2008 vda + */ + +#include "libbb.h" + +int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int timeout_main(int argc UNUSED_PARAM, char **argv) +{ + int signo; + int status; + int parent = 0; + int timeout = 10; + pid_t pid; +#if !BB_MMU + char *sv1, *sv2; +#endif + const char *opt_s = "TERM"; + + /* -p option is not documented, it is needed to support NOMMU. */ + + /* -t SECONDS; -p PARENT_PID */ + opt_complementary = "t+" USE_FOR_NOMMU(":p+"); + /* '+': stop at first non-option */ + getopt32(argv, "+s:t:" USE_FOR_NOMMU("p:"), &opt_s, &timeout, &parent); + /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ + signo = get_signum(opt_s); + if (signo < 0) + bb_error_msg_and_die("unknown signal '%s'", opt_s); + + /* We want to create a grandchild which will watch + * and kill the grandparent. Other methods: + * making parent watch child disrupts parent<->child link + * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" - + * it's better if service_prog is a child of tcpsvd!), + * making child watch parent results in programs having + * unexpected children. */ + + if (parent) /* we were re-execed, already grandchild */ + goto grandchild; + if (!argv[optind]) /* no PROG? */ + bb_show_usage(); + +#if !BB_MMU + sv1 = argv[optind]; + sv2 = argv[optind + 1]; +#endif + pid = vfork(); + if (pid < 0) + bb_perror_msg_and_die("vfork"); + if (pid == 0) { + /* Child: spawn grandchild and exit */ + parent = getppid(); +#if !BB_MMU + argv[optind] = xasprintf("-p%u", parent); + argv[optind + 1] = NULL; +#endif + /* NB: exits with nonzero on error: */ + 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! */ + while (1) { + sleep(1); + if (--timeout <= 0) + break; + if (kill(parent, 0)) { + /* process is gone */ + return EXIT_SUCCESS; + } + } + kill(parent, signo); + return EXIT_SUCCESS; + } + + /* Parent */ + wait(&status); /* wait for child to die */ + /* Did intermediate [v]fork or exec fail? */ + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return EXIT_FAILURE; + /* Ok, exec a program as requested */ + argv += optind; +#if !BB_MMU + argv[0] = sv1; + argv[1] = sv2; +#endif + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("exec '%s'", argv[0]); +} diff --git a/release/src/router/busybox/miscutils/watchdog.c b/release/src/router/busybox/miscutils/watchdog.c index 9b1a110eac..f85138e119 100644 --- a/release/src/router/busybox/miscutils/watchdog.c +++ b/release/src/router/busybox/miscutils/watchdog.c @@ -3,15 +3,19 @@ * Mini watchdog implementation for busybox * * Copyright (C) 2003 Paul Mundt - * Copyright (C) 2006 Bernhard Fischer + * Copyright (C) 2006 Bernhard Reutner-Fischer + * Copyright (C) 2008 Darius Augulis * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ #include "libbb.h" +#include "linux/types.h" /* for __u32 */ +#include "linux/watchdog.h" -#define OPT_FOREGROUND 0x01 -#define OPT_TIMER 0x02 +#define OPT_FOREGROUND (1 << 0) +#define OPT_STIMER (1 << 1) +#define OPT_HTIMER (1 << 2) static void watchdog_shutdown(int sig UNUSED_PARAM) { @@ -26,46 +30,56 @@ static void watchdog_shutdown(int sig UNUSED_PARAM) int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int watchdog_main(int argc, char **argv) { - unsigned opts; - unsigned timer_duration = 30000; /* Userspace timer duration, in milliseconds */ - char *t_arg; + static const struct suffix_mult suffixes[] = { + { "ms", 1 }, + { "", 1000 }, + { } + }; - opt_complementary = "=1"; /* must have 1 argument */ - opts = getopt32(argv, "Ft:", &t_arg); + unsigned opts; + unsigned stimer_duration; /* how often to restart */ + unsigned htimer_duration = 60000; /* reboots after N ms if not restarted */ + char *st_arg; + char *ht_arg; - if (opts & OPT_TIMER) { - static const struct suffix_mult suffixes[] = { - { "ms", 1 }, - { "", 1000 }, - { } - }; - timer_duration = xatou_sfx(t_arg, suffixes); - } + opt_complementary = "=1"; /* must have exactly 1 argument */ + opts = getopt32(argv, "Ft:T:", &st_arg, &ht_arg); - if (!(opts & OPT_FOREGROUND)) { - bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); - } + if (opts & OPT_HTIMER) + htimer_duration = xatou_sfx(ht_arg, suffixes); + stimer_duration = htimer_duration / 2; + if (opts & OPT_STIMER) + stimer_duration = xatou_sfx(st_arg, suffixes); bb_signals(BB_FATAL_SIGS, watchdog_shutdown); /* Use known fd # - avoid needing global 'int fd' */ xmove_fd(xopen(argv[argc - 1], O_WRONLY), 3); -// TODO? -// if (!(opts & OPT_TIMER)) { -// if (ioctl(fd, WDIOC_GETTIMEOUT, &timer_duration) == 0) -// timer_duration *= 500; -// else -// timer_duration = 30000; -// } + /* WDIOC_SETTIMEOUT takes seconds, not milliseconds */ + htimer_duration = htimer_duration / 1000; +#ifndef WDIOC_SETTIMEOUT +#error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet +#else + ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration); +#endif +#if 0 + ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration); + printf("watchdog: SW timer is %dms, HW timer is %dms\n", + stimer_duration, htimer_duration * 1000); +#endif + + if (!(opts & OPT_FOREGROUND)) { + bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); + } while (1) { /* - * Make sure we clear the counter before sleeping, as the counter value - * is undefined at this point -- PFM + * Make sure we clear the counter before sleeping, + * as the counter value is undefined at this point -- PFM */ write(3, "", 1); /* write zero byte */ - usleep(timer_duration * 1000L); + usleep(stimer_duration * 1000L); } return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */ } diff --git a/release/src/router/busybox/modutils/Config.in b/release/src/router/busybox/modutils/Config.in index a430fcac33..ef8d9692a3 100644 --- a/release/src/router/busybox/modutils/Config.in +++ b/release/src/router/busybox/modutils/Config.in @@ -44,7 +44,6 @@ config FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE depends on MODPROBE_SMALL help Allow insmod and modprobe take module options from command line. - N.B. Very bloaty. config FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED bool "Skip loading of already loaded modules" @@ -52,50 +51,81 @@ config FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED depends on MODPROBE_SMALL help Check if the module is already loaded. - N.B. It's racy. -config DEPMOD - bool "depmod" +config INSMOD + bool "insmod" default n depends on !MODPROBE_SMALL help - depmod generates modules.dep (FIXME: elaborate) + insmod is used to load specified modules in the running kernel. -config FEATURE_DEPMOD_PRUNE_FANCY - bool "Fancy dependency pruning" +config RMMOD + bool "rmmod" default n - depends on DEPMOD + depends on !MODPROBE_SMALL help - By default modules.dep contains all dependencies as listed by - the modules. - If you enable this option then we remove implied modules from - the dependencies. - This makes depmod somewhat bigger but generates a smaller - modules.dep file. + rmmod is used to unload specified modules from the kernel. - If unsure, say N. +config LSMOD + bool "lsmod" + default n + depends on !MODPROBE_SMALL + help + lsmod is used to display a list of loaded modules. -config FEATURE_DEPMOD_ALIAS - bool "Alias support" +config FEATURE_LSMOD_PRETTY_2_6_OUTPUT + bool "Pretty output" default n - depends on DEPMOD + depends on LSMOD help - By default modules.dep does not contain alias information. - Enable this to emit aliases of the form: + This option makes output format of lsmod adjusted to + the format of module-init-tools for Linux kernel 2.6. + Increases size somewhat. - alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs +config MODPROBE + bool "modprobe" + default n + depends on !MODPROBE_SMALL + help + Handle the loading of modules, and their dependencies on a high + level. -config INSMOD - bool "insmod" +config FEATURE_MODPROBE_BLACKLIST + bool + prompt "Blacklist support" + default n + depends on MODPROBE + help + Say 'y' here to enable support for the 'blacklist' command in + modprobe.conf. This prevents the alias resolver to resolve + blacklisted modules. This is useful if you want to prevent your + hardware autodetection scripts to load modules like evdev, frame + buffer drivers etc. + +config DEPMOD + bool "depmod" default n depends on !MODPROBE_SMALL help - insmod is used to load specified modules in the running kernel. + depmod generates modules.dep (and potentially modules.alias + and modules.symbols) that contain dependency information + for modprobe. + +comment "Options common to multiple modutils" + +config FEATURE_2_4_MODULES + bool "Support version 2.2/2.4 Linux kernels" + default n + depends on INSMOD || RMMOD || LSMOD + help + Support module loading for 2.2.x and 2.4.x Linux kernels. + This increases size considerably. Say N unless you plan + to run ancient kernels. config FEATURE_INSMOD_VERSION_CHECKING - bool "Module version checking" + bool "Enable module version checking" default n - depends on INSMOD && FEATURE_2_4_MODULES + depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) help Support checking of versions for modules. This is used to ensure that the kernel and module are made for each other. @@ -103,18 +133,18 @@ config FEATURE_INSMOD_VERSION_CHECKING config FEATURE_INSMOD_KSYMOOPS_SYMBOLS bool "Add module symbols to kernel symbol table" default n - depends on INSMOD && FEATURE_2_4_MODULES + depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) help By adding module symbols to the kernel symbol table, Oops messages occuring within kernel modules can be properly debugged. By enabling this feature, module symbols will always be added to the kernel symbol - table for properly debugging support. If you are not interested in + table for proper debugging support. If you are not interested in Oops messages from kernel modules, say N. config FEATURE_INSMOD_LOADINKMEM bool "In kernel memory optimization (uClinux only)" default n - depends on INSMOD && FEATURE_2_4_MODULES + depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) help This is a special uClinux only memory optimization that lets insmod load the specified kernel module directly into kernel space, reducing @@ -122,9 +152,9 @@ config FEATURE_INSMOD_LOADINKMEM being loaded into memory. config FEATURE_INSMOD_LOAD_MAP - bool "Enable load map (-m) option" + bool "Enable insmod load map (-m) option" default n - depends on INSMOD && ( FEATURE_2_4_MODULES || FEATURE_2_6_MODULES ) + depends on FEATURE_2_4_MODULES && INSMOD help Enabling this, one would be able to get a load map output on stdout. This makes kernel module debugging @@ -135,138 +165,63 @@ config FEATURE_INSMOD_LOAD_MAP config FEATURE_INSMOD_LOAD_MAP_FULL bool "Symbols in load map" default y - depends on FEATURE_INSMOD_LOAD_MAP + depends on FEATURE_INSMOD_LOAD_MAP && !MODPROBE_SMALL help Without this option, -m will only output section load map. With this option, -m will also output symbols load map. -config RMMOD - bool "rmmod" - default n - depends on !MODPROBE_SMALL - help - rmmod is used to unload specified modules from the kernel. - -config LSMOD - bool "lsmod" - default n - depends on !MODPROBE_SMALL - help - lsmod is used to display a list of loaded modules. - -config FEATURE_LSMOD_PRETTY_2_6_OUTPUT - bool "Pretty output for 2.6.x Linux kernels" - default n - depends on LSMOD - help - This option makes output format of lsmod adjusted to - the format of module-init-tools for Linux kernel 2.6. - -config MODPROBE - bool "modprobe" - default n - depends on !MODPROBE_SMALL - help - Handle the loading of modules, and their dependencies on a high - level. - - Note that in the state, modprobe does not understand multiple - module options from the configuration file. See option below. - -config FEATURE_MODPROBE_MULTIPLE_OPTIONS - bool - prompt "Multiple options parsing" - default y - depends on MODPROBE - help - Allow modprobe to understand more than one option to pass to - modules. - - This is a WIP, while waiting for a common argument parsing - common amongst all BB applets (shell, modprobe, etc...) and - adds around 600 bytes on x86, 700 bytes on ARM. The code is - biggish and uggly, but just works. - - Saying Y here is not a bad idea if you're not that short - on storage capacity. - -config FEATURE_MODPROBE_FANCY_ALIAS - bool - prompt "Fancy alias parsing" - default y - depends on MODPROBE && FEATURE_2_6_MODULES - help - Say 'y' here to enable parsing of aliases with underscore/dash - mismatch between module name and file name, along with bus-specific - aliases (such as pci:... or usb:... aliases). - -config FEATURE_MODPROBE_BLACKLIST - bool - prompt "Blacklist support" - default n - depends on MODPROBE && FEATURE_2_6_MODULES - help - Say 'y' here to enable support for the 'blacklist' command in - modprobe.conf. This prevents the alias resolver to resolve - blacklisted modules. This is useful if you want to prevent your - hardware autodetection scripts to load modules like evdev, frame - buffer drivers etc. - -comment "Options common to multiple modutils" - depends on INSMOD || RMMOD || MODPROBE || LSMOD || DEPMOD - config FEATURE_CHECK_TAINTED_MODULE - # Simulate indentation bool "Support tainted module checking with new kernels" default y - depends on INSMOD || LSMOD + depends on (LSMOD || FEATURE_2_4_MODULES) && !MODPROBE_SMALL help Support checking for tainted modules. These are usually binary only modules that will make the linux-kernel list ignore your support request. This option is required to support GPLONLY modules. -config FEATURE_2_4_MODULES - # Simulate indentation - bool "Support version 2.2.x to 2.4.x Linux kernels" +config FEATURE_MODUTILS_ALIAS + bool "Support for module.aliases file" default y - depends on INSMOD || RMMOD || MODPROBE + depends on DEPMOD || MODPROBE help - Support module loading for 2.2.x and 2.4.x Linux kernels. + Generate and parse modules.alias containing aliases for bus + identifiers: + alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs - Note: - This is automatically enabled if 2.6 modules are not enabled. + and aliases for logical modules names e.g.: + alias padlock_aes aes + alias aes_i586 aes + alias aes_generic aes -config FEATURE_2_6_MODULES - # Simulate indentation - bool "Support version 2.6.x Linux kernels" + Say Y if unsure. + +config FEATURE_MODUTILS_SYMBOLS + bool "Support for module.symbols file" default y - depends on INSMOD || RMMOD || MODPROBE + depends on DEPMOD || MODPROBE help - Support module loading for newer 2.6.x Linux kernels. + Generate and parse modules.symbols containing aliases for + symbol_request() kernel calls, such as: + alias symbol:usb_sg_init usbcore + + Say Y if unsure. config DEFAULT_MODULES_DIR - # Simulate indentation string "Default directory containing modules" default "/lib/modules" - depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD + depends on DEPMOD || MODPROBE || MODPROBE_SMALL help Directory that contains kernel modules. Defaults to "/lib/modules" config DEFAULT_DEPMOD_FILE - # Simulate indentation string "Default name of modules.dep" default "modules.dep" - depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD + depends on DEPMOD || MODPROBE || MODPROBE_SMALL help Filename that contains kernel modules dependencies. Defaults to "modules.dep" -config FEATURE_QUERY_MODULE_INTERFACE - bool - default y - depends on FEATURE_2_4_MODULES && !FEATURE_2_6_MODULES - endmenu diff --git a/release/src/router/busybox/modutils/Kbuild b/release/src/router/busybox/modutils/Kbuild dissimilarity index 61% index 828070114e..31f7cbf93a 100644 --- a/release/src/router/busybox/modutils/Kbuild +++ b/release/src/router/busybox/modutils/Kbuild @@ -1,13 +1,14 @@ -# Makefile for busybox -# -# Copyright (C) 1999-2005 by Erik Andersen -# -# Licensed under the GPL v2, see the file LICENSE in this tarball. - -lib-y:= -lib-$(CONFIG_DEPMOD) += depmod.o -lib-$(CONFIG_INSMOD) += insmod.o -lib-$(CONFIG_LSMOD) += lsmod.o -lib-$(CONFIG_MODPROBE) += modprobe.o -lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o -lib-$(CONFIG_RMMOD) += rmmod.o +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= +lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o +lib-$(CONFIG_DEPMOD) += depmod.o modutils.o +lib-$(CONFIG_INSMOD) += insmod.o modutils.o +lib-$(CONFIG_LSMOD) += lsmod.o modutils.o +lib-$(CONFIG_MODPROBE) += modprobe.o modutils.o +lib-$(CONFIG_RMMOD) += rmmod.o modutils.o +lib-$(CONFIG_FEATURE_2_4_MODULES) += modutils-24.o diff --git a/release/src/router/busybox/modutils/depmod.c b/release/src/router/busybox/modutils/depmod.c dissimilarity index 87% index b6a914eb05..405ba9e2a0 100644 --- a/release/src/router/busybox/modutils/depmod.c +++ b/release/src/router/busybox/modutils/depmod.c @@ -1,288 +1,232 @@ -/* vi: set sw=4 ts=4: */ -/* - * depmod - generate modules.dep - * Copyright (c) 2008 Bernhard Fischer - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#undef _GNU_SOURCE -#define _GNU_SOURCE -#include -#include /* uname() */ -/* - * Theory of operation: - * - iterate over all modules and record their full path - * - iterate over all modules looking for "depends=" entries - * for each depends, look through our list of full paths and emit if found - */ - -typedef struct dep_lst_t { - char *name; - llist_t *dependencies; - llist_t *aliases; - struct dep_lst_t *next; -} dep_lst_t; - -struct globals { - dep_lst_t *lst; /* modules without their corresponding extension */ -}; -#define G (*(struct globals*)&bb_common_bufsiz1) -/* We have to zero it out because of NOEXEC */ -#define INIT_G() memset(&G, 0, sizeof(G)) - -static char* find_keyword(void *the_module, size_t len, const char * const word) -{ - char *ptr = the_module; - do { - /* search for the first char in word */ - ptr = memchr(ptr, *word, len - (ptr - (char*)the_module)); - if (ptr == NULL) /* no occurance left, done */ - return NULL; - if (!strncmp(ptr, word, strlen(word))) { - ptr += strlen(word); - break; - } - ++ptr; - } while (1); - return ptr; -} -static int FAST_FUNC fileAction(const char *fname, struct stat *sb, - void UNUSED_PARAM *data, int UNUSED_PARAM depth) -{ - size_t len = sb->st_size; - void *the_module; - char *ptr; - int fd; - char *depends, *deps; - dep_lst_t *this; - - if (strrstr(fname, ".ko") == NULL) /* not a module */ - goto skip; - -/*XXX: FIXME: does not handle compressed modules! - * There should be a function that looks at the extension and sets up - * open_transformer for us. - */ - fd = xopen(fname, O_RDONLY); - the_module = mmap(NULL, len, PROT_READ, MAP_SHARED -#if defined MAP_POPULATE - |MAP_POPULATE -#endif - , fd, 0); - close(fd); - if (the_module == MAP_FAILED) - bb_perror_msg_and_die("mmap"); - - this = xzalloc(sizeof(dep_lst_t)); - this->name = xstrdup(fname); - this->next = G.lst; - G.lst = this; -//bb_info_msg("fname='%s'", fname); - ptr = find_keyword(the_module, len, "depends="); - if (!*ptr) - goto d_none; - deps = depends = xstrdup(ptr); -//bb_info_msg(" depends='%s'", depends); - while (deps) { - ptr = strsep(&deps, ","); -//bb_info_msg("[%s] -> '%s'", fname, (char*)ptr); - llist_add_to_end(&this->dependencies, xstrdup(ptr)); - } - free(depends); - d_none: - if (ENABLE_FEATURE_DEPMOD_ALIAS) - { - size_t pos = 0; - do { - ptr = find_keyword(the_module + pos, len - pos, "alias="); - if (ptr) { -//bb_info_msg("[%s] alias '%s'", fname, (char*)ptr); - llist_add_to_end(&this->aliases, xstrdup(ptr)); - } else - break; - pos = (ptr - (char*)the_module); - } while (1); - } - munmap(the_module, sb->st_size); - skip: - return TRUE; -} - -int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int depmod_main(int argc UNUSED_PARAM, char **argv) -{ - int ret; - size_t moddir_base_len = 0; /* length of the "-b basedir" */ - char *moddir_base = NULL, *moddir, *system_map, *chp; - FILE *filedes = stdout; - enum { - ARG_a = (1<<0), /* All modules, ignore mods in argv */ - ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */ - ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */ - ARG_e = (1<<3), /* with -F, print unresolved symbols */ - ARG_F = (1<<4), /* System.map that contains the symbols */ - ARG_n = (1<<5) /* dry-run, print to stdout only */ - }; - INIT_G(); - - getopt32(argv, "aAb:eF:n", &moddir_base, &system_map); - argv += optind; - - /* If a version is provided, then that kernel version’s module directory - * is used, rather than the current kernel version (as returned by - * "uname -r"). */ - if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) { - moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++); - } else { - struct utsname uts; - if (uname(&uts) < 0) - bb_simple_perror_msg_and_die("uname"); - moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release); - } - /* If no modules are given on the command-line, -a is on per default. */ - option_mask32 |= *argv == NULL; - - if (option_mask32 & ARG_b) { - moddir_base_len = strlen(moddir_base) + 1; - xchdir(moddir_base); - } - - if (!(option_mask32 & ARG_n)) { /* --dry-run */ - chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE); - filedes = xfopen_for_write(chp); - if (ENABLE_FEATURE_CLEAN_UP) - free(chp); - } - ret = EXIT_SUCCESS; - do { - chp = option_mask32 & ARG_a ? moddir : (*argv + moddir_base_len); - - if (!recursive_action(chp, - ACTION_RECURSE, /* flags */ - fileAction, /* file action */ - NULL, /* dir action */ - NULL, /* user data */ - 0)) { /* depth */ - ret = EXIT_FAILURE; - } - } while (!(option_mask32 & ARG_a) && *++argv); - - { - dep_lst_t *mods = G.lst; - - /* Fixup the module names in the depends list */ - while (mods) { - llist_t *deps = NULL, *old_deps = mods->dependencies; - - while (old_deps) { - dep_lst_t *all = G.lst; - char *longname = NULL; - char *shortname = llist_pop(&old_deps); - - while (all) { - char *nam = - xstrdup(bb_get_last_path_component_nostrip(all->name)); - char *tmp = strrstr(nam, ".ko"); - - *tmp = '\0'; - if (!strcmp(nam, shortname)) { - if (ENABLE_FEATURE_CLEAN_UP) - free(nam); - longname = all->name; - break; - } - free(nam); - all = all->next; - } - llist_add_to_end(&deps, longname); - } - mods->dependencies = deps; - mods = mods->next; - } - -#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY - /* modprobe allegedly wants dependencies without duplicates, i.e. - * mod1: mod2 mod3 - * mod2: mod3 - * mod3: - * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is - * already implicitely pulled in via mod2. This leaves us with: - * mod1: mod2 - * mod2: mod3 - * mod3: - */ - mods = G.lst; - while (mods) { - llist_t *deps = mods->dependencies; - while (deps) { - dep_lst_t *all = G.lst; - while (all) { - if (!strcmp(all->name, deps->data)) { - llist_t *implied = all->dependencies; - while (implied) { - /* XXX:FIXME: erm, it would be nicer to just - * llist_unlink(&mods->dependencies, implied) */ - llist_t *prune = mods->dependencies; - while (prune) { - if (!strcmp(implied->data, prune->data)) - break; - prune = prune->link; - } -//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data); - llist_unlink(&mods->dependencies, prune); - implied = implied->link; - } - } - all = all->next; - } - deps = deps->link; - } - mods = mods->next; - } -#endif - - mods = G.lst; - /* Finally print them. */ - while (mods) { - fprintf(filedes, "%s:", mods->name); - /* If we did not resolve all modules, then it's likely that we just did - * not see the names of all prerequisites (which will be NULL in this - * case). */ - while (mods->dependencies) { - char *the_dep = llist_pop(&mods->dependencies); - if (the_dep) - fprintf(filedes, " %s", the_dep); - } - fprintf(filedes, "\n"); - if (ENABLE_FEATURE_DEPMOD_ALIAS) - { - char *shortname = - xstrdup(bb_get_last_path_component_nostrip(mods->name)); - char *tmp = strrstr(shortname, ".ko"); - - *tmp = '\0'; - - while (mods->aliases) { - fprintf(filedes, "alias %s %s\n", - (char*)llist_pop(&mods->aliases), - shortname); - } - free(shortname); - } - mods = mods->next; - } - } - - if (ENABLE_FEATURE_CLEAN_UP) { - fclose_if_not_stdin(filedes); - free(moddir); - while (G.lst) { - dep_lst_t *old = G.lst; - G.lst = G.lst->next; - free(old->name); - free(old); - } - } - return ret; -} +/* vi: set sw=4 ts=4: */ +/* + * depmod - generate modules.dep + * Copyright (c) 2008 Bernhard Reutner-Fischer + * Copyrihgt (c) 2008 Timo Teras + * Copyright (c) 2008 Vladimir Dronnikov + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#undef _GNU_SOURCE +#define _GNU_SOURCE +#include +#include /* uname() */ +#include "modutils.h" + +/* + * Theory of operation: + * - iterate over all modules and record their full path + * - iterate over all modules looking for "depends=" entries + * for each depends, look through our list of full paths and emit if found + */ + +typedef struct module_info { + struct module_info *next; + char *name, *modname; + llist_t *dependencies; + llist_t *aliases; + llist_t *symbols; + struct module_info *dnext, *dprev; +} module_info; + +enum { + ARG_a = (1<<0), /* All modules, ignore mods in argv */ + ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */ + ARG_b = (1<<2), /* base directory when modules are in staging area */ + ARG_e = (1<<3), /* with -F, print unresolved symbols */ + ARG_F = (1<<4), /* System.map that contains the symbols */ + ARG_n = (1<<5), /* dry-run, print to stdout only */ + ARG_r = (1<<6) /* Compat dummy. Linux Makefile uses it */ +}; + +static int FAST_FUNC parse_module(const char *fname, struct stat *sb, + void *data, int UNUSED_PARAM depth) +{ + module_info **first = (module_info **) data; + char *image, *ptr; + module_info *info; + size_t len = sb->st_size; + + if (strrstr(fname, ".ko") == NULL) + return TRUE; + + image = xmalloc_open_zipped_read_close(fname, &len); + info = xzalloc(sizeof(module_info)); + + info->next = *first; + *first = info; + + info->dnext = info->dprev = info; + info->name = xasprintf("/%s", fname); + info->modname = filename2modname(fname, NULL); + for (ptr = image; ptr < image + len - 10; ptr++) { + if (strncmp(ptr, "depends=", 8) == 0) { + char *u; + + ptr += 8; + for (u = ptr; *u; u++) + if (*u == '-') + *u = '_'; + ptr += string_to_llist(ptr, &info->dependencies, ","); + } else if (ENABLE_FEATURE_MODUTILS_ALIAS && + strncmp(ptr, "alias=", 6) == 0) { + llist_add_to(&info->aliases, xstrdup(ptr + 6)); + ptr += strlen(ptr); + } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS && + strncmp(ptr, "__ksymtab_", 10) == 0) { + ptr += 10; + if (strncmp(ptr, "gpl", 3) == 0 || + strcmp(ptr, "strings") == 0) + continue; + llist_add_to(&info->symbols, xstrdup(ptr)); + ptr += strlen(ptr); + } + } + free(image); + + return TRUE; +} + +static module_info *find_module(module_info *modules, const char *modname) +{ + module_info *m; + + for (m = modules; m != NULL; m = m->next) + if (strcmp(m->modname, modname) == 0) + return m; + return NULL; +} + +static void order_dep_list(module_info *modules, module_info *start, + llist_t *add) +{ + module_info *m; + llist_t *n; + + for (n = add; n != NULL; n = n->link) { + m = find_module(modules, n->data); + if (m == NULL) + continue; + + /* unlink current entry */ + m->dnext->dprev = m->dprev; + m->dprev->dnext = m->dnext; + + /* and add it to tail */ + m->dnext = start; + m->dprev = start->dprev; + start->dprev->dnext = m; + start->dprev = m; + + /* recurse */ + order_dep_list(modules, start, m->dependencies); + } +} + +static void xfreopen_write(const char *file, FILE *f) +{ + if (freopen(file, "w", f) == NULL) + bb_perror_msg_and_die("can't open '%s'", file); +} + +int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int depmod_main(int argc UNUSED_PARAM, char **argv) +{ + module_info *modules = NULL, *m, *dep; + const char *moddir_base = "/"; + char *moddir, *version; + struct utsname uts; + int tmp; + + getopt32(argv, "aAb:eF:nr", &moddir_base, NULL); + argv += optind; + + /* goto modules location */ + xchdir(moddir_base); + + /* If a version is provided, then that kernel version's module directory + * is used, rather than the current kernel version (as returned by + * "uname -r"). */ + if (*argv && sscanf(*argv, "%d.%d.%d", &tmp, &tmp, &tmp) == 3) { + version = *argv++; + } else { + uname(&uts); + version = uts.release; + } + moddir = concat_path_file(&CONFIG_DEFAULT_MODULES_DIR[1], version); + + /* Scan modules */ + if (*argv) { + char *modfile; + struct stat sb; + do { + modfile = concat_path_file(moddir, *argv); + xstat(modfile, &sb); + parse_module(modfile, &sb, &modules, 0); + free(modfile); + } while (*(++argv)); + } else { + recursive_action(moddir, ACTION_RECURSE, + parse_module, NULL, &modules, 0); + } + + /* Prepare for writing out the dep files */ + xchdir(moddir); + if (ENABLE_FEATURE_CLEAN_UP) + free(moddir); + + /* Generate dependency and alias files */ + if (!(option_mask32 & ARG_n)) + xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout); + for (m = modules; m != NULL; m = m->next) { + printf("%s:", m->name); + + order_dep_list(modules, m, m->dependencies); + while (m->dnext != m) { + dep = m->dnext; + printf(" %s", dep->name); + + /* unlink current entry */ + dep->dnext->dprev = dep->dprev; + dep->dprev->dnext = dep->dnext; + dep->dnext = dep->dprev = dep; + } + bb_putchar('\n'); + } + +#if ENABLE_FEATURE_MODUTILS_ALIAS + if (!(option_mask32 & ARG_n)) + xfreopen_write("modules.alias", stdout); + for (m = modules; m != NULL; m = m->next) { + while (m->aliases) { + printf("alias %s %s\n", + (char*)llist_pop(&m->aliases), + m->modname); + } + } +#endif +#if ENABLE_FEATURE_MODUTILS_SYMBOLS + if (!(option_mask32 & ARG_n)) + xfreopen_write("modules.symbols", stdout); + for (m = modules; m != NULL; m = m->next) { + while (m->symbols) { + printf("alias symbol:%s %s\n", + (char*)llist_pop(&m->symbols), + m->modname); + } + } +#endif + + if (ENABLE_FEATURE_CLEAN_UP) { + while (modules) { + module_info *old = modules; + modules = modules->next; + free(old->name); + free(old->modname); + free(old); + } + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/modutils/insmod.c b/release/src/router/busybox/modutils/insmod.c dissimilarity index 99% index 80dbfd78ec..90ed87a72a 100644 --- a/release/src/router/busybox/modutils/insmod.c +++ b/release/src/router/busybox/modutils/insmod.c @@ -1,4287 +1,41 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini insmod implementation for busybox - * - * This version of insmod supports ARM, CRIS, H8/300, x86, ia64, x86_64, - * m68k, MIPS, PowerPC, S390, SH3/4/5, Sparc, v850e, and x86_64. - * - * Copyright (C) 1999-2004 by Erik Andersen - * and Ron Alder - * - * Rodney Radford 17-Aug-2004. - * Added x86_64 support. - * - * Miles Bader added NEC V850E support. - * - * Modified by Bryan Rittmeyer to support SH4 - * and (theoretically) SH3. I have only tested SH4 in little endian mode. - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support ARM7TDMI. Only - * very minor changes required to also work with StrongArm and presumably - * all ARM based systems. - * - * Yoshinori Sato 19-May-2004. - * added Renesas H8/300 support. - * - * Paul Mundt 08-Aug-2003. - * Integrated support for sh64 (SH-5), from preliminary modutils - * patches from Benedict Gaster . - * Currently limited to support for 32bit ABI. - * - * Magnus Damm 22-May-2002. - * The plt and got code are now using the same structs. - * Added generic linked list code to fully support PowerPC. - * Replaced the mess in arch_apply_relocation() with architecture blocks. - * The arch_create_got() function got cleaned up with architecture blocks. - * These blocks should be easy maintain and sync with obj_xxx.c in modutils. - * - * Magnus Damm added PowerPC support 20-Feb-2001. - * PowerPC specific code stolen from modutils-2.3.16, - * written by Paul Mackerras, Copyright 1996, 1997 Linux International. - * I've only tested the code on mpc8xx platforms in big-endian mode. - * Did some cleanup and added USE_xxx_ENTRIES... - * - * Quinn Jensen added MIPS support 23-Feb-2001. - * based on modutils-2.4.2 - * MIPS specific support for Elf loading and relocation. - * Copyright 1996, 1997 Linux International. - * Contributed by Ralf Baechle - * - * Based almost entirely on the Linux modutils-2.3.11 implementation. - * Copyright 1996, 1997 Linux International. - * New implementation contributed by Richard Henderson - * Based on original work by Bjorn Ekwall - * Restructured (and partly rewritten) by: - * Björn Ekwall February 1999 - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" -#include -#include - -#if !ENABLE_FEATURE_2_4_MODULES && !ENABLE_FEATURE_2_6_MODULES -#undef ENABLE_FEATURE_2_4_MODULES -#define ENABLE_FEATURE_2_4_MODULES 1 -#endif - -/* - * Big piece of 2.4-specific code - */ -#if ENABLE_FEATURE_2_4_MODULES - -#if ENABLE_FEATURE_2_6_MODULES -static int insmod_ng_main(int argc, char **argv); -#endif - -#if ENABLE_FEATURE_INSMOD_LOADINKMEM -#define LOADBITS 0 -#else -#define LOADBITS 1 -#endif - -/* Alpha */ -#if defined(__alpha__) -#define MATCH_MACHINE(x) (x == EM_ALPHA) -#define SHT_RELM SHT_RELA -#define Elf64_RelM Elf64_Rela -#define ELFCLASSM ELFCLASS64 -#endif - -/* ARM support */ -#if defined(__arm__) -#define MATCH_MACHINE(x) (x == EM_ARM) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFCLASSM ELFCLASS32 -#define USE_PLT_ENTRIES -#define PLT_ENTRY_SIZE 8 -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 8 -#define USE_SINGLE -#endif - -/* blackfin */ -#if defined(BFIN) -#define MATCH_MACHINE(x) (x == EM_BLACKFIN) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#endif - -/* CRIS */ -#if defined(__cris__) -#define MATCH_MACHINE(x) (x == EM_CRIS) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#ifndef EM_CRIS -#define EM_CRIS 76 -#define R_CRIS_NONE 0 -#define R_CRIS_32 3 -#endif -#endif - -/* H8/300 */ -#if defined(__H8300H__) || defined(__H8300S__) -#define MATCH_MACHINE(x) (x == EM_H8_300) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_SINGLE -#define SYMBOL_PREFIX "_" -#endif - -/* PA-RISC / HP-PA */ -#if defined(__hppa__) -#define MATCH_MACHINE(x) (x == EM_PARISC) -#define SHT_RELM SHT_RELA -#if defined(__LP64__) -#define Elf64_RelM Elf64_Rela -#define ELFCLASSM ELFCLASS64 -#else -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#endif -#endif - -/* x86 */ -#if defined(__i386__) -#ifndef EM_486 -#define MATCH_MACHINE(x) (x == EM_386) -#else -#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) -#endif -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFCLASSM ELFCLASS32 -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 4 -#define USE_SINGLE -#endif - -/* IA64, aka Itanium */ -#if defined(__ia64__) -#define MATCH_MACHINE(x) (x == EM_IA_64) -#define SHT_RELM SHT_RELA -#define Elf64_RelM Elf64_Rela -#define ELFCLASSM ELFCLASS64 -#endif - -/* m68k */ -#if defined(__mc68000__) -#define MATCH_MACHINE(x) (x == EM_68K) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 4 -#define USE_SINGLE -#endif - -/* Microblaze */ -#if defined(__microblaze__) -#define USE_SINGLE -#include -#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#endif - -/* MIPS */ -#if defined(__mips__) -#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFCLASSM ELFCLASS32 -/* Account for ELF spec changes. */ -#ifndef EM_MIPS_RS3_LE -#ifdef EM_MIPS_RS4_BE -#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE -#else -#define EM_MIPS_RS3_LE 10 -#endif -#endif /* !EM_MIPS_RS3_LE */ -#define ARCHDATAM "__dbe_table" -#endif - -/* Nios II */ -#if defined(__nios2__) -#define MATCH_MACHINE(x) (x == EM_ALTERA_NIOS2) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#endif - -/* PowerPC */ -#if defined(__powerpc64__) -#define MATCH_MACHINE(x) (x == EM_PPC64) -#define SHT_RELM SHT_RELA -#define Elf64_RelM Elf64_Rela -#define ELFCLASSM ELFCLASS64 -#elif defined(__powerpc__) -#define MATCH_MACHINE(x) (x == EM_PPC) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_PLT_ENTRIES -#define PLT_ENTRY_SIZE 16 -#define USE_PLT_LIST -#define LIST_ARCHTYPE ElfW(Addr) -#define USE_LIST -#define ARCHDATAM "__ftr_fixup" -#endif - -/* S390 */ -#if defined(__s390__) -#define MATCH_MACHINE(x) (x == EM_S390) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_PLT_ENTRIES -#define PLT_ENTRY_SIZE 8 -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 8 -#define USE_SINGLE -#endif - -/* SuperH */ -#if defined(__sh__) -#define MATCH_MACHINE(x) (x == EM_SH) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 4 -#define USE_SINGLE -/* the SH changes have only been tested in =little endian= mode */ -/* I'm not sure about big endian, so let's warn: */ -#if defined(__sh__) && BB_BIG_ENDIAN -# error insmod.c may require changes for use on big endian SH -#endif -/* it may or may not work on the SH1/SH2... Error on those also */ -#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && (defined(__sh__)) -#error insmod.c may require changes for SH1 or SH2 use -#endif -#endif - -/* Sparc */ -#if defined(__sparc__) -#define MATCH_MACHINE(x) (x == EM_SPARC) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#endif - -/* v850e */ -#if defined(__v850e__) -#define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFCLASSM ELFCLASS32 -#define USE_PLT_ENTRIES -#define PLT_ENTRY_SIZE 8 -#define USE_SINGLE -#ifndef EM_CYGNUS_V850 /* grumble */ -#define EM_CYGNUS_V850 0x9080 -#endif -#define SYMBOL_PREFIX "_" -#endif - -/* X86_64 */ -#if defined(__x86_64__) -#define MATCH_MACHINE(x) (x == EM_X86_64) -#define SHT_RELM SHT_RELA -#define USE_GOT_ENTRIES -#define GOT_ENTRY_SIZE 8 -#define USE_SINGLE -#define Elf64_RelM Elf64_Rela -#define ELFCLASSM ELFCLASS64 -#endif - -#ifndef SHT_RELM -#error Sorry, but insmod.c does not yet support this architecture... -#endif - - -//---------------------------------------------------------------------------- -//--------modutils module.h, lines 45-242 -//---------------------------------------------------------------------------- - -/* Definitions for the Linux module syscall interface. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#ifndef MODUTILS_MODULE_H - -/*======================================================================*/ -/* For sizeof() which are related to the module platform and not to the - environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ - -#define tgt_sizeof_char sizeof(char) -#define tgt_sizeof_short sizeof(short) -#define tgt_sizeof_int sizeof(int) -#define tgt_sizeof_long sizeof(long) -#define tgt_sizeof_char_p sizeof(char *) -#define tgt_sizeof_void_p sizeof(void *) -#define tgt_long long - -#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) -#undef tgt_sizeof_long -#undef tgt_sizeof_char_p -#undef tgt_sizeof_void_p -#undef tgt_long -enum { - tgt_sizeof_long = 8, - tgt_sizeof_char_p = 8, - tgt_sizeof_void_p = 8 -}; -#define tgt_long long long -#endif - -/*======================================================================*/ -/* The structures used in Linux 2.1. */ - -/* Note: new_module_symbol does not use tgt_long intentionally */ -struct new_module_symbol { - unsigned long value; - unsigned long name; -}; - -struct new_module_persist; - -struct new_module_ref { - unsigned tgt_long dep; /* kernel addresses */ - unsigned tgt_long ref; - unsigned tgt_long next_ref; -}; - -struct new_module { - unsigned tgt_long size_of_struct; /* == sizeof(module) */ - unsigned tgt_long next; - unsigned tgt_long name; - unsigned tgt_long size; - - tgt_long usecount; - unsigned tgt_long flags; /* AUTOCLEAN et al */ - - unsigned nsyms; - unsigned ndeps; - - unsigned tgt_long syms; - unsigned tgt_long deps; - unsigned tgt_long refs; - unsigned tgt_long init; - unsigned tgt_long cleanup; - unsigned tgt_long ex_table_start; - unsigned tgt_long ex_table_end; -#ifdef __alpha__ - unsigned tgt_long gp; -#endif - /* Everything after here is extension. */ - unsigned tgt_long persist_start; - unsigned tgt_long persist_end; - unsigned tgt_long can_unload; - unsigned tgt_long runsize; - const char *kallsyms_start; /* All symbols for kernel debugging */ - const char *kallsyms_end; - const char *archdata_start; /* arch specific data for module */ - const char *archdata_end; - const char *kernel_data; /* Reserved for kernel internal use */ -}; - -#ifdef ARCHDATAM -#define ARCHDATA_SEC_NAME ARCHDATAM -#else -#define ARCHDATA_SEC_NAME "__archdata" -#endif -#define KALLSYMS_SEC_NAME "__kallsyms" - - -struct new_module_info { - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - -/* Bits of module.flags. */ -enum { - NEW_MOD_RUNNING = 1, - NEW_MOD_DELETED = 2, - NEW_MOD_AUTOCLEAN = 4, - NEW_MOD_VISITED = 8, - NEW_MOD_USED_ONCE = 16 -}; - -int init_module(const char *name, const struct new_module *); -int query_module(const char *name, int which, void *buf, - size_t bufsize, size_t *ret); - -/* Values for query_module's which. */ -enum { - QM_MODULES = 1, - QM_DEPS = 2, - QM_REFS = 3, - QM_SYMBOLS = 4, - QM_INFO = 5 -}; - -/*======================================================================*/ -/* The system calls unchanged between 2.0 and 2.1. */ - -unsigned long create_module(const char *, size_t); -int delete_module(const char *module, unsigned int flags); - - -#endif /* module.h */ - -//---------------------------------------------------------------------------- -//--------end of modutils module.h -//---------------------------------------------------------------------------- - - - -//---------------------------------------------------------------------------- -//--------modutils obj.h, lines 253-462 -//---------------------------------------------------------------------------- - -/* Elf object file loading and relocation routines. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#ifndef MODUTILS_OBJ_H - -/* The relocatable object is manipulated using elfin types. */ - -#include -#include - -#ifndef ElfW -# if ELFCLASSM == ELFCLASS32 -# define ElfW(x) Elf32_ ## x -# define ELFW(x) ELF32_ ## x -# else -# define ElfW(x) Elf64_ ## x -# define ELFW(x) ELF64_ ## x -# endif -#endif - -/* For some reason this is missing from some ancient C libraries.... */ -#ifndef ELF32_ST_INFO -# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -#ifndef ELF64_ST_INFO -# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -#define ELF_ST_BIND(info) ELFW(ST_BIND)(info) -#define ELF_ST_TYPE(info) ELFW(ST_TYPE)(info) -#define ELF_ST_INFO(bind, type) ELFW(ST_INFO)(bind, type) -#define ELF_R_TYPE(val) ELFW(R_TYPE)(val) -#define ELF_R_SYM(val) ELFW(R_SYM)(val) - -struct obj_string_patch; -struct obj_symbol_patch; - -struct obj_section -{ - ElfW(Shdr) header; - const char *name; - char *contents; - struct obj_section *load_next; - int idx; -}; - -struct obj_symbol -{ - struct obj_symbol *next; /* hash table link */ - const char *name; - unsigned long value; - unsigned long size; - int secidx; /* the defining section index/module */ - int info; - int ksymidx; /* for export to the kernel symtab */ - int referenced; /* actually used in the link */ -}; - -/* Hardcode the hash table size. We shouldn't be needing so many - symbols that we begin to degrade performance, and we get a big win - by giving the compiler a constant divisor. */ - -#define HASH_BUCKETS 521 - -struct obj_file { - ElfW(Ehdr) header; - ElfW(Addr) baseaddr; - struct obj_section **sections; - struct obj_section *load_order; - struct obj_section **load_order_search_start; - struct obj_string_patch *string_patches; - struct obj_symbol_patch *symbol_patches; - int (*symbol_cmp)(const char *, const char *); - unsigned long (*symbol_hash)(const char *); - unsigned long local_symtab_size; - struct obj_symbol **local_symtab; - struct obj_symbol *symtab[HASH_BUCKETS]; -}; - -enum obj_reloc { - obj_reloc_ok, - obj_reloc_overflow, - obj_reloc_dangerous, - obj_reloc_unhandled -}; - -struct obj_string_patch { - struct obj_string_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - ElfW(Addr) string_offset; -}; - -struct obj_symbol_patch { - struct obj_symbol_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - struct obj_symbol *sym; -}; - - -/* Generic object manipulation routines. */ - -static unsigned long obj_elf_hash(const char *); - -static unsigned long obj_elf_hash_n(const char *, unsigned long len); - -static struct obj_symbol *obj_find_symbol(struct obj_file *f, - const char *name); - -static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, - struct obj_symbol *sym); - -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING -static void obj_set_symbol_compare(struct obj_file *f, - int (*cmp)(const char *, const char *), - unsigned long (*hash)(const char *)); -#endif - -static struct obj_section *obj_find_section(struct obj_file *f, - const char *name); - -static void obj_insert_section_load_order(struct obj_file *f, - struct obj_section *sec); - -static struct obj_section *obj_create_alloced_section(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static void *obj_extend_section(struct obj_section *sec, unsigned long more); - -static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string); - -static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym); - -static void obj_check_undefineds(struct obj_file *f); - -static void obj_allocate_commons(struct obj_file *f); - -static unsigned long obj_load_size(struct obj_file *f); - -static int obj_relocate(struct obj_file *f, ElfW(Addr) base); - -static struct obj_file *obj_load(FILE *f, int loadprogbits); - -static int obj_create_image(struct obj_file *f, char *image); - -/* Architecture specific manipulation routines. */ - -static struct obj_file *arch_new_file(void); - -static struct obj_section *arch_new_section(void); - -static struct obj_symbol *arch_new_symbol(void); - -static enum obj_reloc arch_apply_relocation(struct obj_file *f, - struct obj_section *targsec, - /*struct obj_section *symsec,*/ - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) value); - -static void arch_create_got(struct obj_file *f); -#if ENABLE_FEATURE_CHECK_TAINTED_MODULE -static int obj_gpl_license(struct obj_file *f, const char **license); -#endif /* FEATURE_CHECK_TAINTED_MODULE */ -#endif /* obj.h */ -//---------------------------------------------------------------------------- -//--------end of modutils obj.h -//---------------------------------------------------------------------------- - - -/* SPFX is always a string, so it can be concatenated to string constants. */ -#ifdef SYMBOL_PREFIX -#define SPFX SYMBOL_PREFIX -#else -#define SPFX "" -#endif - -enum { STRVERSIONLEN = 64 }; - -/*======================================================================*/ - -#define OPTION_STR "sLo:fkvqx" USE_FEATURE_INSMOD_LOAD_MAP("m") -enum { - OPT_s = 0x1, // -s /* log to syslog */ - /* Not supported but kernel needs this for request_module(), - as this calls: modprobe -k -s -- - so silently ignore this flag */ - OPT_L = 0x2, // -L /* Stub warning */ - /* Compatibility with modprobe. - In theory, this does locking, but we don't do - that. So be careful and plan your life around not - loading the same module 50 times concurrently. */ - OPT_o = 0x4, // -o /* name the output module */ - OPT_f = 0x8, // -f /* force loading */ - OPT_k = 0x10, // -k /* module loaded by kerneld, auto-cleanable */ - OPT_v = 0x20, // -v /* verbose output */ - OPT_q = 0x40, // -q /* silent */ - OPT_x = 0x80, // -x /* do not export externs */ - OPT_m = 0x100, // -m /* print module load map */ -}; -#define flag_force_load (option_mask32 & OPT_f) -#define flag_autoclean (option_mask32 & OPT_k) -#define flag_verbose (option_mask32 & OPT_v) -#define flag_quiet (option_mask32 & OPT_q) -#define flag_noexport (option_mask32 & OPT_x) -#if ENABLE_FEATURE_INSMOD_LOAD_MAP -#define flag_print_load_map (option_mask32 & OPT_m) -#else -#define flag_print_load_map 0 -#endif - -/*======================================================================*/ - -#if defined(USE_LIST) - -struct arch_list_entry -{ - struct arch_list_entry *next; - LIST_ARCHTYPE addend; - int offset; - int inited : 1; -}; - -#endif - -#if defined(USE_SINGLE) - -struct arch_single_entry -{ - int offset; - int inited : 1; - int allocated : 1; -}; - -#endif - -#if defined(__mips__) -struct mips_hi16 -{ - struct mips_hi16 *next; - ElfW(Addr) *addr; - ElfW(Addr) value; -}; -#endif - -struct arch_file { - struct obj_file root; -#if defined(USE_PLT_ENTRIES) - struct obj_section *plt; -#endif -#if defined(USE_GOT_ENTRIES) - struct obj_section *got; -#endif -#if defined(__mips__) - struct mips_hi16 *mips_hi16_list; -#endif -}; - -struct arch_symbol { - struct obj_symbol root; -#if defined(USE_PLT_ENTRIES) -#if defined(USE_PLT_LIST) - struct arch_list_entry *pltent; -#else - struct arch_single_entry pltent; -#endif -#endif -#if defined(USE_GOT_ENTRIES) - struct arch_single_entry gotent; -#endif -}; - - -struct external_module { - const char *name; - ElfW(Addr) addr; - int used; - size_t nsyms; - struct new_module_symbol *syms; -}; - -static struct new_module_symbol *ksyms; -static size_t nksyms; - -static struct external_module *ext_modules; -static int n_ext_modules; -static int n_ext_modules_used; - -static char *m_filename; -static char *m_fullName; - - -/*======================================================================*/ - - -static int FAST_FUNC check_module_name_match(const char *filename, - struct stat *statbuf UNUSED_PARAM, - void *userdata, int depth UNUSED_PARAM) -{ - char *fullname = (char *) userdata; - char *tmp; - - if (fullname[0] == '\0') - return FALSE; - - tmp = bb_get_last_path_component_nostrip(filename); - if (strcmp(tmp, fullname) == 0) { - /* Stop searching if we find a match */ - m_filename = xstrdup(filename); - return FALSE; - } - return TRUE; -} - - -/*======================================================================*/ - -static struct obj_file *arch_new_file(void) -{ - struct arch_file *f; - f = xzalloc(sizeof(*f)); - return &f->root; /* it's a first member */ -} - -static struct obj_section *arch_new_section(void) -{ - return xzalloc(sizeof(struct obj_section)); -} - -static struct obj_symbol *arch_new_symbol(void) -{ - struct arch_symbol *sym; - sym = xzalloc(sizeof(*sym)); - return &sym->root; -} - -static enum obj_reloc -arch_apply_relocation(struct obj_file *f, - struct obj_section *targsec, - /*struct obj_section *symsec,*/ - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) v) -{ -#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \ - || defined(__sh__) || defined(__s390__) || defined(__x86_64__) \ - || defined(__powerpc__) || defined(__mips__) - struct arch_file *ifile = (struct arch_file *) f; -#endif - enum obj_reloc ret = obj_reloc_ok; - ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); -#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \ - || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \ - || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \ - || defined(__s390__) || defined(__sh__) || defined(__x86_64__) - ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; -#endif -#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) - struct arch_symbol *isym = (struct arch_symbol *) sym; -#endif -#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \ - || defined(__sh__) || defined(__s390__) -#if defined(USE_GOT_ENTRIES) - ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; -#endif -#endif -#if defined(USE_PLT_ENTRIES) - ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; - unsigned long *ip; -# if defined(USE_PLT_LIST) - struct arch_list_entry *pe; -# else - struct arch_single_entry *pe; -# endif -#endif - - switch (ELF_R_TYPE(rel->r_info)) { - -#if defined(__arm__) - - case R_ARM_NONE: - break; - - case R_ARM_ABS32: - *loc += v; - break; - - case R_ARM_GOT32: - goto bb_use_got; - - case R_ARM_GOTPC: - /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ - * (which is .got) similar to branch, - * but is full 32 bits relative */ - - *loc += got - dot; - break; - - case R_ARM_PC24: - case R_ARM_PLT32: - goto bb_use_plt; - - case R_ARM_GOTOFF: /* address relative to the got */ - *loc += v - got; - break; - -#elif defined(__cris__) - - case R_CRIS_NONE: - break; - - case R_CRIS_32: - /* CRIS keeps the relocation value in the r_addend field and - * should not use whats in *loc at all - */ - *loc = v; - break; - -#elif defined(__H8300H__) || defined(__H8300S__) - - case R_H8_DIR24R8: - loc = (ElfW(Addr) *)((ElfW(Addr))loc - 1); - *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v); - break; - case R_H8_DIR24A8: - *loc += v; - break; - case R_H8_DIR32: - case R_H8_DIR32A16: - *loc += v; - break; - case R_H8_PCREL16: - v -= dot + 2; - if ((ElfW(Sword))v > 0x7fff || - (ElfW(Sword))v < -(ElfW(Sword))0x8000) - ret = obj_reloc_overflow; - else - *(unsigned short *)loc = v; - break; - case R_H8_PCREL8: - v -= dot + 1; - if ((ElfW(Sword))v > 0x7f || - (ElfW(Sword))v < -(ElfW(Sword))0x80) - ret = obj_reloc_overflow; - else - *(unsigned char *)loc = v; - break; - -#elif defined(__i386__) - - case R_386_NONE: - break; - - case R_386_32: - *loc += v; - break; - - case R_386_PLT32: - case R_386_PC32: - case R_386_GOTOFF: - *loc += v - dot; - break; - - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - *loc = v; - break; - - case R_386_RELATIVE: - *loc += f->baseaddr; - break; - - case R_386_GOTPC: - *loc += got - dot; - break; - - case R_386_GOT32: - goto bb_use_got; - break; - -#elif defined(__microblaze__) - case R_MICROBLAZE_NONE: - case R_MICROBLAZE_64_NONE: - case R_MICROBLAZE_32_SYM_OP_SYM: - case R_MICROBLAZE_32_PCREL: - break; - - case R_MICROBLAZE_64_PCREL: { - /* dot is the address of the current instruction. - * v is the target symbol address. - * So we need to extract the offset in the code, - * adding v, then subtrating the current address - * of this instruction. - * Ex: "IMM 0xFFFE bralid 0x0000" = "bralid 0xFFFE0000" - */ - - /* Get split offset stored in code */ - unsigned int temp = (loc[0] & 0xFFFF) << 16 | - (loc[1] & 0xFFFF); - - /* Adjust relative offset. -4 adjustment required - * because dot points to the IMM insn, but branch - * is computed relative to the branch instruction itself. - */ - temp += v - dot - 4; - - /* Store back into code */ - loc[0] = (loc[0] & 0xFFFF0000) | temp >> 16; - loc[1] = (loc[1] & 0xFFFF0000) | (temp & 0xFFFF); - - break; - } - - case R_MICROBLAZE_32: - *loc += v; - break; - - case R_MICROBLAZE_64: { - /* Get split pointer stored in code */ - unsigned int temp1 = (loc[0] & 0xFFFF) << 16 | - (loc[1] & 0xFFFF); - - /* Add reloc offset */ - temp1+=v; - - /* Store back into code */ - loc[0] = (loc[0] & 0xFFFF0000) | temp1 >> 16; - loc[1] = (loc[1] & 0xFFFF0000) | (temp1 & 0xFFFF); - - break; - } - - case R_MICROBLAZE_32_PCREL_LO: - case R_MICROBLAZE_32_LO: - case R_MICROBLAZE_SRO32: - case R_MICROBLAZE_SRW32: - ret = obj_reloc_unhandled; - break; - -#elif defined(__mc68000__) - - case R_68K_NONE: - break; - - case R_68K_32: - *loc += v; - break; - - case R_68K_8: - if (v > 0xff) { - ret = obj_reloc_overflow; - } - *(char *)loc = v; - break; - - case R_68K_16: - if (v > 0xffff) { - ret = obj_reloc_overflow; - } - *(short *)loc = v; - break; - - case R_68K_PC8: - v -= dot; - if ((ElfW(Sword))v > 0x7f - || (ElfW(Sword))v < -(ElfW(Sword))0x80 - ) { - ret = obj_reloc_overflow; - } - *(char *)loc = v; - break; - - case R_68K_PC16: - v -= dot; - if ((ElfW(Sword))v > 0x7fff - || (ElfW(Sword))v < -(ElfW(Sword))0x8000 - ) { - ret = obj_reloc_overflow; - } - *(short *)loc = v; - break; - - case R_68K_PC32: - *(int *)loc = v - dot; - break; - - case R_68K_GLOB_DAT: - case R_68K_JMP_SLOT: - *loc = v; - break; - - case R_68K_RELATIVE: - *(int *)loc += f->baseaddr; - break; - - case R_68K_GOT32: - goto bb_use_got; - -# ifdef R_68K_GOTOFF - case R_68K_GOTOFF: - *loc += v - got; - break; -# endif - -#elif defined(__mips__) - - case R_MIPS_NONE: - break; - - case R_MIPS_32: - *loc += v; - break; - - case R_MIPS_26: - if (v % 4) - ret = obj_reloc_dangerous; - if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) - ret = obj_reloc_overflow; - *loc = - (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & - 0x03ffffff); - break; - - case R_MIPS_HI16: - { - struct mips_hi16 *n; - - /* We cannot relocate this one now because we don't know the value - of the carry we need to add. Save the information, and let LO16 - do the actual relocation. */ - n = xmalloc(sizeof *n); - n->addr = loc; - n->value = v; - n->next = ifile->mips_hi16_list; - ifile->mips_hi16_list = n; - break; - } - - case R_MIPS_LO16: - { - unsigned long insnlo = *loc; - ElfW(Addr) val, vallo; - - /* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - - if (ifile->mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = ifile->mips_hi16_list; - while (l != NULL) { - struct mips_hi16 *next; - unsigned long insn; - - /* Do the HI16 relocation. Note that we actually don't - need to know anything about the LO16 itself, except where - to find the low 16 bits of the addend needed by the LO16. */ - insn = *l->addr; - val = - ((insn & 0xffff) << 16) + - vallo; - val += v; - - /* Account for the sign extension that will happen in the - low bits. */ - val = - ((val >> 16) + - ((val & 0x8000) != - 0)) & 0xffff; - - insn = (insn & ~0xffff) | val; - *l->addr = insn; - - next = l->next; - free(l); - l = next; - } - - ifile->mips_hi16_list = NULL; - } - - /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ - val = v + vallo; - insnlo = (insnlo & ~0xffff) | (val & 0xffff); - *loc = insnlo; - break; - } - -#elif defined(__nios2__) - - case R_NIOS2_NONE: - break; - - case R_NIOS2_BFD_RELOC_32: - *loc += v; - break; - - case R_NIOS2_BFD_RELOC_16: - if (v > 0xffff) { - ret = obj_reloc_overflow; - } - *(short *)loc = v; - break; - - case R_NIOS2_BFD_RELOC_8: - if (v > 0xff) { - ret = obj_reloc_overflow; - } - *(char *)loc = v; - break; - - case R_NIOS2_S16: - { - Elf32_Addr word; - - if ((Elf32_Sword)v > 0x7fff - || (Elf32_Sword)v < -(Elf32_Sword)0x8000 - ) { - ret = obj_reloc_overflow; - } - - word = *loc; - *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | - (word & 0x3f); - } - break; - - case R_NIOS2_U16: - { - Elf32_Addr word; - - if (v > 0xffff) { - ret = obj_reloc_overflow; - } - - word = *loc; - *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | - (word & 0x3f); - } - break; - - case R_NIOS2_PCREL16: - { - Elf32_Addr word; - - v -= dot + 4; - if ((Elf32_Sword)v > 0x7fff - || (Elf32_Sword)v < -(Elf32_Sword)0x8000 - ) { - ret = obj_reloc_overflow; - } - - word = *loc; - *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); - } - break; - - case R_NIOS2_GPREL: - { - Elf32_Addr word, gp; - /* get _gp */ - gp = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "_gp")); - v -= gp; - if ((Elf32_Sword)v > 0x7fff - || (Elf32_Sword)v < -(Elf32_Sword)0x8000 - ) { - ret = obj_reloc_overflow; - } - - word = *loc; - *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); - } - break; - - case R_NIOS2_CALL26: - if (v & 3) - ret = obj_reloc_dangerous; - if ((v >> 28) != (dot >> 28)) - ret = obj_reloc_overflow; - *loc = (*loc & 0x3f) | ((v >> 2) << 6); - break; - - case R_NIOS2_IMM5: - { - Elf32_Addr word; - - if (v > 0x1f) { - ret = obj_reloc_overflow; - } - - word = *loc & ~0x7c0; - *loc = word | ((v & 0x1f) << 6); - } - break; - - case R_NIOS2_IMM6: - { - Elf32_Addr word; - - if (v > 0x3f) { - ret = obj_reloc_overflow; - } - - word = *loc & ~0xfc0; - *loc = word | ((v & 0x3f) << 6); - } - break; - - case R_NIOS2_IMM8: - { - Elf32_Addr word; - - if (v > 0xff) { - ret = obj_reloc_overflow; - } - - word = *loc & ~0x3fc0; - *loc = word | ((v & 0xff) << 6); - } - break; - - case R_NIOS2_HI16: - { - Elf32_Addr word; - - word = *loc; - *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) | - (word & 0x3f); - } - break; - - case R_NIOS2_LO16: - { - Elf32_Addr word; - - word = *loc; - *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | - (word & 0x3f); - } - break; - - case R_NIOS2_HIADJ16: - { - Elf32_Addr word1, word2; - - word1 = *loc; - word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; - *loc = ((((word1 >> 22) << 16) | word2) << 6) | - (word1 & 0x3f); - } - break; - -#elif defined(__powerpc64__) - /* PPC64 needs a 2.6 kernel, 2.4 module relocation irrelevant */ - -#elif defined(__powerpc__) - - case R_PPC_ADDR16_HA: - *(unsigned short *)loc = (v + 0x8000) >> 16; - break; - - case R_PPC_ADDR16_HI: - *(unsigned short *)loc = v >> 16; - break; - - case R_PPC_ADDR16_LO: - *(unsigned short *)loc = v; - break; - - case R_PPC_REL24: - goto bb_use_plt; - - case R_PPC_REL32: - *loc = v - dot; - break; - - case R_PPC_ADDR32: - *loc = v; - break; - -#elif defined(__s390__) - - case R_390_32: - *(unsigned int *) loc += v; - break; - case R_390_16: - *(unsigned short *) loc += v; - break; - case R_390_8: - *(unsigned char *) loc += v; - break; - - case R_390_PC32: - *(unsigned int *) loc += v - dot; - break; - case R_390_PC16DBL: - *(unsigned short *) loc += (v - dot) >> 1; - break; - case R_390_PC16: - *(unsigned short *) loc += v - dot; - break; - - case R_390_PLT32: - case R_390_PLT16DBL: - /* find the plt entry and initialize it. */ - pe = (struct arch_single_entry *) &isym->pltent; - if (pe->inited == 0) { - ip = (unsigned long *)(ifile->plt->contents + pe->offset); - ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */ - ip[1] = 0x100607f1; - if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL) - ip[2] = v - 2; - else - ip[2] = v; - pe->inited = 1; - } - - /* Insert relative distance to target. */ - v = plt + pe->offset - dot; - if (ELF_R_TYPE(rel->r_info) == R_390_PLT32) - *(unsigned int *) loc = (unsigned int) v; - else if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL) - *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1); - break; - - case R_390_GLOB_DAT: - case R_390_JMP_SLOT: - *loc = v; - break; - - case R_390_RELATIVE: - *loc += f->baseaddr; - break; - - case R_390_GOTPC: - *(unsigned long *) loc += got - dot; - break; - - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT32: - if (!isym->gotent.inited) - { - isym->gotent.inited = 1; - *(ElfW(Addr) *)(ifile->got->contents + isym->gotent.offset) = v; - } - if (ELF_R_TYPE(rel->r_info) == R_390_GOT12) - *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff; - else if (ELF_R_TYPE(rel->r_info) == R_390_GOT16) - *(unsigned short *) loc += isym->gotent.offset; - else if (ELF_R_TYPE(rel->r_info) == R_390_GOT32) - *(unsigned int *) loc += isym->gotent.offset; - break; - -# ifndef R_390_GOTOFF32 -# define R_390_GOTOFF32 R_390_GOTOFF -# endif - case R_390_GOTOFF32: - *loc += v - got; - break; - -#elif defined(__sh__) - - case R_SH_NONE: - break; - - case R_SH_DIR32: - *loc += v; - break; - - case R_SH_REL32: - *loc += v - dot; - break; - - case R_SH_PLT32: - *loc = v - dot; - break; - - case R_SH_GLOB_DAT: - case R_SH_JMP_SLOT: - *loc = v; - break; - - case R_SH_RELATIVE: - *loc = f->baseaddr + rel->r_addend; - break; - - case R_SH_GOTPC: - *loc = got - dot + rel->r_addend; - break; - - case R_SH_GOT32: - goto bb_use_got; - - case R_SH_GOTOFF: - *loc = v - got; - break; - -# if defined(__SH5__) - case R_SH_IMM_MEDLOW16: - case R_SH_IMM_LOW16: - { - ElfW(Addr) word; - - if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16) - v >>= 16; - - /* - * movi and shori have the format: - * - * | op | imm | reg | reserved | - * 31..26 25..10 9.. 4 3 .. 0 - * - * so we simply mask and or in imm. - */ - word = *loc & ~0x3fffc00; - word |= (v & 0xffff) << 10; - - *loc = word; - - break; - } - - case R_SH_IMM_MEDLOW16_PCREL: - case R_SH_IMM_LOW16_PCREL: - { - ElfW(Addr) word; - - word = *loc & ~0x3fffc00; - - v -= dot; - - if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL) - v >>= 16; - - word |= (v & 0xffff) << 10; - - *loc = word; - - break; - } -# endif /* __SH5__ */ - -#elif defined(__v850e__) - - case R_V850_NONE: - break; - - case R_V850_32: - /* We write two shorts instead of a long because even - 32-bit insns only need half-word alignment, but - 32-bit data needs to be long-word aligned. */ - v += ((unsigned short *)loc)[0]; - v += ((unsigned short *)loc)[1] << 16; - ((unsigned short *)loc)[0] = v & 0xffff; - ((unsigned short *)loc)[1] = (v >> 16) & 0xffff; - break; - - case R_V850_22_PCREL: - goto bb_use_plt; - -#elif defined(__x86_64__) - - case R_X86_64_NONE: - break; - - case R_X86_64_64: - *loc += v; - break; - - case R_X86_64_32: - *(unsigned int *) loc += v; - if (v > 0xffffffff) - { - ret = obj_reloc_overflow; /* Kernel module compiled without -mcmodel=kernel. */ - /* error("Possibly is module compiled without -mcmodel=kernel!"); */ - } - break; - - case R_X86_64_32S: - *(signed int *) loc += v; - break; - - case R_X86_64_16: - *(unsigned short *) loc += v; - break; - - case R_X86_64_8: - *(unsigned char *) loc += v; - break; - - case R_X86_64_PC32: - *(unsigned int *) loc += v - dot; - break; - - case R_X86_64_PC16: - *(unsigned short *) loc += v - dot; - break; - - case R_X86_64_PC8: - *(unsigned char *) loc += v - dot; - break; - - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: - *loc = v; - break; - - case R_X86_64_RELATIVE: - *loc += f->baseaddr; - break; - - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - goto bb_use_got; -# if 0 - if (!isym->gotent.reloc_done) - { - isym->gotent.reloc_done = 1; - *(Elf64_Addr *)(ifile->got->contents + isym->gotent.offset) = v; - } - /* XXX are these really correct? */ - if (ELF64_R_TYPE(rel->r_info) == R_X86_64_GOTPCREL) - *(unsigned int *) loc += v + isym->gotent.offset; - else - *loc += isym->gotent.offset; - break; -# endif - -#else -# warning "no idea how to handle relocations on your arch" -#endif - - default: - printf("Warning: unhandled reloc %d\n",(int)ELF_R_TYPE(rel->r_info)); - ret = obj_reloc_unhandled; - break; - -#if defined(USE_PLT_ENTRIES) - -bb_use_plt: - - /* find the plt entry and initialize it if necessary */ - -#if defined(USE_PLT_LIST) - for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;) - pe = pe->next; -#else - pe = &isym->pltent; -#endif - - if (! pe->inited) { - ip = (unsigned long *) (ifile->plt->contents + pe->offset); - - /* generate some machine code */ - -#if defined(__arm__) - ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ - ip[1] = v; /* sym@ */ -#endif -#if defined(__powerpc__) - ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */ - ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */ - ip[2] = 0x7d6903a6; /* mtctr r11 */ - ip[3] = 0x4e800420; /* bctr */ -#endif -#if defined(__v850e__) - /* We have to trash a register, so we assume that any control - transfer more than 21-bits away must be a function call - (so we can use a call-clobbered register). */ - ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */ - ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */ -#endif - pe->inited = 1; - } - - /* relative distance to target */ - v -= dot; - /* if the target is too far away.... */ -#if defined(__arm__) || defined(__powerpc__) - if ((int)v < -0x02000000 || (int)v >= 0x02000000) -#elif defined(__v850e__) - if ((ElfW(Sword))v > 0x1fffff || (ElfW(Sword))v < (ElfW(Sword))-0x200000) -#endif - /* go via the plt */ - v = plt + pe->offset - dot; - -#if defined(__v850e__) - if (v & 1) -#else - if (v & 3) -#endif - ret = obj_reloc_dangerous; - - /* merge the offset into the instruction. */ -#if defined(__arm__) - /* Convert to words. */ - v >>= 2; - - *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); -#endif -#if defined(__powerpc__) - *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); -#endif -#if defined(__v850e__) - /* We write two shorts instead of a long because even 32-bit insns - only need half-word alignment, but the 32-bit data write needs - to be long-word aligned. */ - ((unsigned short *)loc)[0] = - (*(unsigned short *)loc & 0xffc0) /* opcode + reg */ - | ((v >> 16) & 0x3f); /* offs high part */ - ((unsigned short *)loc)[1] = - (v & 0xffff); /* offs low part */ -#endif - break; -#endif /* USE_PLT_ENTRIES */ - -#if defined(USE_GOT_ENTRIES) -bb_use_got: - - /* needs an entry in the .got: set it, once */ - if (!isym->gotent.inited) { - isym->gotent.inited = 1; - *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; - } - /* make the reloc with_respect_to_.got */ -#if defined(__sh__) - *loc += isym->gotent.offset + rel->r_addend; -#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) - *loc += isym->gotent.offset; -#endif - break; - -#endif /* USE_GOT_ENTRIES */ - } - - return ret; -} - - -#if defined(USE_LIST) - -static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list, - int offset, int size) -{ - struct arch_list_entry *pe; - - for (pe = *list; pe != NULL; pe = pe->next) { - if (pe->addend == rel->r_addend) { - break; - } - } - - if (pe == NULL) { - pe = xmalloc(sizeof(struct arch_list_entry)); - pe->next = *list; - pe->addend = rel->r_addend; - pe->offset = offset; - pe->inited = 0; - *list = pe; - return size; - } - return 0; -} - -#endif - -#if defined(USE_SINGLE) - -static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single, - int offset, int size) -{ - if (single->allocated == 0) { - single->allocated = 1; - single->offset = offset; - single->inited = 0; - return size; - } - return 0; -} - -#endif - -#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) - -static struct obj_section *arch_xsect_init(struct obj_file *f, const char *name, - int offset, int size) -{ - struct obj_section *myrelsec = obj_find_section(f, name); - - if (offset == 0) { - offset += size; - } - - if (myrelsec) { - obj_extend_section(myrelsec, offset); - } else { - myrelsec = obj_create_alloced_section(f, name, - size, offset); - } - - return myrelsec; -} - -#endif - -static void arch_create_got(struct obj_file *f) -{ -#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) - struct arch_file *ifile = (struct arch_file *) f; - int i; -#if defined(USE_GOT_ENTRIES) - int got_offset = 0, got_needed = 0, got_allocate; -#endif -#if defined(USE_PLT_ENTRIES) - int plt_offset = 0, plt_needed = 0, plt_allocate; -#endif - struct obj_section *relsec, *symsec, *strsec; - ElfW(RelM) *rel, *relend; - ElfW(Sym) *symtab, *extsym; - const char *strtab, *name; - struct arch_symbol *intsym; - - for (i = 0; i < f->header.e_shnum; ++i) { - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - extsym = &symtab[ELF_R_SYM(rel->r_info)]; - -#if defined(USE_GOT_ENTRIES) - got_allocate = 0; -#endif -#if defined(USE_PLT_ENTRIES) - plt_allocate = 0; -#endif - - switch (ELF_R_TYPE(rel->r_info)) { -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: - plt_allocate = 1; - break; - - case R_ARM_GOTOFF: - case R_ARM_GOTPC: - got_needed = 1; - continue; - - case R_ARM_GOT32: - got_allocate = 1; - break; - -#elif defined(__i386__) - case R_386_GOTPC: - case R_386_GOTOFF: - got_needed = 1; - continue; - - case R_386_GOT32: - got_allocate = 1; - break; - -#elif defined(__powerpc__) - case R_PPC_REL24: - plt_allocate = 1; - break; - -#elif defined(__mc68000__) - case R_68K_GOT32: - got_allocate = 1; - break; - -#ifdef R_68K_GOTOFF - case R_68K_GOTOFF: - got_needed = 1; - continue; -#endif - -#elif defined(__sh__) - case R_SH_GOT32: - got_allocate = 1; - break; - - case R_SH_GOTPC: - case R_SH_GOTOFF: - got_needed = 1; - continue; - -#elif defined(__v850e__) - case R_V850_22_PCREL: - plt_needed = 1; - break; - -#endif - default: - continue; - } - - if (extsym->st_name != 0) { - name = strtab + extsym->st_name; - } else { - name = f->sections[extsym->st_shndx]->name; - } - intsym = (struct arch_symbol *) obj_find_symbol(f, name); -#if defined(USE_GOT_ENTRIES) - if (got_allocate) { - got_offset += arch_single_init( - /*rel,*/ &intsym->gotent, - got_offset, GOT_ENTRY_SIZE); - - got_needed = 1; - } -#endif -#if defined(USE_PLT_ENTRIES) - if (plt_allocate) { -#if defined(USE_PLT_LIST) - plt_offset += arch_list_add( - rel, &intsym->pltent, - plt_offset, PLT_ENTRY_SIZE); -#else - plt_offset += arch_single_init( - /*rel,*/ &intsym->pltent, - plt_offset, PLT_ENTRY_SIZE); -#endif - plt_needed = 1; - } -#endif - } - } - -#if defined(USE_GOT_ENTRIES) - if (got_needed) { - ifile->got = arch_xsect_init(f, ".got", got_offset, - GOT_ENTRY_SIZE); - } -#endif - -#if defined(USE_PLT_ENTRIES) - if (plt_needed) { - ifile->plt = arch_xsect_init(f, ".plt", plt_offset, - PLT_ENTRY_SIZE); - } -#endif - -#endif /* defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) */ -} - -/*======================================================================*/ - -/* Standard ELF hash function. */ -static unsigned long obj_elf_hash_n(const char *name, unsigned long n) -{ - unsigned long h = 0; - unsigned long g; - unsigned char ch; - - while (n > 0) { - ch = *name++; - h = (h << 4) + ch; - g = (h & 0xf0000000); - if (g != 0) { - h ^= g >> 24; - h &= ~g; - } - n--; - } - return h; -} - -static unsigned long obj_elf_hash(const char *name) -{ - return obj_elf_hash_n(name, strlen(name)); -} - -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING -/* String comparison for non-co-versioned kernel and module. */ - -static int ncv_strcmp(const char *a, const char *b) -{ - size_t alen = strlen(a), blen = strlen(b); - - if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') - return strncmp(a, b, alen); - else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') - return strncmp(a, b, blen); - else - return strcmp(a, b); -} - -/* String hashing for non-co-versioned kernel and module. Here - we are simply forced to drop the crc from the hash. */ - -static unsigned long ncv_symbol_hash(const char *str) -{ - size_t len = strlen(str); - if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') - len -= 10; - return obj_elf_hash_n(str, len); -} - -static void -obj_set_symbol_compare(struct obj_file *f, - int (*cmp) (const char *, const char *), - unsigned long (*hash) (const char *)) -{ - if (cmp) - f->symbol_cmp = cmp; - if (hash) { - struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; - int i; - - f->symbol_hash = hash; - - memcpy(tmptab, f->symtab, sizeof(tmptab)); - memset(f->symtab, 0, sizeof(f->symtab)); - - for (i = 0; i < HASH_BUCKETS; ++i) - for (sym = tmptab[i]; sym; sym = next) { - unsigned long h = hash(sym->name) % HASH_BUCKETS; - next = sym->next; - sym->next = f->symtab[h]; - f->symtab[h] = sym; - } - } -} - -#endif /* FEATURE_INSMOD_VERSION_CHECKING */ - -static struct obj_symbol * -obj_add_symbol(struct obj_file *f, const char *name, - unsigned long symidx, int info, - int secidx, ElfW(Addr) value, - unsigned long size) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - int n_type = ELF_ST_TYPE(info); - int n_binding = ELF_ST_BIND(info); - - for (sym = f->symtab[hash]; sym; sym = sym->next) { - if (f->symbol_cmp(sym->name, name) == 0) { - int o_secidx = sym->secidx; - int o_info = sym->info; - int o_type = ELF_ST_TYPE(o_info); - int o_binding = ELF_ST_BIND(o_info); - - /* A redefinition! Is it legal? */ - - if (secidx == SHN_UNDEF) - return sym; - else if (o_secidx == SHN_UNDEF) - goto found; - else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { - /* Cope with local and global symbols of the same name - in the same object file, as might have been created - by ld -r. The only reason locals are now seen at this - level at all is so that we can do semi-sensible things - with parameters. */ - - struct obj_symbol *nsym, **p; - - nsym = arch_new_symbol(); - nsym->next = sym->next; - nsym->ksymidx = -1; - - /* Excise the old (local) symbol from the hash chain. */ - for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) - continue; - *p = sym = nsym; - goto found; - } else if (n_binding == STB_LOCAL) { - /* Another symbol of the same name has already been defined. - Just add this to the local table. */ - sym = arch_new_symbol(); - sym->next = NULL; - sym->ksymidx = -1; - f->local_symtab[symidx] = sym; - goto found; - } else if (n_binding == STB_WEAK) - return sym; - else if (o_binding == STB_WEAK) - goto found; - /* Don't unify COMMON symbols with object types the programmer - doesn't expect. */ - else if (secidx == SHN_COMMON - && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) - return sym; - else if (o_secidx == SHN_COMMON - && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) - goto found; - else { - /* Don't report an error if the symbol is coming from - the kernel or some external module. */ - if (secidx <= SHN_HIRESERVE) - bb_error_msg("%s multiply defined", name); - return sym; - } - } - } - - /* Completely new symbol. */ - sym = arch_new_symbol(); - sym->next = f->symtab[hash]; - f->symtab[hash] = sym; - sym->ksymidx = -1; - if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) { - if (symidx >= f->local_symtab_size) - bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", - name, (long) symidx, (long) f->local_symtab_size); - else - f->local_symtab[symidx] = sym; - } - -found: - sym->name = name; - sym->value = value; - sym->size = size; - sym->secidx = secidx; - sym->info = info; - - return sym; -} - -static struct obj_symbol * -obj_find_symbol(struct obj_file *f, const char *name) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - - for (sym = f->symtab[hash]; sym; sym = sym->next) - if (f->symbol_cmp(sym->name, name) == 0) - return sym; - return NULL; -} - -static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) -{ - if (sym) { - if (sym->secidx >= SHN_LORESERVE) - return sym->value; - return sym->value + f->sections[sym->secidx]->header.sh_addr; - } - /* As a special case, a NULL sym has value zero. */ - return 0; -} - -static struct obj_section *obj_find_section(struct obj_file *f, const char *name) -{ - int i, n = f->header.e_shnum; - - for (i = 0; i < n; ++i) - if (strcmp(f->sections[i]->name, name) == 0) - return f->sections[i]; - return NULL; -} - -static int obj_load_order_prio(struct obj_section *a) -{ - unsigned long af, ac; - - af = a->header.sh_flags; - - ac = 0; - if (a->name[0] != '.' || strlen(a->name) != 10 - || strcmp(a->name + 5, ".init") != 0 - ) { - ac |= 32; - } - if (af & SHF_ALLOC) - ac |= 16; - if (!(af & SHF_WRITE)) - ac |= 8; - if (af & SHF_EXECINSTR) - ac |= 4; - if (a->header.sh_type != SHT_NOBITS) - ac |= 2; - - return ac; -} - -static void -obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) -{ - struct obj_section **p; - int prio = obj_load_order_prio(sec); - for (p = f->load_order_search_start; *p; p = &(*p)->load_next) - if (obj_load_order_prio(*p) < prio) - break; - sec->load_next = *p; - *p = sec; -} - -static struct obj_section *obj_create_alloced_section(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc_vector(f->sections, 2, newidx); - f->sections[newidx] = sec = arch_new_section(); - - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xzalloc(size); - - obj_insert_section_load_order(f, sec); - - return sec; -} - -static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc_vector(f->sections, 2, newidx); - f->sections[newidx] = sec = arch_new_section(); - - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xzalloc(size); - - sec->load_next = f->load_order; - f->load_order = sec; - if (f->load_order_search_start == &f->load_order) - f->load_order_search_start = &sec->load_next; - - return sec; -} - -static void *obj_extend_section(struct obj_section *sec, unsigned long more) -{ - unsigned long oldsize = sec->header.sh_size; - if (more) { - sec->header.sh_size += more; - sec->contents = xrealloc(sec->contents, sec->header.sh_size); - } - return sec->contents + oldsize; -} - - -/* Conditionally add the symbols from the given symbol set to the - new module. */ - -static int -add_symbols_from( struct obj_file *f, - int idx, struct new_module_symbol *syms, size_t nsyms) -{ - struct new_module_symbol *s; - size_t i; - int used = 0; -#ifdef SYMBOL_PREFIX - char *name_buf = 0; - size_t name_alloced_size = 0; -#endif -#if ENABLE_FEATURE_CHECK_TAINTED_MODULE - int gpl; - - gpl = obj_gpl_license(f, NULL) == 0; -#endif - for (i = 0, s = syms; i < nsyms; ++i, ++s) { - /* Only add symbols that are already marked external. - If we override locals we may cause problems for - argument initialization. We will also create a false - dependency on the module. */ - struct obj_symbol *sym; - char *name; - - /* GPL licensed modules can use symbols exported with - * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the - * exported names. Non-GPL modules never see any GPLONLY_ - * symbols so they cannot fudge it by adding the prefix on - * their references. - */ - if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) { -#if ENABLE_FEATURE_CHECK_TAINTED_MODULE - if (gpl) - s->name += 8; - else -#endif - continue; - } - name = (char *)s->name; - -#ifdef SYMBOL_PREFIX - /* Prepend SYMBOL_PREFIX to the symbol's name (the - kernel exports `C names', but module object files - reference `linker names'). */ - size_t extra = sizeof SYMBOL_PREFIX; - size_t name_size = strlen(name) + extra; - if (name_size > name_alloced_size) { - name_alloced_size = name_size * 2; - name_buf = alloca(name_alloced_size); - } - strcpy(name_buf, SYMBOL_PREFIX); - strcpy(name_buf + extra - 1, name); - name = name_buf; -#endif /* SYMBOL_PREFIX */ - - sym = obj_find_symbol(f, name); - if (sym && !(ELF_ST_BIND(sym->info) == STB_LOCAL)) { -#ifdef SYMBOL_PREFIX - /* Put NAME_BUF into more permanent storage. */ - name = xmalloc(name_size); - strcpy(name, name_buf); -#endif - sym = obj_add_symbol(f, name, -1, - ELF_ST_INFO(STB_GLOBAL, - STT_NOTYPE), - idx, s->value, 0); - /* Did our symbol just get installed? If so, mark the - module as "used". */ - if (sym->secidx == idx) - used = 1; - } - } - - return used; -} - -static void add_kernel_symbols(struct obj_file *f) -{ - struct external_module *m; - int i, nused = 0; - - /* Add module symbols first. */ - - for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) { - if (m->nsyms - && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms) - ) { - m->used = 1; - ++nused; - } - } - - n_ext_modules_used = nused; - - /* And finally the symbols from the kernel proper. */ - - if (nksyms) - add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); -} - -static char *get_modinfo_value(struct obj_file *f, const char *key) -{ - struct obj_section *sec; - char *p, *v, *n, *ep; - size_t klen = strlen(key); - - sec = obj_find_section(f, ".modinfo"); - if (sec == NULL) - return NULL; - p = sec->contents; - ep = p + sec->header.sh_size; - while (p < ep) { - v = strchr(p, '='); - n = strchr(p, '\0'); - if (v) { - if (p + klen == v && strncmp(p, key, klen) == 0) - return v + 1; - } else { - if (p + klen == n && strcmp(p, key) == 0) - return n; - } - p = n + 1; - } - - return NULL; -} - - -/*======================================================================*/ -/* Functions relating to module loading after 2.1.18. */ - -static void -new_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q, *key, *sym_name; - struct obj_symbol *sym; - char *contents, *loc; - int min, max, n; - - p = *argv; - q = strchr(p, '='); - if (q == NULL) { - argc--; - continue; - } - - key = alloca(q - p + 6); - memcpy(key, "parm_", 5); - memcpy(key + 5, p, q - p); - key[q - p + 5] = 0; - - p = get_modinfo_value(f, key); - key += 5; - if (p == NULL) { - bb_error_msg_and_die("invalid parameter %s", key); - } - -#ifdef SYMBOL_PREFIX - sym_name = alloca(strlen(key) + sizeof SYMBOL_PREFIX); - strcpy(sym_name, SYMBOL_PREFIX); - strcat(sym_name, key); -#else - sym_name = key; -#endif - sym = obj_find_symbol(f, sym_name); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - bb_error_msg_and_die("symbol for parameter %s not found", key); - } - - if (isdigit(*p)) { - min = strtoul(p, &p, 10); - if (*p == '-') - max = strtoul(p + 1, &p, 10); - else - max = min; - } else - min = max = 1; - - contents = f->sections[sym->secidx]->contents; - loc = contents + sym->value; - n = (*++q != '\0'); - - while (1) { - if ((*p == 's') || (*p == 'c')) { - char *str; - - /* Do C quoting if we begin with a ", else slurp the lot. */ - if (*q == '"') { - char *r; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') - bb_error_msg_and_die("improperly terminated string argument for %s", - key); - if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } - else - *r = *q; - } - *r = '\0'; - ++q; - } else { - char *r; - - /* In this case, the string is not quoted. We will break - it using the coma (like for ints). If the user wants to - include comas in a string, he just has to quote it */ - - /* Search the next coma */ - r = strchr(q, ','); - - /* Found ? */ - if (r != (char *) NULL) { - /* Recopy the current field */ - str = alloca(r - q + 1); - memcpy(str, q, r - q); - - /* I don't know if it is useful, as the previous case - doesn't nul terminate the string ??? */ - str[r - q] = '\0'; - - /* Keep next fields */ - q = r; - } else { - /* last string */ - str = q; - q = (char*)""; - } - } - - if (*p == 's') { - /* Normal string */ - obj_string_patch(f, sym->secidx, loc - contents, str); - loc += tgt_sizeof_char_p; - } else { - /* Array of chars (in fact, matrix!) */ - unsigned long charssize; /* size of each member */ - - /* Get the size of each member */ - /* Probably we should do that outside the loop ? */ - if (!isdigit(*(p + 1))) { - bb_error_msg_and_die("parameter type 'c' for %s must be followed by" - " the maximum size", key); - } - charssize = strtoul(p + 1, (char **) NULL, 10); - - /* Check length */ - if (strlen(str) >= charssize) { - bb_error_msg_and_die("string too long for %s (max %ld)", key, - charssize - 1); - } - - /* Copy to location */ - strcpy((char *) loc, str); - loc += charssize; - } - } else { - long v = strtoul(q, &q, 0); - switch (*p) { - case 'b': - *loc++ = v; - break; - case 'h': - *(short *) loc = v; - loc += tgt_sizeof_short; - break; - case 'i': - *(int *) loc = v; - loc += tgt_sizeof_int; - break; - case 'l': - *(long *) loc = v; - loc += tgt_sizeof_long; - break; - - default: - bb_error_msg_and_die("unknown parameter type '%c' for %s", *p, key); - } - } - retry_end_of_value: - switch (*q) { - case '\0': - goto end_of_arg; - - case ' ': - case '\t': - case '\n': - case '\r': - ++q; - goto retry_end_of_value; - - case ',': - if (++n > max) { - bb_error_msg_and_die("too many values for %s (max %d)", key, max); - } - ++q; - break; - - default: - bb_error_msg_and_die("invalid argument syntax for %s", key); - } - } - end_of_arg: - if (n < min) { - bb_error_msg_and_die("too few values for %s (min %d)", key, min); - } - - argc--; - argv++; - } -} - -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING -static int new_is_module_checksummed(struct obj_file *f) -{ - const char *p = get_modinfo_value(f, "using_checksums"); - if (p) - return xatoi(p); - return 0; -} - -/* Get the module's kernel version in the canonical integer form. */ - -static int -new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - char *p, *q; - int a, b, c; - - p = get_modinfo_value(f, "kernel_version"); - if (p == NULL) - return -1; - safe_strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* FEATURE_INSMOD_VERSION_CHECKING */ - - -/* Fetch the loaded modules, and all currently exported symbols. */ - -static void new_get_kernel_symbols(void) -{ - char *module_names, *mn; - struct external_module *modules, *m; - struct new_module_symbol *syms, *s; - size_t ret, bufsize, nmod, nsyms, i, j; - - /* Collect the loaded modules. */ - - bufsize = 256; - module_names = xmalloc(bufsize); - - retry_modules_load: - if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - bufsize = ret; - module_names = xrealloc(module_names, bufsize); - goto retry_modules_load; - } - bb_perror_msg_and_die("QM_MODULES"); - } - - n_ext_modules = nmod = ret; - - /* Collect the modules' symbols. */ - - if (nmod) { - ext_modules = modules = xzalloc(nmod * sizeof(*modules)); - for (i = 0, mn = module_names, m = modules; - i < nmod; ++i, ++m, mn += strlen(mn) + 1) { - struct new_module_info info; - - if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - bb_perror_msg_and_die("query_module: QM_INFO: %s", mn); - } - - bufsize = 1024; - syms = xmalloc(bufsize); - retry_mod_sym_load: - if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { - switch (errno) { - case ENOSPC: - bufsize = ret; - syms = xrealloc(syms, bufsize); - goto retry_mod_sym_load; - case ENOENT: - /* The module was removed out from underneath us. */ - continue; - default: - bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn); - } - } - nsyms = ret; - - m->name = mn; - m->addr = info.addr; - m->nsyms = nsyms; - m->syms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } - } - } - - /* Collect the kernel's symbols. */ - - syms = xmalloc(bufsize = 16 * 1024); - retry_kern_sym_load: - if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - bufsize = ret; - syms = xrealloc(syms, bufsize); - goto retry_kern_sym_load; - } - bb_perror_msg_and_die("kernel: QM_SYMBOLS"); - } - nksyms = nsyms = ret; - ksyms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } -} - - -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int new_is_kernel_checksummed(void) -{ - struct new_module_symbol *s; - size_t i; - - /* Using_Versions is not the first symbol, but it should be in there. */ - - for (i = 0, s = ksyms; i < nksyms; ++i, ++s) - if (strcmp((char *) s->name, "Using_Versions") == 0) - return s->value; - - return 0; -} - - -static void new_create_this_module(struct obj_file *f, const char *m_name) -{ - struct obj_section *sec; - - sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, - sizeof(struct new_module)); - /* done by obj_create_alloced_section_first: */ - /*memset(sec->contents, 0, sizeof(struct new_module));*/ - - obj_add_symbol(f, SPFX "__this_module", -1, - ELF_ST_INFO(STB_LOCAL, STT_OBJECT), sec->idx, 0, - sizeof(struct new_module)); - - obj_string_patch(f, sec->idx, offsetof(struct new_module, name), - m_name); -} - -#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS -/* add an entry to the __ksymtab section, creating it if necessary */ -static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym) -{ - struct obj_section *sec; - ElfW(Addr) ofs; - - /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section. - * If __ksymtab is defined but not marked alloc, x out the first character - * (no obj_delete routine) and create a new __ksymtab with the correct - * characteristics. - */ - sec = obj_find_section(f, "__ksymtab"); - if (sec && !(sec->header.sh_flags & SHF_ALLOC)) { - *((char *)(sec->name)) = 'x'; /* override const */ - sec = NULL; - } - if (!sec) - sec = obj_create_alloced_section(f, "__ksymtab", - tgt_sizeof_void_p, 0); - if (!sec) - return; - sec->header.sh_flags |= SHF_ALLOC; - /* Empty section might be byte-aligned */ - sec->header.sh_addralign = tgt_sizeof_void_p; - ofs = sec->header.sh_size; - obj_symbol_patch(f, sec->idx, ofs, sym); - obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); - obj_extend_section(sec, 2 * tgt_sizeof_char_p); -} -#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ - -static int new_create_module_ksymtab(struct obj_file *f) -{ - struct obj_section *sec; - int i; - - /* We must always add the module references. */ - - if (n_ext_modules_used) { - struct new_module_ref *dep; - struct obj_symbol *tm; - - sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, - (sizeof(struct new_module_ref) - * n_ext_modules_used)); - if (!sec) - return 0; - - tm = obj_find_symbol(f, SPFX "__this_module"); - dep = (struct new_module_ref *) sec->contents; - for (i = 0; i < n_ext_modules; ++i) - if (ext_modules[i].used) { - dep->dep = ext_modules[i].addr; - obj_symbol_patch(f, sec->idx, - (char *) &dep->ref - sec->contents, tm); - dep->next_ref = 0; - ++dep; - } - } - - if (!flag_noexport && !obj_find_section(f, "__ksymtab")) { - size_t nsyms; - int *loaded; - - sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); - - /* We don't want to export symbols residing in sections that - aren't loaded. There are a number of these created so that - we make sure certain module options don't appear twice. */ - i = f->header.e_shnum; - loaded = alloca(sizeof(int) * i); - while (--i >= 0) - loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - - for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) { - if (ELF_ST_BIND(sym->info) != STB_LOCAL - && sym->secidx <= SHN_HIRESERVE - && (sym->secidx >= SHN_LORESERVE - || loaded[sym->secidx]) - ) { - ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; - - obj_symbol_patch(f, sec->idx, ofs, sym); - obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, - sym->name); - - nsyms++; - } - } - } - - obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); - } - - return 1; -} - - -static int -new_init_module(const char *m_name, struct obj_file *f, unsigned long m_size) -{ - struct new_module *module; - struct obj_section *sec; - void *image; - int ret; - tgt_long m_addr; - - sec = obj_find_section(f, ".this"); - if (!sec || !sec->contents) { - bb_perror_msg_and_die("corrupt module %s?", m_name); - } - module = (struct new_module *) sec->contents; - m_addr = sec->header.sh_addr; - - module->size_of_struct = sizeof(*module); - module->size = m_size; - module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; - - sec = obj_find_section(f, "__ksymtab"); - if (sec && sec->header.sh_size) { - module->syms = sec->header.sh_addr; - module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); - } - - if (n_ext_modules_used) { - sec = obj_find_section(f, ".kmodtab"); - module->deps = sec->header.sh_addr; - module->ndeps = n_ext_modules_used; - } - - module->init = - obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); - module->cleanup = - obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); - - sec = obj_find_section(f, "__ex_table"); - if (sec) { - module->ex_table_start = sec->header.sh_addr; - module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; - } - - sec = obj_find_section(f, ".text.init"); - if (sec) { - module->runsize = sec->header.sh_addr - m_addr; - } - sec = obj_find_section(f, ".data.init"); - if (sec) { - if (!module->runsize - || module->runsize > sec->header.sh_addr - m_addr - ) { - module->runsize = sec->header.sh_addr - m_addr; - } - } - sec = obj_find_section(f, ARCHDATA_SEC_NAME); - if (sec && sec->header.sh_size) { - module->archdata_start = (void*)sec->header.sh_addr; - module->archdata_end = module->archdata_start + sec->header.sh_size; - } - sec = obj_find_section(f, KALLSYMS_SEC_NAME); - if (sec && sec->header.sh_size) { - module->kallsyms_start = (void*)sec->header.sh_addr; - module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; - } - - /* Whew! All of the initialization is complete. Collect the final - module image and give it to the kernel. */ - - image = xmalloc(m_size); - obj_create_image(f, image); - - ret = init_module(m_name, (struct new_module *) image); - if (ret) - bb_perror_msg("init_module: %s", m_name); - - free(image); - - return ret == 0; -} - - -/*======================================================================*/ - -static void -obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string) -{ - struct obj_string_patch *p; - struct obj_section *strsec; - size_t len = strlen(string) + 1; - char *loc; - - p = xmalloc(sizeof(*p)); - p->next = f->string_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - f->string_patches = p; - - strsec = obj_find_section(f, ".kstrtab"); - if (strsec == NULL) { - strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); - p->string_offset = 0; - loc = strsec->contents; - } else { - p->string_offset = strsec->header.sh_size; - loc = obj_extend_section(strsec, len); - } - memcpy(loc, string, len); -} - -static void -obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym) -{ - struct obj_symbol_patch *p; - - p = xmalloc(sizeof(*p)); - p->next = f->symbol_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - p->sym = sym; - f->symbol_patches = p; -} - -static void obj_check_undefineds(struct obj_file *f) -{ - unsigned i; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_UNDEF) { - if (ELF_ST_BIND(sym->info) == STB_WEAK) { - sym->secidx = SHN_ABS; - sym->value = 0; - } else { - if (!flag_quiet) - bb_error_msg_and_die("unresolved symbol %s", sym->name); - } - } - } -} - -static void obj_allocate_commons(struct obj_file *f) -{ - struct common_entry { - struct common_entry *next; - struct obj_symbol *sym; - } *common_head = NULL; - - unsigned long i; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_COMMON) { - /* Collect all COMMON symbols and sort them by size so as to - minimize space wasted by alignment requirements. */ - { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym->size <= (*p)->sym->size) - break; - - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - } - } - } - - for (i = 1; i < f->local_symtab_size; ++i) { - struct obj_symbol *sym = f->local_symtab[i]; - if (sym && sym->secidx == SHN_COMMON) { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym == (*p)->sym) - break; - else if (sym->size < (*p)->sym->size) { - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - break; - } - } - } - - if (common_head) { - /* Find the bss section. */ - for (i = 0; i < f->header.e_shnum; ++i) - if (f->sections[i]->header.sh_type == SHT_NOBITS) - break; - - /* If for some reason there hadn't been one, create one. */ - if (i == f->header.e_shnum) { - struct obj_section *sec; - - f->header.e_shnum++; - f->sections = xrealloc_vector(f->sections, 2, i); - f->sections[i] = sec = arch_new_section(); - - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->name = ".bss"; - sec->idx = i; - } - - /* Allocate the COMMONS. */ - { - ElfW(Addr) bss_size = f->sections[i]->header.sh_size; - ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; - struct common_entry *c; - - for (c = common_head; c; c = c->next) { - ElfW(Addr) align = c->sym->value; - - if (align > max_align) - max_align = align; - if (bss_size & (align - 1)) - bss_size = (bss_size | (align - 1)) + 1; - - c->sym->secidx = i; - c->sym->value = bss_size; - - bss_size += c->sym->size; - } - - f->sections[i]->header.sh_size = bss_size; - f->sections[i]->header.sh_addralign = max_align; - } - } - - /* For the sake of patch relocation and parameter initialization, - allocate zeroed data for NOBITS sections now. Note that after - this we cannot assume NOBITS are really empty. */ - for (i = 0; i < f->header.e_shnum; ++i) { - struct obj_section *s = f->sections[i]; - if (s->header.sh_type == SHT_NOBITS) { - s->contents = NULL; - if (s->header.sh_size != 0) - s->contents = xzalloc(s->header.sh_size), - s->header.sh_type = SHT_PROGBITS; - } - } -} - -static unsigned long obj_load_size(struct obj_file *f) -{ - unsigned long dot = 0; - struct obj_section *sec; - - /* Finalize the positions of the sections relative to one another. */ - - for (sec = f->load_order; sec; sec = sec->load_next) { - ElfW(Addr) align; - - align = sec->header.sh_addralign; - if (align && (dot & (align - 1))) - dot = (dot | (align - 1)) + 1; - - sec->header.sh_addr = dot; - dot += sec->header.sh_size; - } - - return dot; -} - -static int obj_relocate(struct obj_file *f, ElfW(Addr) base) -{ - int i, n = f->header.e_shnum; - int ret = 1; - - /* Finalize the addresses of the sections. */ - - f->baseaddr = base; - for (i = 0; i < n; ++i) - f->sections[i]->header.sh_addr += base; - - /* And iterate over all of the relocations. */ - - for (i = 0; i < n; ++i) { - struct obj_section *relsec, *symsec, *targsec, *strsec; - ElfW(RelM) * rel, *relend; - ElfW(Sym) * symtab; - const char *strtab; - - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - targsec = f->sections[relsec->header.sh_info]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - ElfW(Addr) value = 0; - struct obj_symbol *intsym = NULL; - unsigned long symndx; - ElfW(Sym) * extsym = 0; - const char *errmsg; - - /* Attempt to find a value to use for this relocation. */ - - symndx = ELF_R_SYM(rel->r_info); - if (symndx) { - /* Note we've already checked for undefined symbols. */ - - extsym = &symtab[symndx]; - if (ELF_ST_BIND(extsym->st_info) == STB_LOCAL) { - /* Local symbols we look up in the local table to be sure - we get the one that is really intended. */ - intsym = f->local_symtab[symndx]; - } else { - /* Others we look up in the hash table. */ - const char *name; - if (extsym->st_name) - name = strtab + extsym->st_name; - else - name = f->sections[extsym->st_shndx]->name; - intsym = obj_find_symbol(f, name); - } - - value = obj_symbol_final_value(f, intsym); - intsym->referenced = 1; - } -#if SHT_RELM == SHT_RELA -#if defined(__alpha__) && defined(AXP_BROKEN_GAS) - /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ - if (!extsym || !extsym->st_name - || ELF_ST_BIND(extsym->st_info) != STB_LOCAL) -#endif - value += rel->r_addend; -#endif - - /* Do it! */ - switch (arch_apply_relocation - (f, targsec, /*symsec,*/ intsym, rel, value) - ) { - case obj_reloc_ok: - break; - - case obj_reloc_overflow: - errmsg = "Relocation overflow"; - goto bad_reloc; - case obj_reloc_dangerous: - errmsg = "Dangerous relocation"; - goto bad_reloc; - case obj_reloc_unhandled: - errmsg = "Unhandled relocation"; -bad_reloc: - if (extsym) { - bb_error_msg("%s of type %ld for %s", errmsg, - (long) ELF_R_TYPE(rel->r_info), - strtab + extsym->st_name); - } else { - bb_error_msg("%s of type %ld", errmsg, - (long) ELF_R_TYPE(rel->r_info)); - } - ret = 0; - break; - } - } - } - - /* Finally, take care of the patches. */ - - if (f->string_patches) { - struct obj_string_patch *p; - struct obj_section *strsec; - ElfW(Addr) strsec_base; - strsec = obj_find_section(f, ".kstrtab"); - strsec_base = strsec->header.sh_addr; - - for (p = f->string_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = strsec_base + p->string_offset; - } - } - - if (f->symbol_patches) { - struct obj_symbol_patch *p; - - for (p = f->symbol_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = obj_symbol_final_value(f, p->sym); - } - } - - return ret; -} - -static int obj_create_image(struct obj_file *f, char *image) -{ - struct obj_section *sec; - ElfW(Addr) base = f->baseaddr; - - for (sec = f->load_order; sec; sec = sec->load_next) { - char *secimg; - - if (sec->contents == 0 || sec->header.sh_size == 0) - continue; - - secimg = image + (sec->header.sh_addr - base); - - /* Note that we allocated data for NOBITS sections earlier. */ - memcpy(secimg, sec->contents, sec->header.sh_size); - } - - return 1; -} - -/*======================================================================*/ - -static struct obj_file *obj_load(FILE *fp, int loadprogbits UNUSED_PARAM) -{ - struct obj_file *f; - ElfW(Shdr) * section_headers; - size_t shnum, i; - char *shstrtab; - - /* Read the file header. */ - - f = arch_new_file(); - f->symbol_cmp = strcmp; - f->symbol_hash = obj_elf_hash; - f->load_order_search_start = &f->load_order; - - fseek(fp, 0, SEEK_SET); - if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { - bb_perror_msg_and_die("error reading ELF header"); - } - - if (f->header.e_ident[EI_MAG0] != ELFMAG0 - || f->header.e_ident[EI_MAG1] != ELFMAG1 - || f->header.e_ident[EI_MAG2] != ELFMAG2 - || f->header.e_ident[EI_MAG3] != ELFMAG3 - ) { - bb_error_msg_and_die("not an ELF file"); - } - if (f->header.e_ident[EI_CLASS] != ELFCLASSM - || f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB) - || f->header.e_ident[EI_VERSION] != EV_CURRENT - || !MATCH_MACHINE(f->header.e_machine) - ) { - bb_error_msg_and_die("ELF file not for this architecture"); - } - if (f->header.e_type != ET_REL) { - bb_error_msg_and_die("ELF file not a relocatable object"); - } - - /* Read the section headers. */ - - if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - bb_error_msg_and_die("section header size mismatch: %lu != %lu", - (unsigned long) f->header.e_shentsize, - (unsigned long) sizeof(ElfW(Shdr))); - } - - shnum = f->header.e_shnum; - /* Growth of ->sections vector will be done by - * xrealloc_vector(..., 2, ...), therefore we must allocate - * at least 2^2 = 4 extra elements here. */ - f->sections = xzalloc(sizeof(f->sections[0]) * (shnum + 4)); - - section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); - fseek(fp, f->header.e_shoff, SEEK_SET); - if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { - bb_perror_msg_and_die("error reading ELF section headers"); - } - - /* Read the section data. */ - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec; - - f->sections[i] = sec = arch_new_section(); - - sec->header = section_headers[i]; - sec->idx = i; - - if (sec->header.sh_size) { - switch (sec->header.sh_type) { - case SHT_NULL: - case SHT_NOTE: - case SHT_NOBITS: - /* ignore */ - break; - - case SHT_PROGBITS: -#if LOADBITS - if (!loadprogbits) { - sec->contents = NULL; - break; - } -#endif - case SHT_SYMTAB: - case SHT_STRTAB: - case SHT_RELM: - sec->contents = NULL; - if (sec->header.sh_size > 0) { - sec->contents = xzalloc(sec->header.sh_size); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - bb_perror_msg_and_die("error reading ELF section data"); - } - } - break; - -#if SHT_RELM == SHT_REL - case SHT_RELA: - bb_error_msg_and_die("RELA relocations not supported on this architecture"); -#else - case SHT_REL: - bb_error_msg_and_die("REL relocations not supported on this architecture"); -#endif - default: - if (sec->header.sh_type >= SHT_LOPROC) { - /* Assume processor specific section types are debug - info and can safely be ignored. If this is ever not - the case (Hello MIPS?), don't put ifdefs here but - create an arch_load_proc_section(). */ - break; - } - - bb_error_msg_and_die("can't handle sections of type %ld", - (long) sec->header.sh_type); - } - } - } - - /* Do what sort of interpretation as needed by each section. */ - - shstrtab = f->sections[f->header.e_shstrndx]->contents; - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - sec->name = shstrtab + sec->header.sh_name; - } - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - - /* .modinfo should be contents only but gcc has no attribute for that. - * The kernel may have marked .modinfo as ALLOC, ignore this bit. - */ - if (strcmp(sec->name, ".modinfo") == 0) - sec->header.sh_flags &= ~SHF_ALLOC; - - if (sec->header.sh_flags & SHF_ALLOC) - obj_insert_section_load_order(f, sec); - - switch (sec->header.sh_type) { - case SHT_SYMTAB: - { - unsigned long nsym, j; - char *strtab; - ElfW(Sym) * sym; - - if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - bb_error_msg_and_die("symbol size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(Sym))); - } - - nsym = sec->header.sh_size / sizeof(ElfW(Sym)); - strtab = f->sections[sec->header.sh_link]->contents; - sym = (ElfW(Sym) *) sec->contents; - - /* Allocate space for a table of local symbols. */ - j = f->local_symtab_size = sec->header.sh_info; - f->local_symtab = xzalloc(j * sizeof(struct obj_symbol *)); - - /* Insert all symbols into the hash table. */ - for (j = 1, ++sym; j < nsym; ++j, ++sym) { - ElfW(Addr) val = sym->st_value; - const char *name; - if (sym->st_name) - name = strtab + sym->st_name; - else if (sym->st_shndx < shnum) - name = f->sections[sym->st_shndx]->name; - else - continue; -#if defined(__SH5__) - /* - * For sh64 it is possible that the target of a branch - * requires a mode switch (32 to 16 and back again). - * - * This is implied by the lsb being set in the target - * address for SHmedia mode and clear for SHcompact. - */ - val |= sym->st_other & 4; -#endif - obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, - val, sym->st_size); - } - } - break; - - case SHT_RELM: - if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(RelM))); - } - break; - /* XXX Relocation code from modutils-2.3.19 is not here. - * Why? That's about 20 lines of code from obj/obj_load.c, - * which gets done in a second pass through the sections. - * This BusyBox insmod does similar work in obj_relocate(). */ - } - } - - return f; -} - -#if ENABLE_FEATURE_INSMOD_LOADINKMEM -/* - * load the unloaded sections directly into the memory allocated by - * kernel for the module - */ - -static int obj_load_progbits(FILE *fp, struct obj_file *f, char *imagebase) -{ - ElfW(Addr) base = f->baseaddr; - struct obj_section* sec; - - for (sec = f->load_order; sec; sec = sec->load_next) { - - /* section already loaded? */ - if (sec->contents != NULL) - continue; - - if (sec->header.sh_size == 0) - continue; - - sec->contents = imagebase + (sec->header.sh_addr - base); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - bb_perror_msg("error reading ELF section data"); - return 0; - } - - } - return 1; -} -#endif - -static void hide_special_symbols(struct obj_file *f) -{ - static const char *const specials[] = { - SPFX "cleanup_module", - SPFX "init_module", - SPFX "kernel_version", - NULL - }; - - struct obj_symbol *sym; - const char *const *p; - - for (p = specials; *p; ++p) { - sym = obj_find_symbol(f, *p); - if (sym != NULL) - sym->info = ELF_ST_INFO(STB_LOCAL, ELF_ST_TYPE(sym->info)); - } -} - - -#if ENABLE_FEATURE_CHECK_TAINTED_MODULE -static int obj_gpl_license(struct obj_file *f, const char **license) -{ - struct obj_section *sec; - /* This list must match *exactly* the list of allowable licenses in - * linux/include/linux/module.h. Checking for leading "GPL" will not - * work, somebody will use "GPL sucks, this is proprietary". - */ - static const char *const gpl_licenses[] = { - "GPL", - "GPL v2", - "GPL and additional rights", - "Dual BSD/GPL", - "Dual MPL/GPL" - }; - - sec = obj_find_section(f, ".modinfo"); - if (sec) { - const char *value, *ptr, *endptr; - ptr = sec->contents; - endptr = ptr + sec->header.sh_size; - while (ptr < endptr) { - value = strchr(ptr, '='); - if (value && strncmp(ptr, "license", value-ptr) == 0) { - unsigned i; - if (license) - *license = value+1; - for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) { - if (strcmp(value+1, gpl_licenses[i]) == 0) - return 0; - } - return 2; - } - ptr = strchr(ptr, '\0'); - if (ptr) - ptr++; - else - ptr = endptr; - } - } - return 1; -} - -#define TAINT_FILENAME "/proc/sys/kernel/tainted" -#define TAINT_PROPRIETORY_MODULE (1 << 0) -#define TAINT_FORCED_MODULE (1 << 1) -#define TAINT_UNSAFE_SMP (1 << 2) -#define TAINT_URL "http://www.tux.org/lkml/#export-tainted" - -static void set_tainted(int fd, char *m_name, - int kernel_has_tainted, int taint, const char *text1, const char *text2) -{ - static smallint printed_info; - - char buf[80]; - int oldval; - - if (fd < 0 && !kernel_has_tainted) - return; /* New modutils on old kernel */ - printf("Warning: loading %s will taint the kernel: %s%s\n", - m_name, text1, text2); - if (!printed_info) { - printf(" See %s for information about tainted modules\n", TAINT_URL); - printed_info = 1; - } - if (fd >= 0) { - read(fd, buf, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - oldval = strtoul(buf, NULL, 10); - sprintf(buf, "%d\n", oldval | taint); - write(fd, buf, strlen(buf)); - } -} - -/* Check if loading this module will taint the kernel. */ -static void check_tainted_module(struct obj_file *f, char *m_name) -{ - static const char tainted_file[] ALIGN1 = TAINT_FILENAME; - - int fd, kernel_has_tainted; - const char *ptr; - - kernel_has_tainted = 1; - fd = open(tainted_file, O_RDWR); - if (fd < 0) { - if (errno == ENOENT) - kernel_has_tainted = 0; - else if (errno == EACCES) - kernel_has_tainted = 1; - else { - perror(tainted_file); - kernel_has_tainted = 0; - } - } - - switch (obj_gpl_license(f, &ptr)) { - case 0: - break; - case 1: - set_tainted(fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", ""); - break; - case 2: - /* The module has a non-GPL license so we pretend that the - * kernel always has a taint flag to get a warning even on - * kernels without the proc flag. - */ - set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr); - break; - default: - set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", ""); - break; - } - - if (flag_force_load) - set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", ""); - - if (fd >= 0) - close(fd); -} -#else /* FEATURE_CHECK_TAINTED_MODULE */ -#define check_tainted_module(x, y) do { } while (0); -#endif /* FEATURE_CHECK_TAINTED_MODULE */ - -#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS -/* add module source, timestamp, kernel version and a symbol for the - * start of some sections. this info is used by ksymoops to do better - * debugging. - */ -#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING -#define get_module_version(f, str) get_module_version(str) -#endif -static int -get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING - return new_get_module_version(f, str); -#else /* FEATURE_INSMOD_VERSION_CHECKING */ - strncpy(str, "???", sizeof(str)); - return -1; -#endif /* FEATURE_INSMOD_VERSION_CHECKING */ -} - -/* add module source, timestamp, kernel version and a symbol for the - * start of some sections. this info is used by ksymoops to do better - * debugging. - */ -static void -add_ksymoops_symbols(struct obj_file *f, const char *filename, - const char *m_name) -{ - static const char symprefix[] ALIGN1 = "__insmod_"; - static const char section_names[][8] = { - ".text", - ".rodata", - ".data", - ".bss", - ".sbss" - }; - - struct obj_section *sec; - struct obj_symbol *sym; - char *name, *absolute_filename; - char str[STRVERSIONLEN]; - unsigned i; - int l, lm_name, lfilename, use_ksymtab, version; - struct stat statbuf; - - /* WARNING: was using realpath, but replaced by readlink to stop using - * lots of stack. But here it seems to be able to cause problems? */ - absolute_filename = xmalloc_readlink(filename); - if (!absolute_filename) - absolute_filename = xstrdup(filename); - - lm_name = strlen(m_name); - lfilename = strlen(absolute_filename); - - /* add to ksymtab if it already exists or there is no ksymtab and other symbols - * are not to be exported. otherwise leave ksymtab alone for now, the - * "export all symbols" compatibility code will export these symbols later. - */ - use_ksymtab = obj_find_section(f, "__ksymtab") || flag_noexport; - - sec = obj_find_section(f, ".this"); - if (sec) { - /* tag the module header with the object name, last modified - * timestamp and module version. worst case for module version - * is 0xffffff, decimal 16777215. putting all three fields in - * one symbol is less readable but saves kernel space. - */ - l = sizeof(symprefix) + /* "__insmod_" */ - lm_name + /* module name */ - 2 + /* "_O" */ - lfilename + /* object filename */ - 2 + /* "_M" */ - 2 * sizeof(statbuf.st_mtime) + /* mtime in hex */ - 2 + /* "_V" */ - 8 + /* version in dec */ - 1; /* nul */ - name = xmalloc(l); - if (stat(absolute_filename, &statbuf) != 0) - statbuf.st_mtime = 0; - version = get_module_version(f, str); /* -1 if not found */ - snprintf(name, l, "%s%s_O%s_M%0*lX_V%d", - symprefix, m_name, absolute_filename, - (int)(2 * sizeof(statbuf.st_mtime)), statbuf.st_mtime, - version); - sym = obj_add_symbol(f, name, -1, - ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), - sec->idx, sec->header.sh_addr, 0); - if (use_ksymtab) - new_add_ksymtab(f, sym); - } - free(absolute_filename); -#ifdef _NOT_SUPPORTED_ - /* record where the persistent data is going, same address as previous symbol */ - - if (f->persist) { - l = sizeof(symprefix) + /* "__insmod_" */ - lm_name + /* module name */ - 2 + /* "_P" */ - strlen(f->persist) + /* data store */ - 1; /* nul */ - name = xmalloc(l); - snprintf(name, l, "%s%s_P%s", - symprefix, m_name, f->persist); - sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), - sec->idx, sec->header.sh_addr, 0); - if (use_ksymtab) - new_add_ksymtab(f, sym); - } -#endif /* _NOT_SUPPORTED_ */ - /* tag the desired sections if size is non-zero */ - - for (i = 0; i < ARRAY_SIZE(section_names); ++i) { - sec = obj_find_section(f, section_names[i]); - if (sec && sec->header.sh_size) { - l = sizeof(symprefix) + /* "__insmod_" */ - lm_name + /* module name */ - 2 + /* "_S" */ - strlen(sec->name) + /* section name */ - 2 + /* "_L" */ - 8 + /* length in dec */ - 1; /* nul */ - name = xmalloc(l); - snprintf(name, l, "%s%s_S%s_L%ld", - symprefix, m_name, sec->name, - (long)sec->header.sh_size); - sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), - sec->idx, sec->header.sh_addr, 0); - if (use_ksymtab) - new_add_ksymtab(f, sym); - } - } -} -#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ - -#if ENABLE_FEATURE_INSMOD_LOAD_MAP -static void print_load_map(struct obj_file *f) -{ - struct obj_section *sec; -#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL - struct obj_symbol **all, **p; - int i, nsyms, *loaded; - struct obj_symbol *sym; -#endif - /* Report on the section layout. */ - - printf("Sections: Size %-*s Align\n", - (int) (2 * sizeof(void *)), "Address"); - - for (sec = f->load_order; sec; sec = sec->load_next) { - int a; - unsigned long tmp; - - for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a) - tmp >>= 1; - if (a == -1) - a = 0; - - printf("%-15s %08lx %0*lx 2**%d\n", - sec->name, - (long)sec->header.sh_size, - (int) (2 * sizeof(void *)), - (long)sec->header.sh_addr, - a); - } -#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL - /* Quick reference which section indices are loaded. */ - - i = f->header.e_shnum; - loaded = alloca(sizeof(int) * i); - while (--i >= 0) - loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0); - - /* Collect the symbols we'll be listing. */ - - for (nsyms = i = 0; i < HASH_BUCKETS; ++i) - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx <= SHN_HIRESERVE - && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]) - ) { - ++nsyms; - } - - all = alloca(nsyms * sizeof(struct obj_symbol *)); - - for (i = 0, p = all; i < HASH_BUCKETS; ++i) - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx <= SHN_HIRESERVE - && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]) - ) { - *p++ = sym; - } - - /* And list them. */ - printf("\nSymbols:\n"); - for (p = all; p < all + nsyms; ++p) { - char type = '?'; - unsigned long value; - - sym = *p; - if (sym->secidx == SHN_ABS) { - type = 'A'; - value = sym->value; - } else if (sym->secidx == SHN_UNDEF) { - type = 'U'; - value = 0; - } else { - sec = f->sections[sym->secidx]; - - if (sec->header.sh_type == SHT_NOBITS) - type = 'B'; - else if (sec->header.sh_flags & SHF_ALLOC) { - if (sec->header.sh_flags & SHF_EXECINSTR) - type = 'T'; - else if (sec->header.sh_flags & SHF_WRITE) - type = 'D'; - else - type = 'R'; - } - value = sym->value + sec->header.sh_addr; - } - - if (ELF_ST_BIND(sym->info) == STB_LOCAL) - type = tolower(type); - - printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value, - type, sym->name); - } -#endif -} -#else /* !FEATURE_INSMOD_LOAD_MAP */ -void print_load_map(struct obj_file *f); -#endif - -int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int insmod_main(int argc, char **argv) -{ - char *opt_o, *arg1; - int len; - int k_crcs; - char *tmp, *tmp1; - unsigned long m_size; - ElfW(Addr) m_addr; - struct obj_file *f; - struct stat st; - char *m_name = NULL; - int exit_status = EXIT_FAILURE; - int m_has_modinfo; -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING - struct utsname uts_info; - char m_strversion[STRVERSIONLEN]; - int m_version, m_crcs; -#endif -#if ENABLE_FEATURE_CLEAN_UP - FILE *fp = NULL; -#else - FILE *fp; -#endif - int k_version = 0; - struct utsname myuname; - - /* Parse any options */ - getopt32(argv, OPTION_STR, &opt_o); - arg1 = argv[optind]; - if (option_mask32 & OPT_o) { // -o /* name the output module */ - free(m_name); - m_name = xstrdup(opt_o); - } - - if (arg1 == NULL) { - bb_show_usage(); - } - - /* Grab the module name */ - tmp1 = xstrdup(arg1); - tmp = basename(tmp1); - len = strlen(tmp); - - if (uname(&myuname) == 0) { - if (myuname.release[0] == '2') { - k_version = myuname.release[2] - '0'; - } - } - -#if ENABLE_FEATURE_2_6_MODULES - if (k_version > 4 && len > 3 && tmp[len - 3] == '.' - && tmp[len - 2] == 'k' && tmp[len - 1] == 'o' - ) { - len -= 3; - tmp[len] = '\0'; - } else -#endif - if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { - len -= 2; - tmp[len] = '\0'; - } - - -#if ENABLE_FEATURE_2_6_MODULES - if (k_version > 4) - m_fullName = xasprintf("%s.ko", tmp); - else -#endif - m_fullName = xasprintf("%s.o", tmp); - - if (!m_name) { - m_name = tmp; - } else { - free(tmp1); - tmp1 = NULL; /* flag for free(m_name) before exit() */ - } - - /* Get a filedesc for the module. Check that we have a complete path */ - if (stat(arg1, &st) < 0 || !S_ISREG(st.st_mode) - || (fp = fopen_for_read(arg1)) == NULL - ) { - /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, - * but do not error out yet if we fail to find it... */ - if (k_version) { /* uname succeedd */ - char *module_dir; - char *tmdn; - - tmdn = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, myuname.release); - /* Jump through hoops in case /lib/modules/`uname -r` - * is a symlink. We do not want recursive_action to - * follow symlinks, but we do want to follow the - * /lib/modules/`uname -r` dir, So resolve it ourselves - * if it is a link... */ - module_dir = xmalloc_readlink(tmdn); - if (!module_dir) - module_dir = xstrdup(tmdn); - recursive_action(module_dir, ACTION_RECURSE, - check_module_name_match, NULL, m_fullName, 0); - free(module_dir); - free(tmdn); - } - - /* Check if we have found anything yet */ - if (!m_filename || ((fp = fopen_for_read(m_filename)) == NULL)) { - int r; - char *module_dir; - - free(m_filename); - m_filename = NULL; - module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR); - if (!module_dir) - module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR); - /* No module found under /lib/modules/`uname -r`, this - * time cast the net a bit wider. Search /lib/modules/ */ - r = recursive_action(module_dir, ACTION_RECURSE, - check_module_name_match, NULL, m_fullName, 0); - if (r) - bb_error_msg_and_die("%s: module not found", m_fullName); - free(module_dir); - if (m_filename == NULL - || ((fp = fopen_for_read(m_filename)) == NULL) - ) { - bb_error_msg_and_die("%s: module not found", m_fullName); - } - } - } else - m_filename = xstrdup(arg1); - - if (flag_verbose) - printf("Using %s\n", m_filename); - -#if ENABLE_FEATURE_2_6_MODULES - if (k_version > 4) { - argv[optind] = m_filename; - optind--; - return insmod_ng_main(argc - optind, argv + optind); - } -#endif - - f = obj_load(fp, LOADBITS); - - if (get_modinfo_value(f, "kernel_version") == NULL) - m_has_modinfo = 0; - else - m_has_modinfo = 1; - -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING - /* Version correspondence? */ - if (!flag_quiet) { - if (uname(&uts_info) < 0) - uts_info.release[0] = '\0'; - if (m_has_modinfo) { - m_version = new_get_module_version(f, m_strversion); - if (m_version == -1) { - bb_error_msg_and_die("cannot find the kernel version the module was " - "compiled for"); - } - } - - if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { - bb_error_msg("%skernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s", - flag_force_load ? "warning: " : "", - m_filename, m_strversion, uts_info.release); - if (!flag_force_load) - goto out; - } - } - k_crcs = 0; -#endif /* FEATURE_INSMOD_VERSION_CHECKING */ - - if (query_module(NULL, 0, NULL, 0, NULL)) - bb_error_msg_and_die("not configured to support old kernels"); - new_get_kernel_symbols(); - k_crcs = new_is_kernel_checksummed(); - -#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING - m_crcs = 0; - if (m_has_modinfo) - m_crcs = new_is_module_checksummed(f); - - if (m_crcs != k_crcs) - obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); -#endif /* FEATURE_INSMOD_VERSION_CHECKING */ - - /* Let the module know about the kernel symbols. */ - add_kernel_symbols(f); - - /* Allocate common symbols, symbol tables, and string tables. */ - - new_create_this_module(f, m_name); - obj_check_undefineds(f); - obj_allocate_commons(f); - check_tainted_module(f, m_name); - - /* done with the module name, on to the optional var=value arguments */ - ++optind; - if (optind < argc) { - new_process_module_arguments(f, argc - optind, argv + optind); - } - - arch_create_got(f); - hide_special_symbols(f); - -#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS - add_ksymoops_symbols(f, m_filename, m_name); -#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ - - new_create_module_ksymtab(f); - - /* Find current size of the module */ - m_size = obj_load_size(f); - - m_addr = create_module(m_name, m_size); - if (m_addr == (ElfW(Addr))(-1)) switch (errno) { - case EEXIST: - bb_error_msg_and_die("a module named %s already exists", m_name); - case ENOMEM: - bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes", - m_size); - default: - bb_perror_msg_and_die("create_module: %s", m_name); - } - -#if !LOADBITS - /* - * the PROGBITS section was not loaded by the obj_load - * now we can load them directly into the kernel memory - */ - if (!obj_load_progbits(fp, f, (char*)m_addr)) { - delete_module(m_name, 0); - goto out; - } -#endif - - if (!obj_relocate(f, m_addr)) { - delete_module(m_name, 0); - goto out; - } - - if (!new_init_module(m_name, f, m_size)) { - delete_module(m_name, 0); - goto out; - } - - if (flag_print_load_map) - print_load_map(f); - - exit_status = EXIT_SUCCESS; - - out: -#if ENABLE_FEATURE_CLEAN_UP - if (fp) - fclose(fp); - free(tmp1); - if (!tmp1) - free(m_name); - free(m_filename); -#endif - return exit_status; -} - -#endif /* ENABLE_FEATURE_2_4_MODULES */ -/* - * End of big piece of 2.4-specific code - */ - - -#if ENABLE_FEATURE_2_6_MODULES - -#include - -#if defined __UCLIBC__ && !ENABLE_FEATURE_2_4_MODULES -/* big time suckage. The old prototype above renders our nice fwd-decl wrong */ -extern int init_module(void *module, unsigned long len, const char *options); -#else -#include -#include -#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) -#endif - -/* We use error numbers in a loose translation... */ -static const char *moderror(int err) -{ - switch (err) { - case ENOEXEC: - return "invalid module format"; - case ENOENT: - return "unknown symbol in module"; - case ESRCH: - return "module has wrong symbol version"; - case EINVAL: - return "invalid parameters"; - default: - return strerror(err); - } -} - -#if !ENABLE_FEATURE_2_4_MODULES -int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int insmod_main(int argc UNUSED_PARAM, char **argv) -#else -static int insmod_ng_main(int argc UNUSED_PARAM, char **argv) -#endif -{ - size_t len; - int optlen; - void *map; - char *filename, *options; - - filename = *++argv; - if (!filename) - bb_show_usage(); - - /* Rest is options */ - options = xzalloc(1); - optlen = 0; - while (*++argv) { - options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); - /* Spaces handled by "" pairs, but no way of escaping quotes */ - optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv); - } - -#if 0 - /* Any special reason why mmap? It isn't performance critical. -vda */ - /* Yes, xmalloc'ing can use *alot* of RAM. Don't forget that there are - * modules out there that are half a megabyte! mmap()ing is way nicer - * for small mem boxes, i guess. */ - /* But after load, these modules will take up that 0.5mb in kernel - * anyway. Using malloc here causes only a transient spike to 1mb, - * after module is loaded, we go back to normal 0.5mb usage - * (in kernel). Also, mmap isn't magic - when we touch mapped data, - * we use memory. -vda */ - int fd; - struct stat st; - unsigned long len; - fd = xopen(filename, O_RDONLY); - fstat(fd, &st); - len = st.st_size; - map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - bb_perror_msg_and_die("cannot mmap '%s'", filename); - } - - /* map == NULL on Blackfin, probably on other MMU-less systems too. Workaround. */ - if (map == NULL) { - map = xmalloc(len); - xread(fd, map, len); - } -#else - len = MAXINT(ssize_t); - map = xmalloc_xopen_read_close(filename, &len); -#endif - - if (init_module(map, len, options) != 0) - bb_error_msg_and_die("cannot insert '%s': %s", - filename, moderror(errno)); - return 0; -} - -#endif +/* vi: set sw=4 ts=4: */ +/* + * Mini insmod implementation for busybox + * + * Copyright (C) 2008 Timo Teras + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "modutils.h" + +int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int insmod_main(int argc UNUSED_PARAM, char **argv) +{ + char *filename; + int rc; + + /* Compat note: + * 2.6 style insmod has no options and required filename + * (not module name - .ko can't be omitted). + * 2.4 style insmod can take module name without .o + * and performs module search in default directories + * or in $MODPATH. + */ + + USE_FEATURE_2_4_MODULES( + getopt32(argv, INSMOD_OPTS INSMOD_ARGS); + argv += optind - 1; + ); + + filename = *++argv; + if (!filename) + bb_show_usage(); + + rc = bb_init_module(filename, parse_cmdline_module_options(argv)); + if (rc) + bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); + + return rc; +} diff --git a/release/src/router/busybox/modutils/lsmod.c b/release/src/router/busybox/modutils/lsmod.c dissimilarity index 83% index 3f237039e9..87dd1fcba9 100644 --- a/release/src/router/busybox/modutils/lsmod.c +++ b/release/src/router/busybox/modutils/lsmod.c @@ -1,194 +1,79 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini lsmod implementation for busybox - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support pre 2.1 kernels - * (which lack the query_module() interface). - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - - -#if !ENABLE_FEATURE_CHECK_TAINTED_MODULE -static void check_tainted(void) { bb_putchar('\n'); } -#else -#define TAINT_FILENAME "/proc/sys/kernel/tainted" -#define TAINT_PROPRIETORY_MODULE (1<<0) -#define TAINT_FORCED_MODULE (1<<1) -#define TAINT_UNSAFE_SMP (1<<2) - -static void check_tainted(void) -{ - int tainted; - FILE *f; - - tainted = 0; - f = fopen_for_read(TAINT_FILENAME); - if (f) { - fscanf(f, "%d", &tainted); - fclose(f); - } - if (tainted) { - printf(" Tainted: %c%c%c\n", - tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', - tainted & TAINT_FORCED_MODULE ? 'F' : ' ', - tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); - } else { - printf(" Not tainted\n"); - } -} -#endif - -#if ENABLE_FEATURE_QUERY_MODULE_INTERFACE - -struct module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - - -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); - -enum { -/* Values for query_module's which. */ - QM_MODULES = 1, - QM_DEPS = 2, - QM_REFS = 3, - QM_SYMBOLS = 4, - QM_INFO = 5, - -/* Bits of module.flags. */ - NEW_MOD_RUNNING = 1, - NEW_MOD_DELETED = 2, - NEW_MOD_AUTOCLEAN = 4, - NEW_MOD_VISITED = 8, - NEW_MOD_USED_ONCE = 16, - NEW_MOD_INITIALIZING = 64 -}; - -int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) -{ - struct module_info info; - char *module_names, *mn, *deps, *dn; - size_t bufsize, depsize, nmod, count, i, j; - - module_names = deps = NULL; - bufsize = depsize = 0; - while (query_module(NULL, QM_MODULES, module_names, bufsize, &nmod)) { - if (errno != ENOSPC) bb_perror_msg_and_die("QM_MODULES"); - module_names = xmalloc(bufsize = nmod); - } - - deps = xmalloc(depsize = 256); - printf("Module\t\t\tSize Used by"); - check_tainted(); - - for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { - if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - /* else choke */ - bb_perror_msg_and_die("module %s: QM_INFO", mn); - } - while (query_module(mn, QM_REFS, deps, depsize, &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } else if (errno != ENOSPC) - bb_perror_msg_and_die("module %s: QM_REFS", mn); - deps = xrealloc(deps, count); - } - printf("%-20s%8lu%4ld", mn, info.size, info.usecount); - if (info.flags & NEW_MOD_DELETED) - printf(" (deleted)"); - else if (info.flags & NEW_MOD_INITIALIZING) - printf(" (initializing)"); - else if (!(info.flags & NEW_MOD_RUNNING)) - printf(" (uninitialized)"); - else { - if (info.flags & NEW_MOD_AUTOCLEAN) - printf(" (autoclean) "); - if (!(info.flags & NEW_MOD_USED_ONCE)) - printf(" (unused)"); - } - if (count) - printf(" ["); - for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { - printf("%s%s", dn, (j==count-1)? "":" "); - } - if (count) - bb_putchar(']'); - - bb_putchar('\n'); - } - -#if ENABLE_FEATURE_CLEAN_UP - free(module_names); -#endif - - return 0; -} - -#else /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ - -int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) -{ - FILE *file = xfopen_for_read("/proc/modules"); - - printf("Module Size Used by"); - check_tainted(); -#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT - { - char *line; - while ((line = xmalloc_fgets(file)) != NULL) { - char *tok; - - tok = strtok(line, " \t"); - printf("%-19s", tok); - tok = strtok(NULL, " \t\n"); - printf(" %8s", tok); - tok = strtok(NULL, " \t\n"); - /* Null if no module unloading support. */ - if (tok) { - printf(" %s", tok); - tok = strtok(NULL, "\n"); - if (!tok) - tok = (char*)""; - /* New-style has commas, or -. If so, - truncate (other fields might follow). */ - else if (strchr(tok, ',')) { - tok = strtok(tok, "\t "); - /* Strip trailing comma. */ - if (tok[strlen(tok)-1] == ',') - tok[strlen(tok)-1] = '\0'; - } else if (tok[0] == '-' - && (tok[1] == '\0' || isspace(tok[1])) - ) { - tok = (char*)""; - } - printf(" %s", tok); - } - bb_putchar('\n'); - free(line); - } - fclose(file); - } -#else - xprint_and_close_file(file); -#endif /* CONFIG_FEATURE_2_6_MODULES */ - return EXIT_SUCCESS; -} - -#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ +/* vi: set sw=4 ts=4: */ +/* + * Mini lsmod implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +#if ENABLE_FEATURE_CHECK_TAINTED_MODULE +enum { + TAINT_PROPRIETORY_MODULE = (1 << 0), + TAINT_FORCED_MODULE = (1 << 1), + TAINT_UNSAFE_SMP = (1 << 2), +}; + +static void check_tainted(void) +{ + int tainted = 0; + char *buf = xmalloc_open_read_close("/proc/sys/kernel/tainted", NULL); + if (buf) { + tainted = atoi(buf); + if (ENABLE_FEATURE_CLEAN_UP) + free(buf); + } + + if (tainted) { + printf(" Tainted: %c%c%c\n", + tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); + } else { + puts(" Not tainted"); + } +} +#else +static void check_tainted(void) { putchar('\n'); } +#endif + +int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ +#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT + char *token[4]; + parser_t *parser = config_open("/proc/modules"); + printf("%-24sSize Used by", "Module"); + check_tainted(); + + if (ENABLE_FEATURE_2_4_MODULES + && get_linux_version_code() < KERNEL_VERSION(2,6,0) + ) { + while (config_read(parser, token, 4, 3, "# \t", PARSE_NORMAL)) { + if (token[3] != NULL && token[3][0] == '[') { + token[3]++; + token[3][strlen(token[3])-1] = '\0'; + } else + token[3] = (char *) ""; + printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]); + } + } else { + while (config_read(parser, token, 4, 4, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) { + // N.B. token[3] is either '-' (module is not used by others) + // or comma-separated list ended by comma + // so trimming the trailing char is just what we need! + token[3][strlen(token[3])-1] = '\0'; + printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]); + } + } + if (ENABLE_FEATURE_CLEAN_UP) + config_close(parser); +#else + check_tainted(); + xprint_and_close_file(xfopen_for_read("/proc/modules")); +#endif + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/modutils/modprobe-small.c b/release/src/router/busybox/modutils/modprobe-small.c index 06c45742b8..6eb950f32e 100644 --- a/release/src/router/busybox/modutils/modprobe-small.c +++ b/release/src/router/busybox/modutils/modprobe-small.c @@ -3,7 +3,7 @@ * simplified modprobe * * Copyright (c) 2008 Vladimir Dronnikov - * Copyright (c) 2008 Bernhard Fischer (initial depmod code) + * Copyright (c) 2008 Bernhard Reutner-Fischer (initial depmod code) * * Licensed under GPLv2, see file LICENSE in this tarball for details. */ @@ -599,19 +599,23 @@ static void process_module(char *name, const char *cmdline_options) } free(deps); - /* insmod -> load it */ + /* modprobe -> load it */ if (!is_rmmod) { - errno = 0; - if (load_module(info->pathname, options) != 0) { - if (EEXIST != errno) { - bb_error_msg("'%s': %s", + if (!options || strstr(options, "blacklist") == NULL) { + errno = 0; + if (load_module(info->pathname, options) != 0) { + if (EEXIST != errno) { + bb_error_msg("'%s': %s", info->pathname, moderror(errno)); - } else { - dbg1_error_msg("'%s': %s", + } else { + dbg1_error_msg("'%s': %s", info->pathname, moderror(errno)); + } } + } else { + dbg1_error_msg("'%s': blacklisted", info->pathname); } } ret: @@ -688,8 +692,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* Prevent ugly corner cases with no modules at all */ modinfo = xzalloc(sizeof(modinfo[0])); - /* Goto modules directory */ - xchdir(CONFIG_DEFAULT_MODULES_DIR); + if ('i' != applet0) { /* not insmod */ + /* Goto modules directory */ + xchdir(CONFIG_DEFAULT_MODULES_DIR); + } uname(&uts); /* never fails */ /* depmod? */ @@ -736,8 +742,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_r; } - /* Goto $VERSION directory */ - xchdir(uts.release); + if ('i' != applet0) { /* not insmod */ + /* Goto $VERSION directory */ + xchdir(uts.release); + } #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE /* If not rmmod, parse possible module options given on command line. @@ -758,11 +766,26 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) argv[1] = NULL; #endif + if ('i' == applet0) { /* insmod */ + size_t len; + void *map; + + len = MAXINT(ssize_t); + map = xmalloc_xopen_read_close(*argv, &len); + if (init_module(map, len, + USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "") + SKIP_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("") + ) != 0) + bb_error_msg_and_die("can't insert '%s': %s", + *argv, moderror(errno)); + return 0; + } + /* Try to load modprobe.dep.bb */ load_dep_bb(); /* Load/remove modules. - * Only rmmod loops here, insmod/modprobe has only argv[0] */ + * Only rmmod loops here, modprobe has only argv[0] */ do { process_module(*argv++, options); } while (*argv); diff --git a/release/src/router/busybox/modutils/modprobe.c b/release/src/router/busybox/modutils/modprobe.c dissimilarity index 96% index 8bbc2397c7..218a898a8e 100644 --- a/release/src/router/busybox/modutils/modprobe.c +++ b/release/src/router/busybox/modutils/modprobe.c @@ -1,952 +1,398 @@ -/* vi: set sw=4 ts=4: */ -/* - * Modprobe written from scratch for BusyBox - * - * Copyright (c) 2002 by Robert Griebl, griebl@gmx.de - * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au - * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com - * - * Portions Copyright (c) 2005 by Yann E. MORIN, yann.morin.1998@anciens.enib.fr - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. -*/ - -#include "libbb.h" -#include -#include - -#define line_buffer bb_common_bufsiz1 - -struct mod_opt_t { /* one-way list of options to pass to a module */ - char * m_opt_val; - struct mod_opt_t * m_next; -}; - -struct dep_t { /* one-way list of dependency rules */ - /* a dependency rule */ - char * m_name; /* the module name*/ - char * m_path; /* the module file path */ - struct mod_opt_t * m_options; /* the module options */ - - unsigned int m_isalias :1; /* the module is an alias */ - unsigned int m_isblacklisted:1; /* the module is blacklisted */ - unsigned int m_reserved :14; /* stuffin' */ - - unsigned int m_depcnt :16; /* the number of dependable module(s) */ - char ** m_deparr; /* the list of dependable module(s) */ - - struct dep_t * m_next; /* the next dependency rule */ -}; - -struct mod_list_t { /* two-way list of modules to process */ - /* a module description */ - const char * m_name; - char * m_path; - struct mod_opt_t * m_options; - - struct mod_list_t * m_prev; - struct mod_list_t * m_next; -}; - -struct include_conf_t { - struct dep_t *first; - struct dep_t *current; -}; - -static struct dep_t *depend; - -#define MAIN_OPT_STR "acdklnqrst:vVC:" -#define INSERT_ALL 1 /* a */ -#define DUMP_CONF_EXIT 2 /* c */ -#define D_OPT_IGNORED 4 /* d */ -#define AUTOCLEAN_FLG 8 /* k */ -#define LIST_ALL 16 /* l */ -#define SHOW_ONLY 32 /* n */ -#define QUIET 64 /* q */ -#define REMOVE_OPT 128 /* r */ -#define DO_SYSLOG 256 /* s */ -#define RESTRICT_DIR 512 /* t */ -#define VERBOSE 1024 /* v */ -#define VERSION_ONLY 2048 /* V */ -#define CONFIG_FILE 4096 /* C */ - -#define autoclean (option_mask32 & AUTOCLEAN_FLG) -#define show_only (option_mask32 & SHOW_ONLY) -#define quiet (option_mask32 & QUIET) -#define remove_opt (option_mask32 & REMOVE_OPT) -#define do_syslog (option_mask32 & DO_SYSLOG) -#define verbose (option_mask32 & VERBOSE) - -static int parse_tag_value(char *buffer, char **ptag, char **pvalue) -{ - char *tag, *value; - - buffer = skip_whitespace(buffer); - tag = value = buffer; - while (!isspace(*value)) { - if (!*value) - return 0; - value++; - } - *value++ = '\0'; - value = skip_whitespace(value); - if (!*value) - return 0; - - *ptag = tag; - *pvalue = value; - - return 1; -} - -/* - * This function appends an option to a list - */ -static struct mod_opt_t *append_option(struct mod_opt_t *opt_list, char *opt) -{ - struct mod_opt_t *ol = opt_list; - - if (ol) { - while (ol->m_next) { - ol = ol->m_next; - } - ol->m_next = xzalloc(sizeof(struct mod_opt_t)); - ol = ol->m_next; - } else { - ol = opt_list = xzalloc(sizeof(struct mod_opt_t)); - } - - ol->m_opt_val = xstrdup(opt); - /*ol->m_next = NULL; - done by xzalloc*/ - - return opt_list; -} - -#if ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS -/* static char* parse_command_string(char* src, char **dst); - * src: pointer to string containing argument - * dst: pointer to where to store the parsed argument - * return value: the pointer to the first char after the parsed argument, - * NULL if there was no argument parsed (only trailing spaces). - * Note that memory is allocated with xstrdup when a new argument was - * parsed. Don't forget to free it! - */ -#define ARG_EMPTY 0x00 -#define ARG_IN_DQUOTES 0x01 -#define ARG_IN_SQUOTES 0x02 -static char *parse_command_string(char *src, char **dst) -{ - int opt_status = ARG_EMPTY; - char* tmp_str; - - /* Dumb you, I have nothing to do... */ - if (src == NULL) return src; - - /* Skip leading spaces */ - while (*src == ' ') { - src++; - } - /* Is the end of string reached? */ - if (*src == '\0') { - return NULL; - } - /* Reached the start of an argument - * By the way, we duplicate a little too much - * here but what is too much is freed later. */ - *dst = tmp_str = xstrdup(src); - /* Get to the end of that argument */ - while (*tmp_str != '\0' - && (*tmp_str != ' ' || (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES))) - ) { - switch (*tmp_str) { - case '\'': - if (opt_status & ARG_IN_DQUOTES) { - /* Already in double quotes, keep current char as is */ - } else { - /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ - memmove(tmp_str, tmp_str + 1, strlen(tmp_str)); - /* mark me: we enter or leave single quotes */ - opt_status ^= ARG_IN_SQUOTES; - /* Back one char, as we need to re-scan the new char there. */ - tmp_str--; - } - break; - case '"': - if (opt_status & ARG_IN_SQUOTES) { - /* Already in single quotes, keep current char as is */ - } else { - /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ - memmove(tmp_str, tmp_str + 1, strlen(tmp_str)); - /* mark me: we enter or leave double quotes */ - opt_status ^= ARG_IN_DQUOTES; - /* Back one char, as we need to re-scan the new char there. */ - tmp_str--; - } - break; - case '\\': - if (opt_status & ARG_IN_SQUOTES) { - /* Between single quotes: keep as is. */ - } else { - switch (*(tmp_str+1)) { - case 'a': - case 'b': - case 't': - case 'n': - case 'v': - case 'f': - case 'r': - case '0': - /* We escaped a special character. For now, keep - * both the back-slash and the following char. */ - tmp_str++; - src++; - break; - default: - /* We escaped a space or a single or double quote, - * or a back-slash, or a non-escapable char. Remove - * the '\' and keep the new current char as is. */ - memmove(tmp_str, tmp_str + 1, strlen(tmp_str)); - break; - } - } - break; - /* Any other char that is special shall appear here. - * Example: $ starts a variable - case '$': - do_variable_expansion(); - break; - * */ - default: - /* any other char is kept as is. */ - break; - } - tmp_str++; /* Go to next char */ - src++; /* Go to next char to find the end of the argument. */ - } - /* End of string, but still no ending quote */ - if (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)) { - bb_error_msg_and_die("unterminated (single or double) quote in options list: %s", src); - } - *tmp_str++ = '\0'; - *dst = xrealloc(*dst, (tmp_str - *dst)); - return src; -} -#else -#define parse_command_string(src, dst) (0) -#endif /* ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ - -static int is_conf_command(char *buffer, const char *command) -{ - int len = strlen(command); - return ((strstr(buffer, command) == buffer) && - isspace(buffer[len])); -} - -/* - * This function reads aliases and default module options from a configuration file - * (/etc/modprobe.conf syntax). It supports includes (only files, no directories). - */ - -static int FAST_FUNC include_conf_file_act(const char *filename, - struct stat *statbuf UNUSED_PARAM, - void *userdata, - int depth UNUSED_PARAM); - -static int FAST_FUNC include_conf_dir_act(const char *filename UNUSED_PARAM, - struct stat *statbuf UNUSED_PARAM, - void *userdata UNUSED_PARAM, - int depth) -{ - if (depth > 1) - return SKIP; - - return TRUE; -} - -static int include_conf_recursive(struct include_conf_t *conf, const char *filename, int flags) -{ - return recursive_action(filename, ACTION_RECURSE | flags, - include_conf_file_act, - include_conf_dir_act, - conf, 1); -} - -static int FAST_FUNC include_conf_file_act(const char *filename, - struct stat *statbuf UNUSED_PARAM, - void *userdata, - int depth UNUSED_PARAM) -{ - struct include_conf_t *conf = (struct include_conf_t *) userdata; - struct dep_t **first = &conf->first; - struct dep_t **current = &conf->current; - int continuation_line = 0; - FILE *f; - - if (bb_basename(filename)[0] == '.') - return TRUE; - - f = fopen_for_read(filename); - if (f == NULL) - return FALSE; - - // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)! - - while (fgets(line_buffer, sizeof(line_buffer), f)) { - int l; - - *strchrnul(line_buffer, '#') = '\0'; - - l = strlen(line_buffer); - - while (l && isspace(line_buffer[l-1])) { - line_buffer[l-1] = '\0'; - l--; - } - - if (l == 0) { - continuation_line = 0; - continue; - } - - if (continuation_line) - continue; - - if (is_conf_command(line_buffer, "alias")) { - char *alias, *mod; - - if (parse_tag_value(line_buffer + 6, &alias, &mod)) { - /* handle alias as a module dependent on the aliased module */ - if (!*current) { - (*first) = (*current) = xzalloc(sizeof(struct dep_t)); - } else { - (*current)->m_next = xzalloc(sizeof(struct dep_t)); - (*current) = (*current)->m_next; - } - (*current)->m_name = xstrdup(alias); - (*current)->m_isalias = 1; - - if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) { - /*(*current)->m_depcnt = 0; - done by xzalloc */ - /*(*current)->m_deparr = 0;*/ - } else { - (*current)->m_depcnt = 1; - (*current)->m_deparr = xmalloc(sizeof(char *)); - (*current)->m_deparr[0] = xstrdup(mod); - } - /*(*current)->m_next = NULL; - done by xzalloc */ - } - } else if (is_conf_command(line_buffer, "options")) { - char *mod, *opt; - - /* split the line in the module/alias name, and options */ - if (parse_tag_value(line_buffer + 8, &mod, &opt)) { - struct dep_t *dt; - - /* find the corresponding module */ - for (dt = *first; dt; dt = dt->m_next) { - if (strcmp(dt->m_name, mod) == 0) - break; - } - if (dt) { - if (ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS) { - char* new_opt = NULL; - while ((opt = parse_command_string(opt, &new_opt))) { - dt->m_options = append_option(dt->m_options, new_opt); - } - } else { - dt->m_options = append_option(dt->m_options, opt); - } - } - } - } else if (is_conf_command(line_buffer, "include")) { - char *includefile; - - includefile = skip_whitespace(line_buffer + 8); - include_conf_recursive(conf, includefile, 0); - } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST && - (is_conf_command(line_buffer, "blacklist"))) { - char *mod; - struct dep_t *dt; - - mod = skip_whitespace(line_buffer + 10); - for (dt = *first; dt; dt = dt->m_next) { - if (strcmp(dt->m_name, mod) == 0) - break; - } - if (dt) - dt->m_isblacklisted = 1; - } - } /* while (fgets(...)) */ - - fclose(f); - return TRUE; -} - -static int include_conf_file(struct include_conf_t *conf, - const char *filename) -{ - return include_conf_file_act(filename, NULL, conf, 0); -} - -static int include_conf_file2(struct include_conf_t *conf, - const char *filename, const char *oldname) -{ - if (include_conf_file(conf, filename) == TRUE) - return TRUE; - return include_conf_file(conf, oldname); -} - -/* - * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep. - * It then fills every modules and aliases with their default options, found by parsing - * modprobe.conf (or modules.conf, or conf.modules). - */ -static struct dep_t *build_dep(void) -{ - FILE *f; - struct utsname un; - struct include_conf_t conf = { NULL, NULL }; - char *filename; - int continuation_line = 0; - int k_version; - - uname(&un); /* never fails */ - - k_version = 0; - if (un.release[0] == '2') { - k_version = un.release[2] - '0'; - } - - filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, un.release); - f = fopen_for_read(filename); - if (ENABLE_FEATURE_CLEAN_UP) - free(filename); - if (f == NULL) { - /* Ok, that didn't work. Fall back to looking in /lib/modules */ - f = fopen_for_read(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE); - if (f == NULL) { - bb_error_msg_and_die("cannot parse "CONFIG_DEFAULT_DEPMOD_FILE); - } - } - - while (fgets(line_buffer, sizeof(line_buffer), f)) { - int l = strlen(line_buffer); - char *p = NULL; - - while (l > 0 && isspace(line_buffer[l-1])) { - line_buffer[l-1] = '\0'; - l--; - } - - if (l == 0) { - continuation_line = 0; - continue; - } - - /* Is this a new module dep description? */ - if (!continuation_line) { - /* find the dep beginning */ - char *col = strchr(line_buffer, ':'); - char *dot = col; - - if (col) { - /* This line is a dep description */ - const char *mods; - char *modpath; - char *mod; - - /* Find the beginning of the module file name */ - *col = '\0'; - mods = bb_basename(line_buffer); - - /* find the path of the module */ - modpath = strchr(line_buffer, '/'); /* ... and this is the path */ - if (!modpath) - modpath = line_buffer; /* module with no path */ - /* find the end of the module name in the file name */ - if (ENABLE_FEATURE_2_6_MODULES && - (k_version > 4) && (col[-3] == '.') && - (col[-2] == 'k') && (col[-1] == 'o')) - dot = col - 3; - else if ((col[-2] == '.') && (col[-1] == 'o')) - dot = col - 2; - - mod = xstrndup(mods, dot - mods); - - /* enqueue new module */ - if (!conf.current) { - conf.first = conf.current = xzalloc(sizeof(struct dep_t)); - } else { - conf.current->m_next = xzalloc(sizeof(struct dep_t)); - conf.current = conf.current->m_next; - } - conf.current->m_name = mod; - conf.current->m_path = xstrdup(modpath); - /*current->m_options = NULL; - xzalloc did it*/ - /*current->m_isalias = 0;*/ - /*current->m_depcnt = 0;*/ - /*current->m_deparr = 0;*/ - /*current->m_next = 0;*/ - - p = col + 1; - } else - /* this line is not a dep description */ - p = NULL; - } else - /* It's a dep description continuation */ - p = line_buffer; - - /* p points to the first dependable module; if NULL, no dependable module */ - if (p && (p = skip_whitespace(p))[0] != '\0') { - char *end = &line_buffer[l-1]; - const char *deps; - char *dep; - char *next; - int ext = 0; - - while (isblank(*end) || (*end == '\\')) - end--; - - do { - /* search the end of the dependency */ - next = strchr(p, ' '); - if (next) { - *next = '\0'; - next--; - } else - next = end; - - /* find the beginning of the module file name */ - deps = bb_basename(p); - if (deps == p) - deps = skip_whitespace(deps); - - /* find the end of the module name in the file name */ - if (ENABLE_FEATURE_2_6_MODULES - && (k_version > 4) && (next[-2] == '.') - && (next[-1] == 'k') && (next[0] == 'o')) - ext = 3; - else if ((next[-1] == '.') && (next[0] == 'o')) - ext = 2; - - /* Cope with blank lines */ - if ((next - deps - ext + 1) <= 0) - continue; - dep = xstrndup(deps, next - deps - ext + 1); - - /* Add the new dependable module name */ - conf.current->m_deparr = xrealloc_vector(conf.current->m_deparr, 2, conf.current->m_depcnt); - conf.current->m_deparr[conf.current->m_depcnt++] = dep; - - p = next + 2; - } while (next < end); - } - - /* is there other dependable module(s) ? */ - continuation_line = (line_buffer[l-1] == '\\'); - } /* while (fgets(...)) */ - fclose(f); - - /* - * First parse system-specific options and aliases - * as they take precedence over the kernel ones. - * >=2.6: we only care about modprobe.conf - * <=2.4: we care about modules.conf and conf.modules - */ - { - int r = FALSE; - - if (ENABLE_FEATURE_2_6_MODULES) { - if (include_conf_file(&conf, "/etc/modprobe.conf")) - r = TRUE; - if (include_conf_recursive(&conf, "/etc/modprobe.d", ACTION_QUIET)) - r = TRUE; - } - if (ENABLE_FEATURE_2_4_MODULES && !r) - include_conf_file2(&conf, - "/etc/modules.conf", - "/etc/conf.modules"); - } - - /* Only 2.6 has a modules.alias file */ - if (ENABLE_FEATURE_2_6_MODULES) { - /* Parse kernel-declared module aliases */ - filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release); - include_conf_file2(&conf, - filename, - CONFIG_DEFAULT_MODULES_DIR"/modules.alias"); - if (ENABLE_FEATURE_CLEAN_UP) - free(filename); - - /* Parse kernel-declared symbol aliases */ - filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release); - include_conf_file2(&conf, - filename, - CONFIG_DEFAULT_MODULES_DIR"/modules.symbols"); - if (ENABLE_FEATURE_CLEAN_UP) - free(filename); - } - - return conf.first; -} - -/* return 1 = loaded, 0 = not loaded, -1 = can't tell */ -static int already_loaded(const char *name) -{ - FILE *f; - int ret; - - f = fopen_for_read("/proc/modules"); - if (f == NULL) - return -1; - - ret = 0; - while (fgets(line_buffer, sizeof(line_buffer), f)) { - char *p = line_buffer; - const char *n = name; - - while (1) { - char cn = *n; - char cp = *p; - if (cp == ' ' || cp == '\0') { - if (cn == '\0') { - ret = 1; /* match! */ - goto done; - } - break; /* no match on this line, take next one */ - } - if (cn == '-') cn = '_'; - if (cp == '-') cp = '_'; - if (cp != cn) - break; /* no match on this line, take next one */ - n++; - p++; - } - } - done: - fclose(f); - return ret; -} - -static int mod_process(const struct mod_list_t *list, int do_insert) -{ - int rc = 0; - char **argv = NULL; - struct mod_opt_t *opts; - int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */ - int argc; - - while (list) { - argc = 0; - if (ENABLE_FEATURE_CLEAN_UP) - argc_malloc = 0; - /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory - * each time we allocate memory for argv. - * But it is (quite) small amounts of memory that leak each - * time a module is loaded, and it is reclaimed when modprobe - * exits anyway (even when standalone shell? Yes --vda). - * This could become a problem when loading a module with LOTS of - * dependencies, with LOTS of options for each dependencies, with - * very little memory on the target... But in that case, the module - * would not load because there is no more memory, so there's no - * problem. */ - /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */ - argv = xmalloc(6 * sizeof(char*)); - if (do_insert) { - if (already_loaded(list->m_name) != 1) { - argv[argc++] = (char*)"insmod"; - if (ENABLE_FEATURE_2_4_MODULES) { - if (do_syslog) - argv[argc++] = (char*)"-s"; - if (autoclean) - argv[argc++] = (char*)"-k"; - if (quiet) - argv[argc++] = (char*)"-q"; - else if (verbose) /* verbose and quiet are mutually exclusive */ - argv[argc++] = (char*)"-v"; - } - argv[argc++] = list->m_path; - if (ENABLE_FEATURE_CLEAN_UP) - argc_malloc = argc; - opts = list->m_options; - while (opts) { - /* Add one more option */ - argc++; - argv = xrealloc(argv, (argc + 1) * sizeof(char*)); - argv[argc-1] = opts->m_opt_val; - opts = opts->m_next; - } - } - } else { - /* modutils uses short name for removal */ - if (already_loaded(list->m_name) != 0) { - argv[argc++] = (char*)"rmmod"; - if (do_syslog) - argv[argc++] = (char*)"-s"; - argv[argc++] = (char*)list->m_name; - if (ENABLE_FEATURE_CLEAN_UP) - argc_malloc = argc; - } - } - argv[argc] = NULL; - - if (argc) { - if (verbose) { - printf("%s module %s\n", do_insert?"Loading":"Unloading", list->m_name); - } - if (!show_only) { - int rc2 = wait4pid(spawn(argv)); - - if (do_insert) { - rc = rc2; /* only last module matters */ - } else if (!rc2) { - rc = 0; /* success if remove any mod */ - } - } - if (ENABLE_FEATURE_CLEAN_UP) { - /* the last value in the array has index == argc, but - * it is the terminating NULL, so we must not free it. */ - while (argc_malloc < argc) { - free(argv[argc_malloc++]); - } - } - } - if (ENABLE_FEATURE_CLEAN_UP) { - free(argv); - argv = NULL; - } - list = do_insert ? list->m_prev : list->m_next; - } - return (show_only) ? 0 : rc; -} - -/* - * Check the matching between a pattern and a module name. - * We need this as *_* is equivalent to *-*, even in pattern matching. - */ -static int check_pattern(const char* pat_src, const char* mod_src) -{ - int ret; - - if (ENABLE_FEATURE_MODPROBE_FANCY_ALIAS) { - char* pat; - char* mod; - char* p; - - pat = xstrdup(pat_src); - mod = xstrdup(mod_src); - - for (p = pat; (p = strchr(p, '-')); *p++ = '_'); - for (p = mod; (p = strchr(p, '-')); *p++ = '_'); - - ret = fnmatch(pat, mod, 0); - - if (ENABLE_FEATURE_CLEAN_UP) { - free(pat); - free(mod); - } - - return ret; - } - return fnmatch(pat_src, mod_src, 0); -} - -/* - * Builds the dependency list (aka stack) of a module. - * head: the highest module in the stack (last to insmod, first to rmmod) - * tail: the lowest module in the stack (first to insmod, last to rmmod) - */ -static void check_dep(char *mod, struct mod_list_t **head, struct mod_list_t **tail) -{ - struct mod_list_t *find; - struct dep_t *dt; - struct mod_opt_t *opt = NULL; - char *path = NULL; - - /* Search for the given module name amongst all dependency rules. - * The module name in a dependency rule can be a shell pattern, - * so try to match the given module name against such a pattern. - * Of course if the name in the dependency rule is a plain string, - * then we consider it a pattern, and matching will still work. */ - for (dt = depend; dt; dt = dt->m_next) { - if (check_pattern(dt->m_name, mod) == 0) { - break; - } - } - - if (!dt) { - bb_error_msg("module %s not found", mod); - return; - } - - // resolve alias names - while (dt->m_isalias) { - if (dt->m_depcnt == 1) { - struct dep_t *adt; - - for (adt = depend; adt; adt = adt->m_next) { - if (check_pattern(adt->m_name, dt->m_deparr[0]) == 0 && - !(ENABLE_FEATURE_MODPROBE_BLACKLIST && - adt->m_isblacklisted)) - break; - } - if (adt) { - /* This is the module we are aliased to */ - struct mod_opt_t *opts = dt->m_options; - /* Option of the alias are appended to the options of the module */ - while (opts) { - adt->m_options = append_option(adt->m_options, opts->m_opt_val); - opts = opts->m_next; - } - dt = adt; - } else { - bb_error_msg("module %s not found", mod); - return; - } - } else { - bb_error_msg("bad alias %s", dt->m_name); - return; - } - } - - mod = dt->m_name; - path = dt->m_path; - opt = dt->m_options; - - // search for duplicates - for (find = *head; find; find = find->m_next) { - if (strcmp(mod, find->m_name) == 0) { - // found -> dequeue it - - if (find->m_prev) - find->m_prev->m_next = find->m_next; - else - *head = find->m_next; - - if (find->m_next) - find->m_next->m_prev = find->m_prev; - else - *tail = find->m_prev; - - break; // there can be only one duplicate - } - } - - if (!find) { // did not find a duplicate - find = xzalloc(sizeof(struct mod_list_t)); - find->m_name = mod; - find->m_path = path; - find->m_options = opt; - } - - // enqueue at tail - if (*tail) - (*tail)->m_next = find; - find->m_prev = *tail; - find->m_next = NULL; /* possibly NOT done by xzalloc! */ - - if (!*head) - *head = find; - *tail = find; - - if (dt) { - int i; - - /* Add all dependable module for that new module */ - for (i = 0; i < dt->m_depcnt; i++) - check_dep(dt->m_deparr[i], head, tail); - } -} - -static int mod_insert(char **argv) -{ - struct mod_list_t *tail = NULL; - struct mod_list_t *head = NULL; - char *modname = *argv++; - int rc; - - // get dep list for module mod - check_dep(modname, &head, &tail); - - rc = 1; - if (head && tail) { - while (*argv) - head->m_options = append_option(head->m_options, *argv++); - - // process tail ---> head - rc = mod_process(tail, 1); - if (rc) { - /* - * In case of using udev, multiple instances of modprobe can be - * spawned to load the same module (think of two same usb devices, - * for example; or cold-plugging at boot time). Thus we shouldn't - * fail if the module was loaded, and not by us. - */ - if (already_loaded(modname)) - rc = 0; - } - } - return rc; -} - -static int mod_remove(char *modname) -{ - static const struct mod_list_t rm_a_dummy = { "-a", NULL, NULL, NULL, NULL }; - - int rc; - struct mod_list_t *head = NULL; - struct mod_list_t *tail = NULL; - - if (modname) - check_dep(modname, &head, &tail); - else // autoclean - head = tail = (struct mod_list_t*) &rm_a_dummy; - - rc = 1; - if (head && tail) - rc = mod_process(head, 0); // process head ---> tail - return rc; -} - -int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int modprobe_main(int argc UNUSED_PARAM, char **argv) -{ - int rc = EXIT_SUCCESS; - unsigned opt; - char *unused; - - opt_complementary = "q-v:v-q"; - opt = getopt32(argv, MAIN_OPT_STR, &unused, &unused); - argv += optind; - - if (opt & (DUMP_CONF_EXIT | LIST_ALL)) - return EXIT_SUCCESS; - if (opt & (RESTRICT_DIR | CONFIG_FILE)) - bb_error_msg_and_die("-t and -C not supported"); - - depend = build_dep(); - - if (!depend) - bb_error_msg_and_die("cannot parse "CONFIG_DEFAULT_DEPMOD_FILE); - - if (remove_opt) { - do { - /* (*argv) can be NULL here */ - if (mod_remove(*argv)) { - bb_perror_msg("failed to %s module %s", "remove", - *argv); - rc = EXIT_FAILURE; - } - } while (*argv && *++argv); - } else { - if (!*argv) - bb_error_msg_and_die("no module or pattern provided"); - - if (mod_insert(argv)) - bb_perror_msg_and_die("failed to %s module %s", "load", *argv); - } - - /* Here would be a good place to free up memory allocated during the dependencies build. */ - - return rc; -} +/* vi: set sw=4 ts=4: */ +/* + * Modprobe written from scratch for BusyBox + * + * Copyright (c) 2008 Timo Teras + * Copyright (c) 2008 Vladimir Dronnikov + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "modutils.h" +#include +#include + +//#define DBG(...) bb_error_msg(__VA_ARGS__) +#define DBG(...) ((void)0) + +#define MODULE_FLAG_LOADED 0x0001 +#define MODULE_FLAG_NEED_DEPS 0x0002 +/* "was seen in modules.dep": */ +#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 +#define MODULE_FLAG_BLACKLISTED 0x0008 + +struct module_entry { /* I'll call it ME. */ + unsigned flags; + char *modname; /* stripped of /path/, .ext and s/-/_/g */ + const char *probed_name; /* verbatim as seen on cmdline */ + char *options; /* options from config files */ + llist_t *realnames; /* strings. if this module is an alias, */ + /* real module name is one of these. */ +//Can there really be more than one? Example from real kernel? + llist_t *deps; /* strings. modules we depend on */ +}; + +#define MODPROBE_OPTS "acdlnrt:VC:" USE_FEATURE_MODPROBE_BLACKLIST("b") +enum { + MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ + MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */ + MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */ + MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */ + MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */ + MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */ + MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */ + MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */ + MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */ + MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST, +}; + +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; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) + + +static int read_config(const char *path); + +static char *gather_options_str(char *opts, const char *append) +{ + /* Speed-optimized. We call gather_options_str many times. */ + if (opts == NULL) { + opts = xstrdup(append); + } else { + int optlen = strlen(opts); + opts = xrealloc(opts, optlen + strlen(append) + 2); + sprintf(opts + optlen, " %s", append); + } + return opts; +} + +static struct module_entry *helper_get_module(const char *module, int create) +{ + char modname[MODULE_NAME_LEN]; + struct module_entry *e; + llist_t *l; + + filename2modname(module, modname); + for (l = G.db; l != NULL; l = l->link) { + e = (struct module_entry *) l->data; + if (strcmp(e->modname, modname) == 0) + return e; + } + if (!create) + return NULL; + + e = xzalloc(sizeof(*e)); + e->modname = xstrdup(modname); + llist_add_to(&G.db, e); + + return e; +} +static 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) +{ + return helper_get_module(module, 0); +} + +static void add_probe(const char *name) +{ + struct module_entry *m; + + m = get_or_add_modentry(name); + if (m->flags & MODULE_FLAG_LOADED) { + DBG("skipping %s, it is already loaded", name); + return; + } + + m->probed_name = name; + m->flags |= MODULE_FLAG_NEED_DEPS; + llist_add_to_end(&G.probes, m); + G.num_unresolved_deps++; + if (ENABLE_FEATURE_MODUTILS_SYMBOLS + && strncmp(m->modname, "symbol:", 7) == 0 + ) { + G.need_symbols = 1; + } +} + +static int FAST_FUNC config_file_action(const char *filename, + struct stat *statbuf UNUSED_PARAM, + void *userdata UNUSED_PARAM, + int depth UNUSED_PARAM) +{ + char *tokens[3]; + parser_t *p; + struct module_entry *m; + int rc = TRUE; + + if (bb_basename(filename)[0] == '.') + goto error; + + p = config_open2(filename, fopen_for_read); + if (p == NULL) { + rc = FALSE; + goto error; + } + + while (config_read(p, tokens, 3, 2, "# \t", PARSE_NORMAL)) { +//Use index_in_strings? + if (strcmp(tokens[0], "alias") == 0) { + /* alias */ + llist_t *l; + char wildcard[MODULE_NAME_LEN]; + char *rmod; + + if (tokens[2] == NULL) + continue; + filename2modname(tokens[1], wildcard); + + for (l = G.probes; l != NULL; l = l->link) { + m = (struct module_entry *) l->data; + if (fnmatch(wildcard, m->modname, 0) != 0) + continue; + rmod = filename2modname(tokens[2], NULL); + llist_add_to(&m->realnames, rmod); + + if (m->flags & MODULE_FLAG_NEED_DEPS) { + m->flags &= ~MODULE_FLAG_NEED_DEPS; + G.num_unresolved_deps--; + } + + m = get_or_add_modentry(rmod); + if (!(m->flags & MODULE_FLAG_NEED_DEPS)) { + m->flags |= MODULE_FLAG_NEED_DEPS; + G.num_unresolved_deps++; + } + } + } else if (strcmp(tokens[0], "options") == 0) { + /* options */ + if (tokens[2] == NULL) + continue; + m = get_or_add_modentry(tokens[1]); + m->options = gather_options_str(m->options, tokens[2]); + } else if (strcmp(tokens[0], "include") == 0) { + /* include */ + read_config(tokens[1]); + } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST + && strcmp(tokens[0], "blacklist") == 0 + ) { + /* blacklist */ + get_or_add_modentry(tokens[1])->flags |= MODULE_FLAG_BLACKLISTED; + } + } + config_close(p); +error: + return rc; +} + +static int read_config(const char *path) +{ + return recursive_action(path, ACTION_RECURSE | ACTION_QUIET, + config_file_action, NULL, NULL, 1); +} + +static int do_modprobe(struct module_entry *m) +{ + struct module_entry *m2; + char *fn, *options; + int rc = -1; + + if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { + DBG("skipping %s, not found in modules.dep", m->modname); + return -ENOENT; + } + DBG("do_modprob'ing %s", m->modname); + + if (!(option_mask32 & MODPROBE_OPT_REMOVE)) + m->deps = llist_rev(m->deps); + + rc = 0; + while (m->deps && rc == 0) { + fn = llist_pop(&m->deps); + m2 = get_or_add_modentry(fn); + if (option_mask32 & MODPROBE_OPT_REMOVE) { + if (bb_delete_module(m->modname, O_EXCL) != 0) + rc = errno; + } else if (!(m2->flags & MODULE_FLAG_LOADED)) { + options = m2->options; + m2->options = NULL; + if (m == m2) + options = gather_options_str(options, G.cmdline_mopts); + rc = bb_init_module(fn, options); + DBG("loaded %s '%s', rc:%d", fn, options, rc); + if (rc == 0) + m2->flags |= MODULE_FLAG_LOADED; + free(options); + } else { + DBG("%s is already loaded, skipping", fn); + } + + free(fn); + } + +//FIXME: what if rc < 0? + if (rc > 0 && !(option_mask32 & INSMOD_OPT_SILENT)) { + bb_error_msg("failed to %sload module %s: %s", + (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", + m->probed_name ? m->probed_name : m->modname, + moderror(rc) + ); + } + + return rc; +} + +static void load_modules_dep(void) +{ + struct module_entry *m; + char *colon, *tokens[2]; + parser_t *p; + + /* Modprobe does not work at all without modprobe.dep, + * even if the full module name is given. Returning error here + * was making us later confuse user with this message: + * "module /full/path/to/existing/file/module.ko not found". + * It's better to die immediately, with good message. + * xfopen_for_read provides that. */ + p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); + + while (G.num_unresolved_deps + && config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL) + ) { + colon = last_char_is(tokens[0], ':'); + if (colon == NULL) + continue; + *colon = 0; + + m = get_modentry(tokens[0]); + if (m == NULL) + continue; + + /* Optimization... */ + if ((m->flags & MODULE_FLAG_LOADED) + && !(option_mask32 & MODPROBE_OPT_REMOVE) + ) { + DBG("skip deps of %s, it's already loaded", tokens[0]); + continue; + } + + m->flags |= MODULE_FLAG_FOUND_IN_MODDEP; + if ((m->flags & MODULE_FLAG_NEED_DEPS) && (m->deps == NULL)) { + G.num_unresolved_deps--; + llist_add_to(&m->deps, xstrdup(tokens[0])); + if (tokens[1]) + string_to_llist(tokens[1], &m->deps, " "); + } + } + config_close(p); +} + +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; + + opt_complementary = "q-v:v-q"; + opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS, NULL, NULL); + argv += optind; + + if (opt & (MODPROBE_OPT_DUMP_ONLY | MODPROBE_OPT_LIST_ONLY | + MODPROBE_OPT_SHOW_ONLY)) + bb_error_msg_and_die("not supported"); + + if (!argv[0]) { + if (opt & MODPROBE_OPT_REMOVE) { + /* "modprobe -r" (w/o params). + * "If name is NULL, all unused modules marked + * autoclean will be removed". + */ + if (bb_delete_module(NULL, O_NONBLOCK|O_EXCL) != 0) + bb_perror_msg_and_die("rmmod"); + } + return EXIT_SUCCESS; + } + + /* Goto modules location */ + xchdir(CONFIG_DEFAULT_MODULES_DIR); + uname(&uts); + xchdir(uts.release); + + /* Retrieve module names of already loaded modules */ + { + char *s; + parser_t *parser = config_open2("/proc/modules", fopen_for_read); + while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) + get_or_add_modentry(s)->flags |= MODULE_FLAG_LOADED; + config_close(parser); + } + + if (opt & MODPROBE_OPT_INSERT_ALL) { + /* Each argument is a module name */ + do { + add_probe(*argv++); + } while (*argv); + } else { + /* First argument is module name, rest are parameters */ + add_probe(argv[0]); + G.cmdline_mopts = parse_cmdline_module_options(argv); + } + + /* Happens if all requested modules are already loaded */ + if (G.probes == NULL) + return EXIT_SUCCESS; + + read_config("/etc/modprobe.conf"); + read_config("/etc/modprobe.d"); + if (ENABLE_FEATURE_MODUTILS_SYMBOLS && G.need_symbols) + read_config("modules.symbols"); + load_modules_dep(); + if (ENABLE_FEATURE_MODUTILS_ALIAS && G.num_unresolved_deps) { + read_config("modules.alias"); + load_modules_dep(); + } + + while ((me = llist_pop(&G.probes)) != NULL) { + if (me->realnames == NULL) { + /* This is not an alias. Literal names are blacklisted + * only if '-b' is given. + */ + if (!(opt & MODPROBE_OPT_BLACKLIST) + || !(me->flags & MODULE_FLAG_BLACKLISTED) + ) { + rc = do_modprobe(me); +//FIXME: what if rc > 0? + if (rc < 0 && !(opt & INSMOD_OPT_SILENT)) + bb_error_msg("module %s not found", + me->probed_name); + } + } else { + /* Probe all realnames */ + do { + char *realname = llist_pop(&me->realnames); + struct module_entry *m2; + + DBG("probing %s by realname %s", me->modname, realname); + m2 = get_or_add_modentry(realname); + if (!(m2->flags & MODULE_FLAG_BLACKLISTED)) + do_modprobe(m2); +//FIXME: error check? + free(realname); + } while (me->realnames != NULL); + } + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/modutils/modutils-24.c b/release/src/router/busybox/modutils/modutils-24.c new file mode 100644 index 0000000000..a16cb1bbe3 --- /dev/null +++ b/release/src/router/busybox/modutils/modutils-24.c @@ -0,0 +1,3905 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini insmod implementation for busybox + * + * This version of insmod supports ARM, CRIS, H8/300, x86, ia64, x86_64, + * m68k, MIPS, PowerPC, S390, SH3/4/5, Sparc, v850e, and x86_64. + * + * Copyright (C) 1999-2004 by Erik Andersen + * and Ron Alder + * + * Rodney Radford 17-Aug-2004. + * Added x86_64 support. + * + * Miles Bader added NEC V850E support. + * + * Modified by Bryan Rittmeyer to support SH4 + * and (theoretically) SH3. I have only tested SH4 in little endian mode. + * + * Modified by Alcove, Julien Gaulmin and + * Nicolas Ferre to support ARM7TDMI. Only + * very minor changes required to also work with StrongArm and presumably + * all ARM based systems. + * + * Yoshinori Sato 19-May-2004. + * added Renesas H8/300 support. + * + * Paul Mundt 08-Aug-2003. + * Integrated support for sh64 (SH-5), from preliminary modutils + * patches from Benedict Gaster . + * Currently limited to support for 32bit ABI. + * + * Magnus Damm 22-May-2002. + * The plt and got code are now using the same structs. + * Added generic linked list code to fully support PowerPC. + * Replaced the mess in arch_apply_relocation() with architecture blocks. + * The arch_create_got() function got cleaned up with architecture blocks. + * These blocks should be easy maintain and sync with obj_xxx.c in modutils. + * + * Magnus Damm added PowerPC support 20-Feb-2001. + * PowerPC specific code stolen from modutils-2.3.16, + * written by Paul Mackerras, Copyright 1996, 1997 Linux International. + * I've only tested the code on mpc8xx platforms in big-endian mode. + * Did some cleanup and added USE_xxx_ENTRIES... + * + * Quinn Jensen added MIPS support 23-Feb-2001. + * based on modutils-2.4.2 + * MIPS specific support for Elf loading and relocation. + * Copyright 1996, 1997 Linux International. + * Contributed by Ralf Baechle + * + * Based almost entirely on the Linux modutils-2.3.11 implementation. + * Copyright 1996, 1997 Linux International. + * New implementation contributed by Richard Henderson + * Based on original work by Bjorn Ekwall + * Restructured (and partly rewritten) by: + * Björn Ekwall February 1999 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "modutils.h" +#include +#include + +#if ENABLE_FEATURE_INSMOD_LOADINKMEM +#define LOADBITS 0 +#else +#define LOADBITS 1 +#endif + +/* Alpha */ +#if defined(__alpha__) +#define MATCH_MACHINE(x) (x == EM_ALPHA) +#define SHT_RELM SHT_RELA +#define Elf64_RelM Elf64_Rela +#define ELFCLASSM ELFCLASS64 +#endif + +/* ARM support */ +#if defined(__arm__) +#define MATCH_MACHINE(x) (x == EM_ARM) +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +#define USE_PLT_ENTRIES +#define PLT_ENTRY_SIZE 8 +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 8 +#define USE_SINGLE +#endif + +/* blackfin */ +#if defined(BFIN) +#define MATCH_MACHINE(x) (x == EM_BLACKFIN) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + +/* CRIS */ +#if defined(__cris__) +#define MATCH_MACHINE(x) (x == EM_CRIS) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#ifndef EM_CRIS +#define EM_CRIS 76 +#define R_CRIS_NONE 0 +#define R_CRIS_32 3 +#endif +#endif + +/* H8/300 */ +#if defined(__H8300H__) || defined(__H8300S__) +#define MATCH_MACHINE(x) (x == EM_H8_300) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_SINGLE +#define SYMBOL_PREFIX "_" +#endif + +/* PA-RISC / HP-PA */ +#if defined(__hppa__) +#define MATCH_MACHINE(x) (x == EM_PARISC) +#define SHT_RELM SHT_RELA +#if defined(__LP64__) +#define Elf64_RelM Elf64_Rela +#define ELFCLASSM ELFCLASS64 +#else +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif +#endif + +/* x86 */ +#if defined(__i386__) +#ifndef EM_486 +#define MATCH_MACHINE(x) (x == EM_386) +#else +#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) +#endif +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 4 +#define USE_SINGLE +#endif + +/* IA64, aka Itanium */ +#if defined(__ia64__) +#define MATCH_MACHINE(x) (x == EM_IA_64) +#define SHT_RELM SHT_RELA +#define Elf64_RelM Elf64_Rela +#define ELFCLASSM ELFCLASS64 +#endif + +/* m68k */ +#if defined(__mc68000__) +#define MATCH_MACHINE(x) (x == EM_68K) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 4 +#define USE_SINGLE +#endif + +/* Microblaze */ +#if defined(__microblaze__) +#define USE_SINGLE +#include +#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + +/* MIPS */ +#if defined(__mips__) +#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +/* Account for ELF spec changes. */ +#ifndef EM_MIPS_RS3_LE +#ifdef EM_MIPS_RS4_BE +#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE +#else +#define EM_MIPS_RS3_LE 10 +#endif +#endif /* !EM_MIPS_RS3_LE */ +#define ARCHDATAM "__dbe_table" +#endif + +/* Nios II */ +#if defined(__nios2__) +#define MATCH_MACHINE(x) (x == EM_ALTERA_NIOS2) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + +/* PowerPC */ +#if defined(__powerpc64__) +#define MATCH_MACHINE(x) (x == EM_PPC64) +#define SHT_RELM SHT_RELA +#define Elf64_RelM Elf64_Rela +#define ELFCLASSM ELFCLASS64 +#elif defined(__powerpc__) +#define MATCH_MACHINE(x) (x == EM_PPC) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_PLT_ENTRIES +#define PLT_ENTRY_SIZE 16 +#define USE_PLT_LIST +#define LIST_ARCHTYPE ElfW(Addr) +#define USE_LIST +#define ARCHDATAM "__ftr_fixup" +#endif + +/* S390 */ +#if defined(__s390__) +#define MATCH_MACHINE(x) (x == EM_S390) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_PLT_ENTRIES +#define PLT_ENTRY_SIZE 8 +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 8 +#define USE_SINGLE +#endif + +/* SuperH */ +#if defined(__sh__) +#define MATCH_MACHINE(x) (x == EM_SH) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 4 +#define USE_SINGLE +/* the SH changes have only been tested in =little endian= mode */ +/* I'm not sure about big endian, so let's warn: */ +#if defined(__sh__) && BB_BIG_ENDIAN +# error insmod.c may require changes for use on big endian SH +#endif +/* it may or may not work on the SH1/SH2... Error on those also */ +#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && (defined(__sh__)) +#error insmod.c may require changes for SH1 or SH2 use +#endif +#endif + +/* Sparc */ +#if defined(__sparc__) +#define MATCH_MACHINE(x) (x == EM_SPARC) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + +/* v850e */ +#if defined(__v850e__) +#define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define USE_PLT_ENTRIES +#define PLT_ENTRY_SIZE 8 +#define USE_SINGLE +#ifndef EM_CYGNUS_V850 /* grumble */ +#define EM_CYGNUS_V850 0x9080 +#endif +#define SYMBOL_PREFIX "_" +#endif + +/* X86_64 */ +#if defined(__x86_64__) +#define MATCH_MACHINE(x) (x == EM_X86_64) +#define SHT_RELM SHT_RELA +#define USE_GOT_ENTRIES +#define GOT_ENTRY_SIZE 8 +#define USE_SINGLE +#define Elf64_RelM Elf64_Rela +#define ELFCLASSM ELFCLASS64 +#endif + +#ifndef SHT_RELM +#error Sorry, but insmod.c does not yet support this architecture... +#endif + + +//---------------------------------------------------------------------------- +//--------modutils module.h, lines 45-242 +//---------------------------------------------------------------------------- + +/* Definitions for the Linux module syscall interface. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef MODUTILS_MODULE_H + +/*======================================================================*/ +/* For sizeof() which are related to the module platform and not to the + environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ + +#define tgt_sizeof_char sizeof(char) +#define tgt_sizeof_short sizeof(short) +#define tgt_sizeof_int sizeof(int) +#define tgt_sizeof_long sizeof(long) +#define tgt_sizeof_char_p sizeof(char *) +#define tgt_sizeof_void_p sizeof(void *) +#define tgt_long long + +#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) +#undef tgt_sizeof_long +#undef tgt_sizeof_char_p +#undef tgt_sizeof_void_p +#undef tgt_long +enum { + tgt_sizeof_long = 8, + tgt_sizeof_char_p = 8, + tgt_sizeof_void_p = 8 +}; +#define tgt_long long long +#endif + +/*======================================================================*/ +/* The structures used in Linux 2.1. */ + +/* Note: new_module_symbol does not use tgt_long intentionally */ +struct new_module_symbol { + unsigned long value; + unsigned long name; +}; + +struct new_module_persist; + +struct new_module_ref { + unsigned tgt_long dep; /* kernel addresses */ + unsigned tgt_long ref; + unsigned tgt_long next_ref; +}; + +struct new_module { + unsigned tgt_long size_of_struct; /* == sizeof(module) */ + unsigned tgt_long next; + unsigned tgt_long name; + unsigned tgt_long size; + + tgt_long usecount; + unsigned tgt_long flags; /* AUTOCLEAN et al */ + + unsigned nsyms; + unsigned ndeps; + + unsigned tgt_long syms; + unsigned tgt_long deps; + unsigned tgt_long refs; + unsigned tgt_long init; + unsigned tgt_long cleanup; + unsigned tgt_long ex_table_start; + unsigned tgt_long ex_table_end; +#ifdef __alpha__ + unsigned tgt_long gp; +#endif + /* Everything after here is extension. */ + unsigned tgt_long persist_start; + unsigned tgt_long persist_end; + unsigned tgt_long can_unload; + unsigned tgt_long runsize; + const char *kallsyms_start; /* All symbols for kernel debugging */ + const char *kallsyms_end; + const char *archdata_start; /* arch specific data for module */ + const char *archdata_end; + const char *kernel_data; /* Reserved for kernel internal use */ +}; + +#ifdef ARCHDATAM +#define ARCHDATA_SEC_NAME ARCHDATAM +#else +#define ARCHDATA_SEC_NAME "__archdata" +#endif +#define KALLSYMS_SEC_NAME "__kallsyms" + + +struct new_module_info { + unsigned long addr; + unsigned long size; + unsigned long flags; + long usecount; +}; + +/* Bits of module.flags. */ +enum { + NEW_MOD_RUNNING = 1, + NEW_MOD_DELETED = 2, + NEW_MOD_AUTOCLEAN = 4, + NEW_MOD_VISITED = 8, + NEW_MOD_USED_ONCE = 16 +}; + +int init_module(const char *name, const struct new_module *); +int query_module(const char *name, int which, void *buf, + size_t bufsize, size_t *ret); + +/* Values for query_module's which. */ +enum { + QM_MODULES = 1, + QM_DEPS = 2, + QM_REFS = 3, + QM_SYMBOLS = 4, + QM_INFO = 5 +}; + +/*======================================================================*/ +/* The system calls unchanged between 2.0 and 2.1. */ + +unsigned long create_module(const char *, size_t); +int delete_module(const char *module, unsigned int flags); + + +#endif /* module.h */ + +//---------------------------------------------------------------------------- +//--------end of modutils module.h +//---------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------- +//--------modutils obj.h, lines 253-462 +//---------------------------------------------------------------------------- + +/* Elf object file loading and relocation routines. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef MODUTILS_OBJ_H + +/* The relocatable object is manipulated using elfin types. */ + +#include +#include + +#ifndef ElfW +# if ELFCLASSM == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +/* For some reason this is missing from some ancient C libraries.... */ +#ifndef ELF32_ST_INFO +# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +#ifndef ELF64_ST_INFO +# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +#define ELF_ST_BIND(info) ELFW(ST_BIND)(info) +#define ELF_ST_TYPE(info) ELFW(ST_TYPE)(info) +#define ELF_ST_INFO(bind, type) ELFW(ST_INFO)(bind, type) +#define ELF_R_TYPE(val) ELFW(R_TYPE)(val) +#define ELF_R_SYM(val) ELFW(R_SYM)(val) + +struct obj_string_patch; +struct obj_symbol_patch; + +struct obj_section +{ + ElfW(Shdr) header; + const char *name; + char *contents; + struct obj_section *load_next; + int idx; +}; + +struct obj_symbol +{ + struct obj_symbol *next; /* hash table link */ + const char *name; + unsigned long value; + unsigned long size; + int secidx; /* the defining section index/module */ + int info; + int ksymidx; /* for export to the kernel symtab */ + int referenced; /* actually used in the link */ +}; + +/* Hardcode the hash table size. We shouldn't be needing so many + symbols that we begin to degrade performance, and we get a big win + by giving the compiler a constant divisor. */ + +#define HASH_BUCKETS 521 + +struct obj_file { + ElfW(Ehdr) header; + ElfW(Addr) baseaddr; + struct obj_section **sections; + struct obj_section *load_order; + struct obj_section **load_order_search_start; + struct obj_string_patch *string_patches; + struct obj_symbol_patch *symbol_patches; + int (*symbol_cmp)(const char *, const char *); + unsigned long (*symbol_hash)(const char *); + unsigned long local_symtab_size; + struct obj_symbol **local_symtab; + struct obj_symbol *symtab[HASH_BUCKETS]; +}; + +enum obj_reloc { + obj_reloc_ok, + obj_reloc_overflow, + obj_reloc_dangerous, + obj_reloc_unhandled +}; + +struct obj_string_patch { + struct obj_string_patch *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + ElfW(Addr) string_offset; +}; + +struct obj_symbol_patch { + struct obj_symbol_patch *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + struct obj_symbol *sym; +}; + + +/* Generic object manipulation routines. */ + +static unsigned long obj_elf_hash(const char *); + +static unsigned long obj_elf_hash_n(const char *, unsigned long len); + +static struct obj_symbol *obj_find_symbol(struct obj_file *f, + const char *name); + +static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, + struct obj_symbol *sym); + +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING +static void obj_set_symbol_compare(struct obj_file *f, + int (*cmp)(const char *, const char *), + unsigned long (*hash)(const char *)); +#endif + +static struct obj_section *obj_find_section(struct obj_file *f, + const char *name); + +static void obj_insert_section_load_order(struct obj_file *f, + struct obj_section *sec); + +static struct obj_section *obj_create_alloced_section(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size); + +static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size); + +static void *obj_extend_section(struct obj_section *sec, unsigned long more); + +static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + const char *string); + +static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + struct obj_symbol *sym); + +static void obj_check_undefineds(struct obj_file *f); + +static void obj_allocate_commons(struct obj_file *f); + +static unsigned long obj_load_size(struct obj_file *f); + +static int obj_relocate(struct obj_file *f, ElfW(Addr) base); + +#if !LOADBITS +#define obj_load(image, image_size, loadprogbits) \ + obj_load(image, image_size) +#endif +static struct obj_file *obj_load(char *image, size_t image_size, int loadprogbits); + +static int obj_create_image(struct obj_file *f, char *image); + +/* Architecture specific manipulation routines. */ + +static struct obj_file *arch_new_file(void); + +static struct obj_section *arch_new_section(void); + +static struct obj_symbol *arch_new_symbol(void); + +static enum obj_reloc arch_apply_relocation(struct obj_file *f, + struct obj_section *targsec, + /*struct obj_section *symsec,*/ + struct obj_symbol *sym, + ElfW(RelM) *rel, ElfW(Addr) value); + +static void arch_create_got(struct obj_file *f); +#if ENABLE_FEATURE_CHECK_TAINTED_MODULE +static int obj_gpl_license(struct obj_file *f, const char **license); +#endif +#endif /* obj.h */ +//---------------------------------------------------------------------------- +//--------end of modutils obj.h +//---------------------------------------------------------------------------- + + +/* SPFX is always a string, so it can be concatenated to string constants. */ +#ifdef SYMBOL_PREFIX +#define SPFX SYMBOL_PREFIX +#else +#define SPFX "" +#endif + +enum { STRVERSIONLEN = 64 }; + +/*======================================================================*/ + +#define flag_force_load (option_mask32 & INSMOD_OPT_FORCE) +#define flag_autoclean (option_mask32 & INSMOD_OPT_KERNELD) +#define flag_verbose (option_mask32 & INSMOD_OPT_VERBOSE) +#define flag_quiet (option_mask32 & INSMOD_OPT_SILENT) +#define flag_noexport (option_mask32 & INSMOD_OPT_NO_EXPORT) +#define flag_print_load_map (option_mask32 & INSMOD_OPT_PRINT_MAP) + +/*======================================================================*/ + +#if defined(USE_LIST) + +struct arch_list_entry +{ + struct arch_list_entry *next; + LIST_ARCHTYPE addend; + int offset; + int inited : 1; +}; + +#endif + +#if defined(USE_SINGLE) + +struct arch_single_entry +{ + int offset; + int inited : 1; + int allocated : 1; +}; + +#endif + +#if defined(__mips__) +struct mips_hi16 +{ + struct mips_hi16 *next; + ElfW(Addr) *addr; + ElfW(Addr) value; +}; +#endif + +struct arch_file { + struct obj_file root; +#if defined(USE_PLT_ENTRIES) + struct obj_section *plt; +#endif +#if defined(USE_GOT_ENTRIES) + struct obj_section *got; +#endif +#if defined(__mips__) + struct mips_hi16 *mips_hi16_list; +#endif +}; + +struct arch_symbol { + struct obj_symbol root; +#if defined(USE_PLT_ENTRIES) +#if defined(USE_PLT_LIST) + struct arch_list_entry *pltent; +#else + struct arch_single_entry pltent; +#endif +#endif +#if defined(USE_GOT_ENTRIES) + struct arch_single_entry gotent; +#endif +}; + + +struct external_module { + const char *name; + ElfW(Addr) addr; + int used; + size_t nsyms; + struct new_module_symbol *syms; +}; + +static struct new_module_symbol *ksyms; +static size_t nksyms; + +static struct external_module *ext_modules; +static int n_ext_modules; +static int n_ext_modules_used; + +/*======================================================================*/ + + +static struct obj_file *arch_new_file(void) +{ + struct arch_file *f; + f = xzalloc(sizeof(*f)); + return &f->root; /* it's a first member */ +} + +static struct obj_section *arch_new_section(void) +{ + return xzalloc(sizeof(struct obj_section)); +} + +static struct obj_symbol *arch_new_symbol(void) +{ + struct arch_symbol *sym; + sym = xzalloc(sizeof(*sym)); + return &sym->root; +} + +static enum obj_reloc +arch_apply_relocation(struct obj_file *f, + struct obj_section *targsec, + /*struct obj_section *symsec,*/ + struct obj_symbol *sym, + ElfW(RelM) *rel, ElfW(Addr) v) +{ +#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \ + || defined(__sh__) || defined(__s390__) || defined(__x86_64__) \ + || defined(__powerpc__) || defined(__mips__) + struct arch_file *ifile = (struct arch_file *) f; +#endif + enum obj_reloc ret = obj_reloc_ok; + ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); +#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \ + || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \ + || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \ + || defined(__s390__) || defined(__sh__) || defined(__x86_64__) + ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; +#endif +#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) + struct arch_symbol *isym = (struct arch_symbol *) sym; +#endif +#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \ + || defined(__sh__) || defined(__s390__) +#if defined(USE_GOT_ENTRIES) + ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; +#endif +#endif +#if defined(USE_PLT_ENTRIES) + ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; + unsigned long *ip; +# if defined(USE_PLT_LIST) + struct arch_list_entry *pe; +# else + struct arch_single_entry *pe; +# endif +#endif + + switch (ELF_R_TYPE(rel->r_info)) { + +#if defined(__arm__) + + case R_ARM_NONE: + break; + + case R_ARM_ABS32: + *loc += v; + break; + + case R_ARM_GOT32: + goto bb_use_got; + + case R_ARM_GOTPC: + /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ + * (which is .got) similar to branch, + * but is full 32 bits relative */ + + *loc += got - dot; + break; + + case R_ARM_PC24: + case R_ARM_PLT32: + goto bb_use_plt; + + case R_ARM_GOTOFF: /* address relative to the got */ + *loc += v - got; + break; + +#elif defined(__cris__) + + case R_CRIS_NONE: + break; + + case R_CRIS_32: + /* CRIS keeps the relocation value in the r_addend field and + * should not use whats in *loc at all + */ + *loc = v; + break; + +#elif defined(__H8300H__) || defined(__H8300S__) + + case R_H8_DIR24R8: + loc = (ElfW(Addr) *)((ElfW(Addr))loc - 1); + *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v); + break; + case R_H8_DIR24A8: + *loc += v; + break; + case R_H8_DIR32: + case R_H8_DIR32A16: + *loc += v; + break; + case R_H8_PCREL16: + v -= dot + 2; + if ((ElfW(Sword))v > 0x7fff || + (ElfW(Sword))v < -(ElfW(Sword))0x8000) + ret = obj_reloc_overflow; + else + *(unsigned short *)loc = v; + break; + case R_H8_PCREL8: + v -= dot + 1; + if ((ElfW(Sword))v > 0x7f || + (ElfW(Sword))v < -(ElfW(Sword))0x80) + ret = obj_reloc_overflow; + else + *(unsigned char *)loc = v; + break; + +#elif defined(__i386__) + + case R_386_NONE: + break; + + case R_386_32: + *loc += v; + break; + + case R_386_PLT32: + case R_386_PC32: + case R_386_GOTOFF: + *loc += v - dot; + break; + + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + *loc = v; + break; + + case R_386_RELATIVE: + *loc += f->baseaddr; + break; + + case R_386_GOTPC: + *loc += got - dot; + break; + + case R_386_GOT32: + goto bb_use_got; + break; + +#elif defined(__microblaze__) + case R_MICROBLAZE_NONE: + case R_MICROBLAZE_64_NONE: + case R_MICROBLAZE_32_SYM_OP_SYM: + case R_MICROBLAZE_32_PCREL: + break; + + case R_MICROBLAZE_64_PCREL: { + /* dot is the address of the current instruction. + * v is the target symbol address. + * So we need to extract the offset in the code, + * adding v, then subtrating the current address + * of this instruction. + * Ex: "IMM 0xFFFE bralid 0x0000" = "bralid 0xFFFE0000" + */ + + /* Get split offset stored in code */ + unsigned int temp = (loc[0] & 0xFFFF) << 16 | + (loc[1] & 0xFFFF); + + /* Adjust relative offset. -4 adjustment required + * because dot points to the IMM insn, but branch + * is computed relative to the branch instruction itself. + */ + temp += v - dot - 4; + + /* Store back into code */ + loc[0] = (loc[0] & 0xFFFF0000) | temp >> 16; + loc[1] = (loc[1] & 0xFFFF0000) | (temp & 0xFFFF); + + break; + } + + case R_MICROBLAZE_32: + *loc += v; + break; + + case R_MICROBLAZE_64: { + /* Get split pointer stored in code */ + unsigned int temp1 = (loc[0] & 0xFFFF) << 16 | + (loc[1] & 0xFFFF); + + /* Add reloc offset */ + temp1+=v; + + /* Store back into code */ + loc[0] = (loc[0] & 0xFFFF0000) | temp1 >> 16; + loc[1] = (loc[1] & 0xFFFF0000) | (temp1 & 0xFFFF); + + break; + } + + case R_MICROBLAZE_32_PCREL_LO: + case R_MICROBLAZE_32_LO: + case R_MICROBLAZE_SRO32: + case R_MICROBLAZE_SRW32: + ret = obj_reloc_unhandled; + break; + +#elif defined(__mc68000__) + + case R_68K_NONE: + break; + + case R_68K_32: + *loc += v; + break; + + case R_68K_8: + if (v > 0xff) { + ret = obj_reloc_overflow; + } + *(char *)loc = v; + break; + + case R_68K_16: + if (v > 0xffff) { + ret = obj_reloc_overflow; + } + *(short *)loc = v; + break; + + case R_68K_PC8: + v -= dot; + if ((ElfW(Sword))v > 0x7f + || (ElfW(Sword))v < -(ElfW(Sword))0x80 + ) { + ret = obj_reloc_overflow; + } + *(char *)loc = v; + break; + + case R_68K_PC16: + v -= dot; + if ((ElfW(Sword))v > 0x7fff + || (ElfW(Sword))v < -(ElfW(Sword))0x8000 + ) { + ret = obj_reloc_overflow; + } + *(short *)loc = v; + break; + + case R_68K_PC32: + *(int *)loc = v - dot; + break; + + case R_68K_GLOB_DAT: + case R_68K_JMP_SLOT: + *loc = v; + break; + + case R_68K_RELATIVE: + *(int *)loc += f->baseaddr; + break; + + case R_68K_GOT32: + goto bb_use_got; + +# ifdef R_68K_GOTOFF + case R_68K_GOTOFF: + *loc += v - got; + break; +# endif + +#elif defined(__mips__) + + case R_MIPS_NONE: + break; + + case R_MIPS_32: + *loc += v; + break; + + case R_MIPS_26: + if (v % 4) + ret = obj_reloc_dangerous; + if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) + ret = obj_reloc_overflow; + *loc = + (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & + 0x03ffffff); + break; + + case R_MIPS_HI16: + { + struct mips_hi16 *n; + + /* We cannot relocate this one now because we don't know the value + of the carry we need to add. Save the information, and let LO16 + do the actual relocation. */ + n = xmalloc(sizeof *n); + n->addr = loc; + n->value = v; + n->next = ifile->mips_hi16_list; + ifile->mips_hi16_list = n; + break; + } + + case R_MIPS_LO16: + { + unsigned long insnlo = *loc; + ElfW(Addr) val, vallo; + + /* Sign extend the addend we extract from the lo insn. */ + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; + + if (ifile->mips_hi16_list != NULL) { + struct mips_hi16 *l; + + l = ifile->mips_hi16_list; + while (l != NULL) { + struct mips_hi16 *next; + unsigned long insn; + + /* Do the HI16 relocation. Note that we actually don't + need to know anything about the LO16 itself, except where + to find the low 16 bits of the addend needed by the LO16. */ + insn = *l->addr; + val = + ((insn & 0xffff) << 16) + + vallo; + val += v; + + /* Account for the sign extension that will happen in the + low bits. */ + val = + ((val >> 16) + + ((val & 0x8000) != + 0)) & 0xffff; + + insn = (insn & ~0xffff) | val; + *l->addr = insn; + + next = l->next; + free(l); + l = next; + } + + ifile->mips_hi16_list = NULL; + } + + /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ + val = v + vallo; + insnlo = (insnlo & ~0xffff) | (val & 0xffff); + *loc = insnlo; + break; + } + +#elif defined(__nios2__) + + case R_NIOS2_NONE: + break; + + case R_NIOS2_BFD_RELOC_32: + *loc += v; + break; + + case R_NIOS2_BFD_RELOC_16: + if (v > 0xffff) { + ret = obj_reloc_overflow; + } + *(short *)loc = v; + break; + + case R_NIOS2_BFD_RELOC_8: + if (v > 0xff) { + ret = obj_reloc_overflow; + } + *(char *)loc = v; + break; + + case R_NIOS2_S16: + { + Elf32_Addr word; + + if ((Elf32_Sword)v > 0x7fff + || (Elf32_Sword)v < -(Elf32_Sword)0x8000 + ) { + ret = obj_reloc_overflow; + } + + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + } + break; + + case R_NIOS2_U16: + { + Elf32_Addr word; + + if (v > 0xffff) { + ret = obj_reloc_overflow; + } + + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + } + break; + + case R_NIOS2_PCREL16: + { + Elf32_Addr word; + + v -= dot + 4; + if ((Elf32_Sword)v > 0x7fff + || (Elf32_Sword)v < -(Elf32_Sword)0x8000 + ) { + ret = obj_reloc_overflow; + } + + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); + } + break; + + case R_NIOS2_GPREL: + { + Elf32_Addr word, gp; + /* get _gp */ + gp = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "_gp")); + v -= gp; + if ((Elf32_Sword)v > 0x7fff + || (Elf32_Sword)v < -(Elf32_Sword)0x8000 + ) { + ret = obj_reloc_overflow; + } + + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); + } + break; + + case R_NIOS2_CALL26: + if (v & 3) + ret = obj_reloc_dangerous; + if ((v >> 28) != (dot >> 28)) + ret = obj_reloc_overflow; + *loc = (*loc & 0x3f) | ((v >> 2) << 6); + break; + + case R_NIOS2_IMM5: + { + Elf32_Addr word; + + if (v > 0x1f) { + ret = obj_reloc_overflow; + } + + word = *loc & ~0x7c0; + *loc = word | ((v & 0x1f) << 6); + } + break; + + case R_NIOS2_IMM6: + { + Elf32_Addr word; + + if (v > 0x3f) { + ret = obj_reloc_overflow; + } + + word = *loc & ~0xfc0; + *loc = word | ((v & 0x3f) << 6); + } + break; + + case R_NIOS2_IMM8: + { + Elf32_Addr word; + + if (v > 0xff) { + ret = obj_reloc_overflow; + } + + word = *loc & ~0x3fc0; + *loc = word | ((v & 0xff) << 6); + } + break; + + case R_NIOS2_HI16: + { + Elf32_Addr word; + + word = *loc; + *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) | + (word & 0x3f); + } + break; + + case R_NIOS2_LO16: + { + Elf32_Addr word; + + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + } + break; + + case R_NIOS2_HIADJ16: + { + Elf32_Addr word1, word2; + + word1 = *loc; + word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; + *loc = ((((word1 >> 22) << 16) | word2) << 6) | + (word1 & 0x3f); + } + break; + +#elif defined(__powerpc64__) + /* PPC64 needs a 2.6 kernel, 2.4 module relocation irrelevant */ + +#elif defined(__powerpc__) + + case R_PPC_ADDR16_HA: + *(unsigned short *)loc = (v + 0x8000) >> 16; + break; + + case R_PPC_ADDR16_HI: + *(unsigned short *)loc = v >> 16; + break; + + case R_PPC_ADDR16_LO: + *(unsigned short *)loc = v; + break; + + case R_PPC_REL24: + goto bb_use_plt; + + case R_PPC_REL32: + *loc = v - dot; + break; + + case R_PPC_ADDR32: + *loc = v; + break; + +#elif defined(__s390__) + + case R_390_32: + *(unsigned int *) loc += v; + break; + case R_390_16: + *(unsigned short *) loc += v; + break; + case R_390_8: + *(unsigned char *) loc += v; + break; + + case R_390_PC32: + *(unsigned int *) loc += v - dot; + break; + case R_390_PC16DBL: + *(unsigned short *) loc += (v - dot) >> 1; + break; + case R_390_PC16: + *(unsigned short *) loc += v - dot; + break; + + case R_390_PLT32: + case R_390_PLT16DBL: + /* find the plt entry and initialize it. */ + pe = (struct arch_single_entry *) &isym->pltent; + if (pe->inited == 0) { + ip = (unsigned long *)(ifile->plt->contents + pe->offset); + ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */ + ip[1] = 0x100607f1; + if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL) + ip[2] = v - 2; + else + ip[2] = v; + pe->inited = 1; + } + + /* Insert relative distance to target. */ + v = plt + pe->offset - dot; + if (ELF_R_TYPE(rel->r_info) == R_390_PLT32) + *(unsigned int *) loc = (unsigned int) v; + else if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL) + *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1); + break; + + case R_390_GLOB_DAT: + case R_390_JMP_SLOT: + *loc = v; + break; + + case R_390_RELATIVE: + *loc += f->baseaddr; + break; + + case R_390_GOTPC: + *(unsigned long *) loc += got - dot; + break; + + case R_390_GOT12: + case R_390_GOT16: + case R_390_GOT32: + if (!isym->gotent.inited) + { + isym->gotent.inited = 1; + *(ElfW(Addr) *)(ifile->got->contents + isym->gotent.offset) = v; + } + if (ELF_R_TYPE(rel->r_info) == R_390_GOT12) + *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff; + else if (ELF_R_TYPE(rel->r_info) == R_390_GOT16) + *(unsigned short *) loc += isym->gotent.offset; + else if (ELF_R_TYPE(rel->r_info) == R_390_GOT32) + *(unsigned int *) loc += isym->gotent.offset; + break; + +# ifndef R_390_GOTOFF32 +# define R_390_GOTOFF32 R_390_GOTOFF +# endif + case R_390_GOTOFF32: + *loc += v - got; + break; + +#elif defined(__sh__) + + case R_SH_NONE: + break; + + case R_SH_DIR32: + *loc += v; + break; + + case R_SH_REL32: + *loc += v - dot; + break; + + case R_SH_PLT32: + *loc = v - dot; + break; + + case R_SH_GLOB_DAT: + case R_SH_JMP_SLOT: + *loc = v; + break; + + case R_SH_RELATIVE: + *loc = f->baseaddr + rel->r_addend; + break; + + case R_SH_GOTPC: + *loc = got - dot + rel->r_addend; + break; + + case R_SH_GOT32: + goto bb_use_got; + + case R_SH_GOTOFF: + *loc = v - got; + break; + +# if defined(__SH5__) + case R_SH_IMM_MEDLOW16: + case R_SH_IMM_LOW16: + { + ElfW(Addr) word; + + if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16) + v >>= 16; + + /* + * movi and shori have the format: + * + * | op | imm | reg | reserved | + * 31..26 25..10 9.. 4 3 .. 0 + * + * so we simply mask and or in imm. + */ + word = *loc & ~0x3fffc00; + word |= (v & 0xffff) << 10; + + *loc = word; + + break; + } + + case R_SH_IMM_MEDLOW16_PCREL: + case R_SH_IMM_LOW16_PCREL: + { + ElfW(Addr) word; + + word = *loc & ~0x3fffc00; + + v -= dot; + + if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL) + v >>= 16; + + word |= (v & 0xffff) << 10; + + *loc = word; + + break; + } +# endif /* __SH5__ */ + +#elif defined(__v850e__) + + case R_V850_NONE: + break; + + case R_V850_32: + /* We write two shorts instead of a long because even + 32-bit insns only need half-word alignment, but + 32-bit data needs to be long-word aligned. */ + v += ((unsigned short *)loc)[0]; + v += ((unsigned short *)loc)[1] << 16; + ((unsigned short *)loc)[0] = v & 0xffff; + ((unsigned short *)loc)[1] = (v >> 16) & 0xffff; + break; + + case R_V850_22_PCREL: + goto bb_use_plt; + +#elif defined(__x86_64__) + + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *loc += v; + break; + + case R_X86_64_32: + *(unsigned int *) loc += v; + if (v > 0xffffffff) + { + ret = obj_reloc_overflow; /* Kernel module compiled without -mcmodel=kernel. */ + /* error("Possibly is module compiled without -mcmodel=kernel!"); */ + } + break; + + case R_X86_64_32S: + *(signed int *) loc += v; + break; + + case R_X86_64_16: + *(unsigned short *) loc += v; + break; + + case R_X86_64_8: + *(unsigned char *) loc += v; + break; + + case R_X86_64_PC32: + *(unsigned int *) loc += v - dot; + break; + + case R_X86_64_PC16: + *(unsigned short *) loc += v - dot; + break; + + case R_X86_64_PC8: + *(unsigned char *) loc += v - dot; + break; + + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + *loc = v; + break; + + case R_X86_64_RELATIVE: + *loc += f->baseaddr; + break; + + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + goto bb_use_got; +# if 0 + if (!isym->gotent.reloc_done) + { + isym->gotent.reloc_done = 1; + *(Elf64_Addr *)(ifile->got->contents + isym->gotent.offset) = v; + } + /* XXX are these really correct? */ + if (ELF64_R_TYPE(rel->r_info) == R_X86_64_GOTPCREL) + *(unsigned int *) loc += v + isym->gotent.offset; + else + *loc += isym->gotent.offset; + break; +# endif + +#else +# warning "no idea how to handle relocations on your arch" +#endif + + default: + printf("Warning: unhandled reloc %d\n",(int)ELF_R_TYPE(rel->r_info)); + ret = obj_reloc_unhandled; + break; + +#if defined(USE_PLT_ENTRIES) + +bb_use_plt: + + /* find the plt entry and initialize it if necessary */ + +#if defined(USE_PLT_LIST) + for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;) + pe = pe->next; +#else + pe = &isym->pltent; +#endif + + if (! pe->inited) { + ip = (unsigned long *) (ifile->plt->contents + pe->offset); + + /* generate some machine code */ + +#if defined(__arm__) + ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ + ip[1] = v; /* sym@ */ +#endif +#if defined(__powerpc__) + ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */ + ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */ + ip[2] = 0x7d6903a6; /* mtctr r11 */ + ip[3] = 0x4e800420; /* bctr */ +#endif +#if defined(__v850e__) + /* We have to trash a register, so we assume that any control + transfer more than 21-bits away must be a function call + (so we can use a call-clobbered register). */ + ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */ + ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */ +#endif + pe->inited = 1; + } + + /* relative distance to target */ + v -= dot; + /* if the target is too far away.... */ +#if defined(__arm__) || defined(__powerpc__) + if ((int)v < -0x02000000 || (int)v >= 0x02000000) +#elif defined(__v850e__) + if ((ElfW(Sword))v > 0x1fffff || (ElfW(Sword))v < (ElfW(Sword))-0x200000) +#endif + /* go via the plt */ + v = plt + pe->offset - dot; + +#if defined(__v850e__) + if (v & 1) +#else + if (v & 3) +#endif + ret = obj_reloc_dangerous; + + /* merge the offset into the instruction. */ +#if defined(__arm__) + /* Convert to words. */ + v >>= 2; + + *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); +#endif +#if defined(__powerpc__) + *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); +#endif +#if defined(__v850e__) + /* We write two shorts instead of a long because even 32-bit insns + only need half-word alignment, but the 32-bit data write needs + to be long-word aligned. */ + ((unsigned short *)loc)[0] = + (*(unsigned short *)loc & 0xffc0) /* opcode + reg */ + | ((v >> 16) & 0x3f); /* offs high part */ + ((unsigned short *)loc)[1] = + (v & 0xffff); /* offs low part */ +#endif + break; +#endif /* USE_PLT_ENTRIES */ + +#if defined(USE_GOT_ENTRIES) +bb_use_got: + + /* needs an entry in the .got: set it, once */ + if (!isym->gotent.inited) { + isym->gotent.inited = 1; + *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; + } + /* make the reloc with_respect_to_.got */ +#if defined(__sh__) + *loc += isym->gotent.offset + rel->r_addend; +#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) + *loc += isym->gotent.offset; +#endif + break; + +#endif /* USE_GOT_ENTRIES */ + } + + return ret; +} + + +#if defined(USE_LIST) + +static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list, + int offset, int size) +{ + struct arch_list_entry *pe; + + for (pe = *list; pe != NULL; pe = pe->next) { + if (pe->addend == rel->r_addend) { + break; + } + } + + if (pe == NULL) { + pe = xzalloc(sizeof(struct arch_list_entry)); + pe->next = *list; + pe->addend = rel->r_addend; + pe->offset = offset; + /*pe->inited = 0;*/ + *list = pe; + return size; + } + return 0; +} + +#endif + +#if defined(USE_SINGLE) + +static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single, + int offset, int size) +{ + if (single->allocated == 0) { + single->allocated = 1; + single->offset = offset; + single->inited = 0; + return size; + } + return 0; +} + +#endif + +#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) + +static struct obj_section *arch_xsect_init(struct obj_file *f, const char *name, + int offset, int size) +{ + struct obj_section *myrelsec = obj_find_section(f, name); + + if (offset == 0) { + offset += size; + } + + if (myrelsec) { + obj_extend_section(myrelsec, offset); + } else { + myrelsec = obj_create_alloced_section(f, name, + size, offset); + } + + return myrelsec; +} + +#endif + +static void arch_create_got(struct obj_file *f) +{ +#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) + struct arch_file *ifile = (struct arch_file *) f; + int i; +#if defined(USE_GOT_ENTRIES) + int got_offset = 0, got_needed = 0, got_allocate; +#endif +#if defined(USE_PLT_ENTRIES) + int plt_offset = 0, plt_needed = 0, plt_allocate; +#endif + struct obj_section *relsec, *symsec, *strsec; + ElfW(RelM) *rel, *relend; + ElfW(Sym) *symtab, *extsym; + const char *strtab, *name; + struct arch_symbol *intsym; + + for (i = 0; i < f->header.e_shnum; ++i) { + relsec = f->sections[i]; + if (relsec->header.sh_type != SHT_RELM) + continue; + + symsec = f->sections[relsec->header.sh_link]; + strsec = f->sections[symsec->header.sh_link]; + + rel = (ElfW(RelM) *) relsec->contents; + relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); + symtab = (ElfW(Sym) *) symsec->contents; + strtab = (const char *) strsec->contents; + + for (; rel < relend; ++rel) { + extsym = &symtab[ELF_R_SYM(rel->r_info)]; + +#if defined(USE_GOT_ENTRIES) + got_allocate = 0; +#endif +#if defined(USE_PLT_ENTRIES) + plt_allocate = 0; +#endif + + switch (ELF_R_TYPE(rel->r_info)) { +#if defined(__arm__) + case R_ARM_PC24: + case R_ARM_PLT32: + plt_allocate = 1; + break; + + case R_ARM_GOTOFF: + case R_ARM_GOTPC: + got_needed = 1; + continue; + + case R_ARM_GOT32: + got_allocate = 1; + break; + +#elif defined(__i386__) + case R_386_GOTPC: + case R_386_GOTOFF: + got_needed = 1; + continue; + + case R_386_GOT32: + got_allocate = 1; + break; + +#elif defined(__powerpc__) + case R_PPC_REL24: + plt_allocate = 1; + break; + +#elif defined(__mc68000__) + case R_68K_GOT32: + got_allocate = 1; + break; + +#ifdef R_68K_GOTOFF + case R_68K_GOTOFF: + got_needed = 1; + continue; +#endif + +#elif defined(__sh__) + case R_SH_GOT32: + got_allocate = 1; + break; + + case R_SH_GOTPC: + case R_SH_GOTOFF: + got_needed = 1; + continue; + +#elif defined(__v850e__) + case R_V850_22_PCREL: + plt_needed = 1; + break; + +#endif + default: + continue; + } + + if (extsym->st_name != 0) { + name = strtab + extsym->st_name; + } else { + name = f->sections[extsym->st_shndx]->name; + } + intsym = (struct arch_symbol *) obj_find_symbol(f, name); +#if defined(USE_GOT_ENTRIES) + if (got_allocate) { + got_offset += arch_single_init( + /*rel,*/ &intsym->gotent, + got_offset, GOT_ENTRY_SIZE); + + got_needed = 1; + } +#endif +#if defined(USE_PLT_ENTRIES) + if (plt_allocate) { +#if defined(USE_PLT_LIST) + plt_offset += arch_list_add( + rel, &intsym->pltent, + plt_offset, PLT_ENTRY_SIZE); +#else + plt_offset += arch_single_init( + /*rel,*/ &intsym->pltent, + plt_offset, PLT_ENTRY_SIZE); +#endif + plt_needed = 1; + } +#endif + } + } + +#if defined(USE_GOT_ENTRIES) + if (got_needed) { + ifile->got = arch_xsect_init(f, ".got", got_offset, + GOT_ENTRY_SIZE); + } +#endif + +#if defined(USE_PLT_ENTRIES) + if (plt_needed) { + ifile->plt = arch_xsect_init(f, ".plt", plt_offset, + PLT_ENTRY_SIZE); + } +#endif + +#endif /* defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) */ +} + +/*======================================================================*/ + +/* Standard ELF hash function. */ +static unsigned long obj_elf_hash_n(const char *name, unsigned long n) +{ + unsigned long h = 0; + unsigned long g; + unsigned char ch; + + while (n > 0) { + ch = *name++; + h = (h << 4) + ch; + g = (h & 0xf0000000); + if (g != 0) { + h ^= g >> 24; + h &= ~g; + } + n--; + } + return h; +} + +static unsigned long obj_elf_hash(const char *name) +{ + return obj_elf_hash_n(name, strlen(name)); +} + +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING +/* String comparison for non-co-versioned kernel and module. */ + +static int ncv_strcmp(const char *a, const char *b) +{ + size_t alen = strlen(a), blen = strlen(b); + + if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') + return strncmp(a, b, alen); + else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') + return strncmp(a, b, blen); + else + return strcmp(a, b); +} + +/* String hashing for non-co-versioned kernel and module. Here + we are simply forced to drop the crc from the hash. */ + +static unsigned long ncv_symbol_hash(const char *str) +{ + size_t len = strlen(str); + if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') + len -= 10; + return obj_elf_hash_n(str, len); +} + +static void +obj_set_symbol_compare(struct obj_file *f, + int (*cmp) (const char *, const char *), + unsigned long (*hash) (const char *)) +{ + if (cmp) + f->symbol_cmp = cmp; + if (hash) { + struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; + int i; + + f->symbol_hash = hash; + + memcpy(tmptab, f->symtab, sizeof(tmptab)); + memset(f->symtab, 0, sizeof(f->symtab)); + + for (i = 0; i < HASH_BUCKETS; ++i) + for (sym = tmptab[i]; sym; sym = next) { + unsigned long h = hash(sym->name) % HASH_BUCKETS; + next = sym->next; + sym->next = f->symtab[h]; + f->symtab[h] = sym; + } + } +} + +#endif /* FEATURE_INSMOD_VERSION_CHECKING */ + +static struct obj_symbol * +obj_add_symbol(struct obj_file *f, const char *name, + unsigned long symidx, int info, + int secidx, ElfW(Addr) value, + unsigned long size) +{ + struct obj_symbol *sym; + unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; + int n_type = ELF_ST_TYPE(info); + int n_binding = ELF_ST_BIND(info); + + for (sym = f->symtab[hash]; sym; sym = sym->next) { + if (f->symbol_cmp(sym->name, name) == 0) { + int o_secidx = sym->secidx; + int o_info = sym->info; + int o_type = ELF_ST_TYPE(o_info); + int o_binding = ELF_ST_BIND(o_info); + + /* A redefinition! Is it legal? */ + + if (secidx == SHN_UNDEF) + return sym; + else if (o_secidx == SHN_UNDEF) + goto found; + else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { + /* Cope with local and global symbols of the same name + in the same object file, as might have been created + by ld -r. The only reason locals are now seen at this + level at all is so that we can do semi-sensible things + with parameters. */ + + struct obj_symbol *nsym, **p; + + nsym = arch_new_symbol(); + nsym->next = sym->next; + nsym->ksymidx = -1; + + /* Excise the old (local) symbol from the hash chain. */ + for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) + continue; + *p = sym = nsym; + goto found; + } else if (n_binding == STB_LOCAL) { + /* Another symbol of the same name has already been defined. + Just add this to the local table. */ + sym = arch_new_symbol(); + sym->next = NULL; + sym->ksymidx = -1; + f->local_symtab[symidx] = sym; + goto found; + } else if (n_binding == STB_WEAK) + return sym; + else if (o_binding == STB_WEAK) + goto found; + /* Don't unify COMMON symbols with object types the programmer + doesn't expect. */ + else if (secidx == SHN_COMMON + && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) + return sym; + else if (o_secidx == SHN_COMMON + && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) + goto found; + else { + /* Don't report an error if the symbol is coming from + the kernel or some external module. */ + if (secidx <= SHN_HIRESERVE) + bb_error_msg("%s multiply defined", name); + return sym; + } + } + } + + /* Completely new symbol. */ + sym = arch_new_symbol(); + sym->next = f->symtab[hash]; + f->symtab[hash] = sym; + sym->ksymidx = -1; + if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) { + if (symidx >= f->local_symtab_size) + bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", + name, (long) symidx, (long) f->local_symtab_size); + else + f->local_symtab[symidx] = sym; + } + +found: + sym->name = name; + sym->value = value; + sym->size = size; + sym->secidx = secidx; + sym->info = info; + + return sym; +} + +static struct obj_symbol * +obj_find_symbol(struct obj_file *f, const char *name) +{ + struct obj_symbol *sym; + unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; + + for (sym = f->symtab[hash]; sym; sym = sym->next) + if (f->symbol_cmp(sym->name, name) == 0) + return sym; + return NULL; +} + +static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) +{ + if (sym) { + if (sym->secidx >= SHN_LORESERVE) + return sym->value; + return sym->value + f->sections[sym->secidx]->header.sh_addr; + } + /* As a special case, a NULL sym has value zero. */ + return 0; +} + +static struct obj_section *obj_find_section(struct obj_file *f, const char *name) +{ + int i, n = f->header.e_shnum; + + for (i = 0; i < n; ++i) + if (strcmp(f->sections[i]->name, name) == 0) + return f->sections[i]; + return NULL; +} + +static int obj_load_order_prio(struct obj_section *a) +{ + unsigned long af, ac; + + af = a->header.sh_flags; + + ac = 0; + if (a->name[0] != '.' || strlen(a->name) != 10 + || strcmp(a->name + 5, ".init") != 0 + ) { + ac |= 32; + } + if (af & SHF_ALLOC) + ac |= 16; + if (!(af & SHF_WRITE)) + ac |= 8; + if (af & SHF_EXECINSTR) + ac |= 4; + if (a->header.sh_type != SHT_NOBITS) + ac |= 2; + + return ac; +} + +static void +obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) +{ + struct obj_section **p; + int prio = obj_load_order_prio(sec); + for (p = f->load_order_search_start; *p; p = &(*p)->load_next) + if (obj_load_order_prio(*p) < prio) + break; + sec->load_next = *p; + *p = sec; +} + +static struct obj_section *helper_create_alloced_section(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size) +{ + int newidx = f->header.e_shnum++; + struct obj_section *sec; + + f->sections = xrealloc_vector(f->sections, 2, newidx); + f->sections[newidx] = sec = arch_new_section(); + + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; + sec->header.sh_size = size; + sec->header.sh_addralign = align; + sec->name = name; + sec->idx = newidx; + if (size) + sec->contents = xzalloc(size); + + return sec; +} + +static struct obj_section *obj_create_alloced_section(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size) +{ + struct obj_section *sec; + + sec = helper_create_alloced_section(f, name, align, size); + obj_insert_section_load_order(f, sec); + return sec; +} + +static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size) +{ + struct obj_section *sec; + + sec = helper_create_alloced_section(f, name, align, size); + sec->load_next = f->load_order; + f->load_order = sec; + if (f->load_order_search_start == &f->load_order) + f->load_order_search_start = &sec->load_next; + + return sec; +} + +static void *obj_extend_section(struct obj_section *sec, unsigned long more) +{ + unsigned long oldsize = sec->header.sh_size; + if (more) { + sec->header.sh_size += more; + sec->contents = xrealloc(sec->contents, sec->header.sh_size); + } + return sec->contents + oldsize; +} + + +/* Conditionally add the symbols from the given symbol set to the + new module. */ + +static int add_symbols_from(struct obj_file *f, + int idx, + struct new_module_symbol *syms, + size_t nsyms) +{ + struct new_module_symbol *s; + size_t i; + int used = 0; +#ifdef SYMBOL_PREFIX + char *name_buf = NULL; + size_t name_alloced_size = 0; +#endif +#if ENABLE_FEATURE_CHECK_TAINTED_MODULE + int gpl; + + gpl = obj_gpl_license(f, NULL) == 0; +#endif + for (i = 0, s = syms; i < nsyms; ++i, ++s) { + /* Only add symbols that are already marked external. + If we override locals we may cause problems for + argument initialization. We will also create a false + dependency on the module. */ + struct obj_symbol *sym; + char *name; + + /* GPL licensed modules can use symbols exported with + * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the + * exported names. Non-GPL modules never see any GPLONLY_ + * symbols so they cannot fudge it by adding the prefix on + * their references. + */ + if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) { +#if ENABLE_FEATURE_CHECK_TAINTED_MODULE + if (gpl) + s->name += 8; + else +#endif + continue; + } + name = (char *)s->name; + +#ifdef SYMBOL_PREFIX + /* Prepend SYMBOL_PREFIX to the symbol's name (the + kernel exports `C names', but module object files + reference `linker names'). */ + size_t extra = sizeof SYMBOL_PREFIX; + size_t name_size = strlen(name) + extra; + if (name_size > name_alloced_size) { + name_alloced_size = name_size * 2; + name_buf = alloca(name_alloced_size); + } + strcpy(name_buf, SYMBOL_PREFIX); + strcpy(name_buf + extra - 1, name); + name = name_buf; +#endif + + sym = obj_find_symbol(f, name); + if (sym && !(ELF_ST_BIND(sym->info) == STB_LOCAL)) { +#ifdef SYMBOL_PREFIX + /* Put NAME_BUF into more permanent storage. */ + name = xmalloc(name_size); + strcpy(name, name_buf); +#endif + sym = obj_add_symbol(f, name, -1, + ELF_ST_INFO(STB_GLOBAL, + STT_NOTYPE), + idx, s->value, 0); + /* Did our symbol just get installed? If so, mark the + module as "used". */ + if (sym->secidx == idx) + used = 1; + } + } + + return used; +} + +static void add_kernel_symbols(struct obj_file *f) +{ + struct external_module *m; + int i, nused = 0; + + /* Add module symbols first. */ + + for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) { + if (m->nsyms + && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms) + ) { + m->used = 1; + ++nused; + } + } + + n_ext_modules_used = nused; + + /* And finally the symbols from the kernel proper. */ + + if (nksyms) + add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); +} + +static char *get_modinfo_value(struct obj_file *f, const char *key) +{ + struct obj_section *sec; + char *p, *v, *n, *ep; + size_t klen = strlen(key); + + sec = obj_find_section(f, ".modinfo"); + if (sec == NULL) + return NULL; + p = sec->contents; + ep = p + sec->header.sh_size; + while (p < ep) { + v = strchr(p, '='); + n = strchr(p, '\0'); + if (v) { + if (p + klen == v && strncmp(p, key, klen) == 0) + return v + 1; + } else { + if (p + klen == n && strcmp(p, key) == 0) + return n; + } + p = n + 1; + } + + return NULL; +} + + +/*======================================================================*/ +/* Functions relating to module loading after 2.1.18. */ + +/* From Linux-2.6 sources */ +/* You can use " around spaces, but can't escape ". */ +/* Hyphens and underscores equivalent in parameter names. */ +static char *next_arg(char *args, char **param, char **val) +{ + unsigned int i, equals = 0; + int in_quote = 0, quoted = 0; + char *next; + + if (*args == '"') { + args++; + in_quote = 1; + quoted = 1; + } + + for (i = 0; args[i]; i++) { + if (args[i] == ' ' && !in_quote) + break; + if (equals == 0) { + if (args[i] == '=') + equals = i; + } + if (args[i] == '"') + in_quote = !in_quote; + } + + *param = args; + if (!equals) + *val = NULL; + else { + args[equals] = '\0'; + *val = args + equals + 1; + + /* Don't include quotes in value. */ + if (**val == '"') { + (*val)++; + if (args[i-1] == '"') + args[i-1] = '\0'; + } + if (quoted && args[i-1] == '"') + args[i-1] = '\0'; + } + + if (args[i]) { + args[i] = '\0'; + next = args + i + 1; + } else + next = args + i; + + /* Chew up trailing spaces. */ + return skip_whitespace(next); +} + +static void +new_process_module_arguments(struct obj_file *f, const char *options) +{ + char *xoptions, *pos; + char *param, *val; + + xoptions = pos = xstrdup(skip_whitespace(options)); + while (*pos) { + unsigned long charssize = 0; + char *tmp, *contents, *loc, *pinfo, *p; + struct obj_symbol *sym; + int min, max, n, len; + + pos = next_arg(pos, ¶m, &val); + + tmp = xasprintf("parm_%s", param); + pinfo = get_modinfo_value(f, tmp); + free(tmp); + if (pinfo == NULL) + bb_error_msg_and_die("invalid parameter %s", param); + +#ifdef SYMBOL_PREFIX + tmp = xasprintf(SYMBOL_PREFIX "%s", param); + sym = obj_find_symbol(f, tmp); + free(tmp); +#else + sym = obj_find_symbol(f, param); +#endif + + /* Also check that the parameter was not resolved from the kernel. */ + if (sym == NULL || sym->secidx > SHN_HIRESERVE) + bb_error_msg_and_die("symbol for parameter %s not found", param); + + /* Number of parameters */ + if (isdigit(*pinfo)) { + min = 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; + + if (*pinfo == 'c') { + if (!isdigit(*(pinfo + 1))) { + bb_error_msg_and_die("parameter type 'c' for %s must be followed by" + " the maximum size", param); + } + charssize = strtoul(pinfo + 1, (char **) NULL, 10); + } + + if (val == NULL) { + if (*pinfo != 'b') + bb_error_msg_and_die("argument expected for parameter %s", param); + val = (char *) "1"; + } + + /* Parse parameter values */ + n = 0; + p = val; + while (*p != 0) { + if (++n > max) + bb_error_msg_and_die("too many values for %s (max %d)", param, max); + + switch (*pinfo) { + case 's': + len = strcspn(p, ","); + p[len] = 0; + obj_string_patch(f, sym->secidx, + loc - contents, p); + loc += tgt_sizeof_char_p; + p += len; + break; + case 'c': + len = strcspn(p, ","); + p[len] = 0; + if (len >= charssize) + bb_error_msg_and_die("string too long for %s (max %ld)", param, + charssize - 1); + strcpy((char *) loc, p); + loc += charssize; + p += len; + break; + case 'b': + *loc++ = strtoul(p, &p, 0); + break; + case 'h': + *(short *) loc = strtoul(p, &p, 0); + loc += tgt_sizeof_short; + break; + case 'i': + *(int *) loc = strtoul(p, &p, 0); + loc += tgt_sizeof_int; + break; + case 'l': + *(long *) loc = strtoul(p, &p, 0); + loc += tgt_sizeof_long; + break; + default: + bb_error_msg_and_die("unknown parameter type '%c' for %s", + *pinfo, param); + } + + p = skip_whitespace(p); + if (*p != ',') + break; + p = skip_whitespace(p + 1); + } + + if (n < min) + bb_error_msg_and_die("parameter %s requires at least %d arguments", param, min); + if (*p != '\0') + bb_error_msg_and_die("invalid argument syntax for %s", param); + } + + free(xoptions); +} + +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING +static int new_is_module_checksummed(struct obj_file *f) +{ + const char *p = get_modinfo_value(f, "using_checksums"); + if (p) + return xatoi(p); + return 0; +} + +/* Get the module's kernel version in the canonical integer form. */ + +static int +new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ + char *p, *q; + int a, b, c; + + p = get_modinfo_value(f, "kernel_version"); + if (p == NULL) + return -1; + safe_strncpy(str, p, STRVERSIONLEN); + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + + return a << 16 | b << 8 | c; +} + +#endif /* FEATURE_INSMOD_VERSION_CHECKING */ + + +/* Fetch the loaded modules, and all currently exported symbols. */ + +static void new_get_kernel_symbols(void) +{ + char *module_names, *mn; + struct external_module *modules, *m; + struct new_module_symbol *syms, *s; + size_t ret, bufsize, nmod, nsyms, i, j; + + /* Collect the loaded modules. */ + + bufsize = 256; + module_names = xmalloc(bufsize); + + retry_modules_load: + if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { + if (errno == ENOSPC && bufsize < ret) { + bufsize = ret; + module_names = xrealloc(module_names, bufsize); + goto retry_modules_load; + } + bb_perror_msg_and_die("QM_MODULES"); + } + + n_ext_modules = nmod = ret; + + /* Collect the modules' symbols. */ + + if (nmod) { + ext_modules = modules = xzalloc(nmod * sizeof(*modules)); + for (i = 0, mn = module_names, m = modules; + i < nmod; ++i, ++m, mn += strlen(mn) + 1) { + struct new_module_info info; + + if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + bb_perror_msg_and_die("query_module: QM_INFO: %s", mn); + } + + bufsize = 1024; + syms = xmalloc(bufsize); + retry_mod_sym_load: + if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { + switch (errno) { + case ENOSPC: + bufsize = ret; + syms = xrealloc(syms, bufsize); + goto retry_mod_sym_load; + case ENOENT: + /* The module was removed out from underneath us. */ + continue; + default: + bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn); + } + } + nsyms = ret; + + m->name = mn; + m->addr = info.addr; + m->nsyms = nsyms; + m->syms = syms; + + for (j = 0, s = syms; j < nsyms; ++j, ++s) { + s->name += (unsigned long) syms; + } + } + } + + /* Collect the kernel's symbols. */ + + bufsize = 16 * 1024; + syms = xmalloc(bufsize); + retry_kern_sym_load: + if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { + if (errno == ENOSPC && bufsize < ret) { + bufsize = ret; + syms = xrealloc(syms, bufsize); + goto retry_kern_sym_load; + } + bb_perror_msg_and_die("kernel: QM_SYMBOLS"); + } + nksyms = nsyms = ret; + ksyms = syms; + + for (j = 0, s = syms; j < nsyms; ++j, ++s) { + s->name += (unsigned long) syms; + } +} + + +/* Return the kernel symbol checksum version, or zero if not used. */ + +static int new_is_kernel_checksummed(void) +{ + struct new_module_symbol *s; + size_t i; + + /* Using_Versions is not the first symbol, but it should be in there. */ + + for (i = 0, s = ksyms; i < nksyms; ++i, ++s) + if (strcmp((char *) s->name, "Using_Versions") == 0) + return s->value; + + return 0; +} + + +static void new_create_this_module(struct obj_file *f, const char *m_name) +{ + struct obj_section *sec; + + sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, + sizeof(struct new_module)); + /* done by obj_create_alloced_section_first: */ + /*memset(sec->contents, 0, sizeof(struct new_module));*/ + + obj_add_symbol(f, SPFX "__this_module", -1, + ELF_ST_INFO(STB_LOCAL, STT_OBJECT), sec->idx, 0, + sizeof(struct new_module)); + + obj_string_patch(f, sec->idx, offsetof(struct new_module, name), + m_name); +} + +#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS +/* add an entry to the __ksymtab section, creating it if necessary */ +static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym) +{ + struct obj_section *sec; + ElfW(Addr) ofs; + + /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section. + * If __ksymtab is defined but not marked alloc, x out the first character + * (no obj_delete routine) and create a new __ksymtab with the correct + * characteristics. + */ + sec = obj_find_section(f, "__ksymtab"); + if (sec && !(sec->header.sh_flags & SHF_ALLOC)) { + *((char *)(sec->name)) = 'x'; /* override const */ + sec = NULL; + } + if (!sec) + sec = obj_create_alloced_section(f, "__ksymtab", + tgt_sizeof_void_p, 0); + if (!sec) + return; + sec->header.sh_flags |= SHF_ALLOC; + /* Empty section might be byte-aligned */ + sec->header.sh_addralign = tgt_sizeof_void_p; + ofs = sec->header.sh_size; + obj_symbol_patch(f, sec->idx, ofs, sym); + obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); + obj_extend_section(sec, 2 * tgt_sizeof_char_p); +} +#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ + +static int new_create_module_ksymtab(struct obj_file *f) +{ + struct obj_section *sec; + int i; + + /* We must always add the module references. */ + + if (n_ext_modules_used) { + struct new_module_ref *dep; + struct obj_symbol *tm; + + sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, + (sizeof(struct new_module_ref) + * n_ext_modules_used)); + if (!sec) + return 0; + + tm = obj_find_symbol(f, SPFX "__this_module"); + dep = (struct new_module_ref *) sec->contents; + for (i = 0; i < n_ext_modules; ++i) + if (ext_modules[i].used) { + dep->dep = ext_modules[i].addr; + obj_symbol_patch(f, sec->idx, + (char *) &dep->ref - sec->contents, tm); + dep->next_ref = 0; + ++dep; + } + } + + if (!flag_noexport && !obj_find_section(f, "__ksymtab")) { + size_t nsyms; + int *loaded; + + sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); + + /* We don't want to export symbols residing in sections that + aren't loaded. There are a number of these created so that + we make sure certain module options don't appear twice. */ + i = f->header.e_shnum; + loaded = alloca(sizeof(int) * i); + while (--i >= 0) + loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; + + for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) { + if (ELF_ST_BIND(sym->info) != STB_LOCAL + && sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]) + ) { + ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; + + obj_symbol_patch(f, sec->idx, ofs, sym); + obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, + sym->name); + nsyms++; + } + } + } + + obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); + } + + return 1; +} + + +static int +new_init_module(const char *m_name, struct obj_file *f, unsigned long m_size) +{ + struct new_module *module; + struct obj_section *sec; + void *image; + int ret; + tgt_long m_addr; + + sec = obj_find_section(f, ".this"); + if (!sec || !sec->contents) { + bb_perror_msg_and_die("corrupt module %s?", m_name); + } + module = (struct new_module *) sec->contents; + m_addr = sec->header.sh_addr; + + module->size_of_struct = sizeof(*module); + module->size = m_size; + module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; + + sec = obj_find_section(f, "__ksymtab"); + if (sec && sec->header.sh_size) { + module->syms = sec->header.sh_addr; + module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); + } + + if (n_ext_modules_used) { + sec = obj_find_section(f, ".kmodtab"); + module->deps = sec->header.sh_addr; + module->ndeps = n_ext_modules_used; + } + + module->init = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); + module->cleanup = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); + + sec = obj_find_section(f, "__ex_table"); + if (sec) { + module->ex_table_start = sec->header.sh_addr; + module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; + } + + sec = obj_find_section(f, ".text.init"); + if (sec) { + module->runsize = sec->header.sh_addr - m_addr; + } + sec = obj_find_section(f, ".data.init"); + if (sec) { + if (!module->runsize + || module->runsize > sec->header.sh_addr - m_addr + ) { + module->runsize = sec->header.sh_addr - m_addr; + } + } + sec = obj_find_section(f, ARCHDATA_SEC_NAME); + if (sec && sec->header.sh_size) { + module->archdata_start = (void*)sec->header.sh_addr; + module->archdata_end = module->archdata_start + sec->header.sh_size; + } + sec = obj_find_section(f, KALLSYMS_SEC_NAME); + if (sec && sec->header.sh_size) { + module->kallsyms_start = (void*)sec->header.sh_addr; + module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; + } + + /* Whew! All of the initialization is complete. Collect the final + module image and give it to the kernel. */ + + image = xmalloc(m_size); + obj_create_image(f, image); + + ret = init_module(m_name, (struct new_module *) image); + if (ret) + bb_perror_msg("init_module: %s", m_name); + + free(image); + + return ret == 0; +} + + +/*======================================================================*/ + +static void +obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + const char *string) +{ + struct obj_string_patch *p; + struct obj_section *strsec; + size_t len = strlen(string) + 1; + char *loc; + + p = xzalloc(sizeof(*p)); + p->next = f->string_patches; + p->reloc_secidx = secidx; + p->reloc_offset = offset; + f->string_patches = p; + + strsec = obj_find_section(f, ".kstrtab"); + if (strsec == NULL) { + strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); + /*p->string_offset = 0;*/ + loc = strsec->contents; + } else { + p->string_offset = strsec->header.sh_size; + loc = obj_extend_section(strsec, len); + } + memcpy(loc, string, len); +} + +static void +obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + struct obj_symbol *sym) +{ + struct obj_symbol_patch *p; + + p = xmalloc(sizeof(*p)); + p->next = f->symbol_patches; + p->reloc_secidx = secidx; + p->reloc_offset = offset; + p->sym = sym; + f->symbol_patches = p; +} + +static void obj_check_undefineds(struct obj_file *f) +{ + unsigned i; + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) { + if (sym->secidx == SHN_UNDEF) { + if (ELF_ST_BIND(sym->info) == STB_WEAK) { + sym->secidx = SHN_ABS; + sym->value = 0; + } else { + if (!flag_quiet) + bb_error_msg_and_die("unresolved symbol %s", sym->name); + } + } + } + } +} + +static void obj_allocate_commons(struct obj_file *f) +{ + struct common_entry { + struct common_entry *next; + struct obj_symbol *sym; + } *common_head = NULL; + + unsigned long i; + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) { + if (sym->secidx == SHN_COMMON) { + /* Collect all COMMON symbols and sort them by size so as to + minimize space wasted by alignment requirements. */ + struct common_entry **p, *n; + for (p = &common_head; *p; p = &(*p)->next) + if (sym->size <= (*p)->sym->size) + break; + n = alloca(sizeof(*n)); + n->next = *p; + n->sym = sym; + *p = n; + } + } + } + + for (i = 1; i < f->local_symtab_size; ++i) { + struct obj_symbol *sym = f->local_symtab[i]; + if (sym && sym->secidx == SHN_COMMON) { + struct common_entry **p, *n; + for (p = &common_head; *p; p = &(*p)->next) { + if (sym == (*p)->sym) + break; + if (sym->size < (*p)->sym->size) { + n = alloca(sizeof(*n)); + n->next = *p; + n->sym = sym; + *p = n; + break; + } + } + } + } + + if (common_head) { + /* Find the bss section. */ + for (i = 0; i < f->header.e_shnum; ++i) + if (f->sections[i]->header.sh_type == SHT_NOBITS) + break; + + /* If for some reason there hadn't been one, create one. */ + if (i == f->header.e_shnum) { + struct obj_section *sec; + + f->header.e_shnum++; + f->sections = xrealloc_vector(f->sections, 2, i); + f->sections[i] = sec = arch_new_section(); + + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; + sec->name = ".bss"; + sec->idx = i; + } + + /* Allocate the COMMONS. */ + { + ElfW(Addr) bss_size = f->sections[i]->header.sh_size; + ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; + struct common_entry *c; + + for (c = common_head; c; c = c->next) { + ElfW(Addr) align = c->sym->value; + + if (align > max_align) + max_align = align; + if (bss_size & (align - 1)) + bss_size = (bss_size | (align - 1)) + 1; + + c->sym->secidx = i; + c->sym->value = bss_size; + + bss_size += c->sym->size; + } + + f->sections[i]->header.sh_size = bss_size; + f->sections[i]->header.sh_addralign = max_align; + } + } + + /* For the sake of patch relocation and parameter initialization, + allocate zeroed data for NOBITS sections now. Note that after + this we cannot assume NOBITS are really empty. */ + for (i = 0; i < f->header.e_shnum; ++i) { + struct obj_section *s = f->sections[i]; + if (s->header.sh_type == SHT_NOBITS) { + s->contents = NULL; + if (s->header.sh_size != 0) + s->contents = xzalloc(s->header.sh_size); + s->header.sh_type = SHT_PROGBITS; + } + } +} + +static unsigned long obj_load_size(struct obj_file *f) +{ + unsigned long dot = 0; + struct obj_section *sec; + + /* Finalize the positions of the sections relative to one another. */ + + for (sec = f->load_order; sec; sec = sec->load_next) { + ElfW(Addr) align; + + align = sec->header.sh_addralign; + if (align && (dot & (align - 1))) + dot = (dot | (align - 1)) + 1; + + sec->header.sh_addr = dot; + dot += sec->header.sh_size; + } + + return dot; +} + +static int obj_relocate(struct obj_file *f, ElfW(Addr) base) +{ + int i, n = f->header.e_shnum; + int ret = 1; + + /* Finalize the addresses of the sections. */ + + f->baseaddr = base; + for (i = 0; i < n; ++i) + f->sections[i]->header.sh_addr += base; + + /* And iterate over all of the relocations. */ + + for (i = 0; i < n; ++i) { + struct obj_section *relsec, *symsec, *targsec, *strsec; + ElfW(RelM) * rel, *relend; + ElfW(Sym) * symtab; + const char *strtab; + + relsec = f->sections[i]; + if (relsec->header.sh_type != SHT_RELM) + continue; + + symsec = f->sections[relsec->header.sh_link]; + targsec = f->sections[relsec->header.sh_info]; + strsec = f->sections[symsec->header.sh_link]; + + rel = (ElfW(RelM) *) relsec->contents; + relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); + symtab = (ElfW(Sym) *) symsec->contents; + strtab = (const char *) strsec->contents; + + for (; rel < relend; ++rel) { + ElfW(Addr) value = 0; + struct obj_symbol *intsym = NULL; + unsigned long symndx; + ElfW(Sym) *extsym = NULL; + const char *errmsg; + + /* Attempt to find a value to use for this relocation. */ + + symndx = ELF_R_SYM(rel->r_info); + if (symndx) { + /* Note we've already checked for undefined symbols. */ + + extsym = &symtab[symndx]; + if (ELF_ST_BIND(extsym->st_info) == STB_LOCAL) { + /* Local symbols we look up in the local table to be sure + we get the one that is really intended. */ + intsym = f->local_symtab[symndx]; + } else { + /* Others we look up in the hash table. */ + const char *name; + if (extsym->st_name) + name = strtab + extsym->st_name; + else + name = f->sections[extsym->st_shndx]->name; + intsym = obj_find_symbol(f, name); + } + + value = obj_symbol_final_value(f, intsym); + intsym->referenced = 1; + } +#if SHT_RELM == SHT_RELA +#if defined(__alpha__) && defined(AXP_BROKEN_GAS) + /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ + if (!extsym || !extsym->st_name + || ELF_ST_BIND(extsym->st_info) != STB_LOCAL) +#endif + value += rel->r_addend; +#endif + + /* Do it! */ + switch (arch_apply_relocation + (f, targsec, /*symsec,*/ intsym, rel, value) + ) { + case obj_reloc_ok: + break; + + case obj_reloc_overflow: + errmsg = "Relocation overflow"; + goto bad_reloc; + case obj_reloc_dangerous: + errmsg = "Dangerous relocation"; + goto bad_reloc; + case obj_reloc_unhandled: + errmsg = "Unhandled relocation"; +bad_reloc: + if (extsym) { + bb_error_msg("%s of type %ld for %s", errmsg, + (long) ELF_R_TYPE(rel->r_info), + strtab + extsym->st_name); + } else { + bb_error_msg("%s of type %ld", errmsg, + (long) ELF_R_TYPE(rel->r_info)); + } + ret = 0; + break; + } + } + } + + /* Finally, take care of the patches. */ + + if (f->string_patches) { + struct obj_string_patch *p; + struct obj_section *strsec; + ElfW(Addr) strsec_base; + strsec = obj_find_section(f, ".kstrtab"); + strsec_base = strsec->header.sh_addr; + + for (p = f->string_patches; p; p = p->next) { + struct obj_section *targsec = f->sections[p->reloc_secidx]; + *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) + = strsec_base + p->string_offset; + } + } + + if (f->symbol_patches) { + struct obj_symbol_patch *p; + + for (p = f->symbol_patches; p; p = p->next) { + struct obj_section *targsec = f->sections[p->reloc_secidx]; + *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) + = obj_symbol_final_value(f, p->sym); + } + } + + return ret; +} + +static int obj_create_image(struct obj_file *f, char *image) +{ + struct obj_section *sec; + ElfW(Addr) base = f->baseaddr; + + for (sec = f->load_order; sec; sec = sec->load_next) { + char *secimg; + + if (sec->contents == 0 || sec->header.sh_size == 0) + continue; + + secimg = image + (sec->header.sh_addr - base); + + /* Note that we allocated data for NOBITS sections earlier. */ + memcpy(secimg, sec->contents, sec->header.sh_size); + } + + return 1; +} + +/*======================================================================*/ + +static struct obj_file *obj_load(char *image, size_t image_size, int loadprogbits) +{ +#if BB_LITTLE_ENDIAN +# define ELFMAG_U32 ((uint32_t)(ELFMAG0 + 0x100 * (ELFMAG1 + (0x100 * (ELFMAG2 + 0x100 * ELFMAG3))))) +#else +# define ELFMAG_U32 ((uint32_t)((((ELFMAG0 * 0x100) + ELFMAG1) * 0x100 + ELFMAG2) * 0x100 + ELFMAG3)) +#endif + struct obj_file *f; + ElfW(Shdr) * section_headers; + size_t shnum, i; + char *shstrtab; + + /* Read the file header. */ + + f = arch_new_file(); + f->symbol_cmp = strcmp; + f->symbol_hash = obj_elf_hash; + f->load_order_search_start = &f->load_order; + + if (image_size < sizeof(f->header)) + bb_error_msg_and_die("error while loading ELF header"); + memcpy(&f->header, image, sizeof(f->header)); + + if (*(uint32_t*)(&f->header.e_ident) != ELFMAG_U32) { + bb_error_msg_and_die("not an ELF file"); + } + if (f->header.e_ident[EI_CLASS] != ELFCLASSM + || f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB) + || f->header.e_ident[EI_VERSION] != EV_CURRENT + || !MATCH_MACHINE(f->header.e_machine) + ) { + bb_error_msg_and_die("ELF file not for this architecture"); + } + if (f->header.e_type != ET_REL) { + bb_error_msg_and_die("ELF file not a relocatable object"); + } + + /* Read the section headers. */ + + if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { + bb_error_msg_and_die("section header size mismatch: %lu != %lu", + (unsigned long) f->header.e_shentsize, + (unsigned long) sizeof(ElfW(Shdr))); + } + + shnum = f->header.e_shnum; + /* Growth of ->sections vector will be done by + * xrealloc_vector(..., 2, ...), therefore we must allocate + * at least 2^2 = 4 extra elements here. */ + f->sections = xzalloc(sizeof(f->sections[0]) * (shnum + 4)); + + section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); + if (image_size < f->header.e_shoff + sizeof(ElfW(Shdr)) * shnum) + bb_error_msg_and_die("error while loading section headers"); + memcpy(section_headers, image + f->header.e_shoff, sizeof(ElfW(Shdr)) * shnum); + + /* Read the section data. */ + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec; + + f->sections[i] = sec = arch_new_section(); + + sec->header = section_headers[i]; + sec->idx = i; + + if (sec->header.sh_size) { + switch (sec->header.sh_type) { + case SHT_NULL: + case SHT_NOTE: + case SHT_NOBITS: + /* ignore */ + break; + case SHT_PROGBITS: +#if LOADBITS + if (!loadprogbits) { + sec->contents = NULL; + break; + } +#endif + case SHT_SYMTAB: + case SHT_STRTAB: + case SHT_RELM: + sec->contents = NULL; + if (sec->header.sh_size > 0) { + sec->contents = xmalloc(sec->header.sh_size); + if (image_size < (sec->header.sh_offset + sec->header.sh_size)) + bb_error_msg_and_die("error while loading section data"); + memcpy(sec->contents, image + sec->header.sh_offset, sec->header.sh_size); + } + break; +#if SHT_RELM == SHT_REL + case SHT_RELA: + bb_error_msg_and_die("RELA relocations not supported on this architecture"); +#else + case SHT_REL: + bb_error_msg_and_die("REL relocations not supported on this architecture"); +#endif + default: + if (sec->header.sh_type >= SHT_LOPROC) { + /* Assume processor specific section types are debug + info and can safely be ignored. If this is ever not + the case (Hello MIPS?), don't put ifdefs here but + create an arch_load_proc_section(). */ + break; + } + + bb_error_msg_and_die("can't handle sections of type %ld", + (long) sec->header.sh_type); + } + } + } + + /* Do what sort of interpretation as needed by each section. */ + + shstrtab = f->sections[f->header.e_shstrndx]->contents; + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec = f->sections[i]; + sec->name = shstrtab + sec->header.sh_name; + } + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec = f->sections[i]; + + /* .modinfo should be contents only but gcc has no attribute for that. + * The kernel may have marked .modinfo as ALLOC, ignore this bit. + */ + if (strcmp(sec->name, ".modinfo") == 0) + sec->header.sh_flags &= ~SHF_ALLOC; + + if (sec->header.sh_flags & SHF_ALLOC) + obj_insert_section_load_order(f, sec); + + switch (sec->header.sh_type) { + case SHT_SYMTAB: + { + unsigned long nsym, j; + char *strtab; + ElfW(Sym) * sym; + + if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { + bb_error_msg_and_die("symbol size mismatch: %lu != %lu", + (unsigned long) sec->header.sh_entsize, + (unsigned long) sizeof(ElfW(Sym))); + } + + nsym = sec->header.sh_size / sizeof(ElfW(Sym)); + strtab = f->sections[sec->header.sh_link]->contents; + sym = (ElfW(Sym) *) sec->contents; + + /* Allocate space for a table of local symbols. */ + j = f->local_symtab_size = sec->header.sh_info; + f->local_symtab = xzalloc(j * sizeof(struct obj_symbol *)); + + /* Insert all symbols into the hash table. */ + for (j = 1, ++sym; j < nsym; ++j, ++sym) { + ElfW(Addr) val = sym->st_value; + const char *name; + if (sym->st_name) + name = strtab + sym->st_name; + else if (sym->st_shndx < shnum) + name = f->sections[sym->st_shndx]->name; + else + continue; +#if defined(__SH5__) + /* + * For sh64 it is possible that the target of a branch + * requires a mode switch (32 to 16 and back again). + * + * This is implied by the lsb being set in the target + * address for SHmedia mode and clear for SHcompact. + */ + val |= sym->st_other & 4; +#endif + obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, + val, sym->st_size); + } + } + break; + + case SHT_RELM: + if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { + bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu", + (unsigned long) sec->header.sh_entsize, + (unsigned long) sizeof(ElfW(RelM))); + } + break; + /* XXX Relocation code from modutils-2.3.19 is not here. + * Why? That's about 20 lines of code from obj/obj_load.c, + * which gets done in a second pass through the sections. + * This BusyBox insmod does similar work in obj_relocate(). */ + } + } + + return f; +} + +#if ENABLE_FEATURE_INSMOD_LOADINKMEM +/* + * load the unloaded sections directly into the memory allocated by + * kernel for the module + */ + +static int obj_load_progbits(char *image, size_t image_size, struct obj_file *f, char *imagebase) +{ + ElfW(Addr) base = f->baseaddr; + struct obj_section* sec; + + for (sec = f->load_order; sec; sec = sec->load_next) { + /* section already loaded? */ + if (sec->contents != NULL) + continue; + if (sec->header.sh_size == 0) + continue; + sec->contents = imagebase + (sec->header.sh_addr - base); + if (image_size < (sec->header.sh_offset + sec->header.sh_size)) { + bb_error_msg("error reading ELF section data"); + return 0; /* need to delete half-loaded module! */ + } + memcpy(sec->contents, image + sec->header.sh_offset, sec->header.sh_size); + } + return 1; +} +#endif + +static void hide_special_symbols(struct obj_file *f) +{ + static const char *const specials[] = { + SPFX "cleanup_module", + SPFX "init_module", + SPFX "kernel_version", + NULL + }; + + struct obj_symbol *sym; + const char *const *p; + + for (p = specials; *p; ++p) { + sym = obj_find_symbol(f, *p); + if (sym != NULL) + sym->info = ELF_ST_INFO(STB_LOCAL, ELF_ST_TYPE(sym->info)); + } +} + + +#if ENABLE_FEATURE_CHECK_TAINTED_MODULE +static int obj_gpl_license(struct obj_file *f, const char **license) +{ + struct obj_section *sec; + /* This list must match *exactly* the list of allowable licenses in + * linux/include/linux/module.h. Checking for leading "GPL" will not + * work, somebody will use "GPL sucks, this is proprietary". + */ + static const char *const gpl_licenses[] = { + "GPL", + "GPL v2", + "GPL and additional rights", + "Dual BSD/GPL", + "Dual MPL/GPL" + }; + + sec = obj_find_section(f, ".modinfo"); + if (sec) { + const char *value, *ptr, *endptr; + ptr = sec->contents; + endptr = ptr + sec->header.sh_size; + while (ptr < endptr) { + value = strchr(ptr, '='); + if (value && strncmp(ptr, "license", value-ptr) == 0) { + unsigned i; + if (license) + *license = value+1; + for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) { + if (strcmp(value+1, gpl_licenses[i]) == 0) + return 0; + } + return 2; + } + ptr = strchr(ptr, '\0'); + if (ptr) + ptr++; + else + ptr = endptr; + } + } + return 1; +} + +#define TAINT_FILENAME "/proc/sys/kernel/tainted" +#define TAINT_PROPRIETORY_MODULE (1 << 0) +#define TAINT_FORCED_MODULE (1 << 1) +#define TAINT_UNSAFE_SMP (1 << 2) +#define TAINT_URL "http://www.tux.org/lkml/#export-tainted" + +static void set_tainted(int fd, const char *m_name, + int kernel_has_tainted, int taint, const char *text1, const char *text2) +{ + static smallint printed_info; + + char buf[80]; + int oldval; + + if (fd < 0 && !kernel_has_tainted) + return; /* New modutils on old kernel */ + printf("Warning: loading %s will taint the kernel: %s%s\n", + m_name, text1, text2); + if (!printed_info) { + printf(" See %s for information about tainted modules\n", TAINT_URL); + printed_info = 1; + } + if (fd >= 0) { + read(fd, buf, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + oldval = strtoul(buf, NULL, 10); + sprintf(buf, "%d\n", oldval | taint); + xwrite_str(fd, buf); + } +} + +/* Check if loading this module will taint the kernel. */ +static void check_tainted_module(struct obj_file *f, const char *m_name) +{ + static const char tainted_file[] ALIGN1 = TAINT_FILENAME; + + int fd, kernel_has_tainted; + const char *ptr; + + kernel_has_tainted = 1; + fd = open(tainted_file, O_RDWR); + if (fd < 0) { + if (errno == ENOENT) + kernel_has_tainted = 0; + else if (errno == EACCES) + kernel_has_tainted = 1; + else { + perror(tainted_file); + kernel_has_tainted = 0; + } + } + + switch (obj_gpl_license(f, &ptr)) { + case 0: + break; + case 1: + set_tainted(fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", ""); + break; + default: /* case 2: */ + /* The module has a non-GPL license so we pretend that the + * kernel always has a taint flag to get a warning even on + * kernels without the proc flag. + */ + set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr); + break; + } + + if (flag_force_load) + set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", ""); + + if (fd >= 0) + close(fd); +} +#else /* !FEATURE_CHECK_TAINTED_MODULE */ +#define check_tainted_module(x, y) do { } while (0); +#endif + +#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS +/* add module source, timestamp, kernel version and a symbol for the + * start of some sections. this info is used by ksymoops to do better + * debugging. + */ +#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING +#define get_module_version(f, str) get_module_version(str) +#endif +static int +get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING + return new_get_module_version(f, str); +#else + strncpy(str, "???", sizeof(str)); + return -1; +#endif +} + +/* add module source, timestamp, kernel version and a symbol for the + * start of some sections. this info is used by ksymoops to do better + * debugging. + */ +static void +add_ksymoops_symbols(struct obj_file *f, const char *filename, + const char *m_name) +{ + static const char symprefix[] ALIGN1 = "__insmod_"; + static const char section_names[][8] = { + ".text", + ".rodata", + ".data", + ".bss", + ".sbss" + }; + + struct obj_section *sec; + struct obj_symbol *sym; + char *name, *absolute_filename; + char str[STRVERSIONLEN]; + unsigned i; + int lm_name, lfilename, use_ksymtab, version; + struct stat statbuf; + + /* WARNING: was using realpath, but replaced by readlink to stop using + * lots of stack. But here it seems to be able to cause problems? */ + absolute_filename = xmalloc_readlink(filename); + if (!absolute_filename) + absolute_filename = xstrdup(filename); + + lm_name = strlen(m_name); + lfilename = strlen(absolute_filename); + + /* add to ksymtab if it already exists or there is no ksymtab and other symbols + * are not to be exported. otherwise leave ksymtab alone for now, the + * "export all symbols" compatibility code will export these symbols later. + */ + use_ksymtab = obj_find_section(f, "__ksymtab") || flag_noexport; + + sec = obj_find_section(f, ".this"); + if (sec) { + /* tag the module header with the object name, last modified + * timestamp and module version. worst case for module version + * is 0xffffff, decimal 16777215. putting all three fields in + * one symbol is less readable but saves kernel space. + */ + if (stat(absolute_filename, &statbuf) != 0) + statbuf.st_mtime = 0; + version = get_module_version(f, str); /* -1 if not found */ + name = xasprintf("%s%s_O%s_M%0*lX_V%d", + symprefix, m_name, absolute_filename, + (int)(2 * sizeof(statbuf.st_mtime)), + (long)statbuf.st_mtime, + version); + sym = obj_add_symbol(f, name, -1, + ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), + sec->idx, sec->header.sh_addr, 0); + if (use_ksymtab) + new_add_ksymtab(f, sym); + } + free(absolute_filename); +#ifdef _NOT_SUPPORTED_ + /* record where the persistent data is going, same address as previous symbol */ + if (f->persist) { + name = xasprintf("%s%s_P%s", + symprefix, m_name, f->persist); + sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), + sec->idx, sec->header.sh_addr, 0); + if (use_ksymtab) + new_add_ksymtab(f, sym); + } +#endif + /* tag the desired sections if size is non-zero */ + for (i = 0; i < ARRAY_SIZE(section_names); ++i) { + sec = obj_find_section(f, section_names[i]); + if (sec && sec->header.sh_size) { + name = xasprintf("%s%s_S%s_L%ld", + symprefix, m_name, sec->name, + (long)sec->header.sh_size); + sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), + sec->idx, sec->header.sh_addr, 0); + if (use_ksymtab) + new_add_ksymtab(f, sym); + } + } +} +#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ + +#if ENABLE_FEATURE_INSMOD_LOAD_MAP +static void print_load_map(struct obj_file *f) +{ + struct obj_section *sec; +#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL + struct obj_symbol **all, **p; + int i, nsyms; + char *loaded; /* array of booleans */ + struct obj_symbol *sym; +#endif + /* Report on the section layout. */ + printf("Sections: Size %-*s Align\n", + (int) (2 * sizeof(void *)), "Address"); + + for (sec = f->load_order; sec; sec = sec->load_next) { + int a; + unsigned long tmp; + + for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a) + tmp >>= 1; + if (a == -1) + a = 0; + + printf("%-15s %08lx %0*lx 2**%d\n", + sec->name, + (long)sec->header.sh_size, + (int) (2 * sizeof(void *)), + (long)sec->header.sh_addr, + a); + } +#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL + /* Quick reference which section indices are loaded. */ + i = f->header.e_shnum; + loaded = alloca(i * sizeof(loaded[0])); + while (--i >= 0) + loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0); + + /* Collect the symbols we'll be listing. */ + for (nsyms = i = 0; i < HASH_BUCKETS; ++i) + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]) + ) { + ++nsyms; + } + + all = alloca(nsyms * sizeof(all[0])); + + for (i = 0, p = all; i < HASH_BUCKETS; ++i) + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]) + ) { + *p++ = sym; + } + + /* And list them. */ + printf("\nSymbols:\n"); + for (p = all; p < all + nsyms; ++p) { + char type = '?'; + unsigned long value; + + sym = *p; + if (sym->secidx == SHN_ABS) { + type = 'A'; + value = sym->value; + } else if (sym->secidx == SHN_UNDEF) { + type = 'U'; + value = 0; + } else { + sec = f->sections[sym->secidx]; + + if (sec->header.sh_type == SHT_NOBITS) + type = 'B'; + else if (sec->header.sh_flags & SHF_ALLOC) { + if (sec->header.sh_flags & SHF_EXECINSTR) + type = 'T'; + else if (sec->header.sh_flags & SHF_WRITE) + type = 'D'; + else + type = 'R'; + } + value = sym->value + sec->header.sh_addr; + } + + if (ELF_ST_BIND(sym->info) == STB_LOCAL) + type |= 0x20; /* tolower. safe for '?' too */ + + printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value, + type, sym->name); + } +#endif +} +#else /* !FEATURE_INSMOD_LOAD_MAP */ +static void print_load_map(struct obj_file *f UNUSED_PARAM) +{ +} +#endif + +int FAST_FUNC bb_init_module_24(const char *m_filename, const char *options) +{ + int k_crcs; + unsigned long m_size; + ElfW(Addr) m_addr; + struct obj_file *f; + int exit_status = EXIT_FAILURE; + char *m_name; +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING + int m_has_modinfo; +#endif + char *image; + size_t image_size = 64 * 1024 * 1024; + + /* Load module into memory and unzip if compressed */ + image = xmalloc_open_zipped_read_close(m_filename, &image_size); + if (!image) + return EXIT_FAILURE; + + m_name = xstrdup(bb_basename(m_filename)); + /* "module.o[.gz]" -> "module" */ + *strchrnul(m_name, '.') = '\0'; + + f = obj_load(image, image_size, LOADBITS); + +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING + /* Version correspondence? */ + m_has_modinfo = (get_modinfo_value(f, "kernel_version") != NULL); + if (!flag_quiet) { + char m_strversion[STRVERSIONLEN]; + struct utsname uts; + + if (m_has_modinfo) { + int m_version = new_get_module_version(f, m_strversion); + if (m_version == -1) { + bb_error_msg_and_die("can't find the kernel version " + "the module was compiled for"); + } + } + + uname(&uts); + if (strncmp(uts.release, m_strversion, STRVERSIONLEN) != 0) { + bb_error_msg("%skernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s", + flag_force_load ? "warning: " : "", + m_name, m_strversion, uts.release); + if (!flag_force_load) + goto out; + } + } +#endif + + if (query_module(NULL, 0, NULL, 0, NULL)) + bb_error_msg_and_die("old (unsupported) kernel"); + new_get_kernel_symbols(); + k_crcs = new_is_kernel_checksummed(); + +#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING + { + int m_crcs = 0; + if (m_has_modinfo) + m_crcs = new_is_module_checksummed(f); + if (m_crcs != k_crcs) + obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); + } +#endif + + /* Let the module know about the kernel symbols. */ + add_kernel_symbols(f); + + /* Allocate common symbols, symbol tables, and string tables. */ + new_create_this_module(f, m_name); + obj_check_undefineds(f); + obj_allocate_commons(f); + check_tainted_module(f, m_name); + + /* Done with the module name, on to the optional var=value arguments */ + new_process_module_arguments(f, options); + + arch_create_got(f); + hide_special_symbols(f); + +#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS + add_ksymoops_symbols(f, m_filename, m_name); +#endif + + new_create_module_ksymtab(f); + + /* Find current size of the module */ + m_size = obj_load_size(f); + + m_addr = create_module(m_name, m_size); + if (m_addr == (ElfW(Addr))(-1)) switch (errno) { + case EEXIST: + bb_error_msg_and_die("a module named %s already exists", m_name); + case ENOMEM: + bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes", + m_size); + default: + bb_perror_msg_and_die("create_module: %s", m_name); + } + +#if !LOADBITS + /* + * the PROGBITS section was not loaded by the obj_load + * now we can load them directly into the kernel memory + */ + if (!obj_load_progbits(image, image_size, f, (char*)m_addr)) { + delete_module(m_name, 0); + goto out; + } +#endif + + if (!obj_relocate(f, m_addr)) { + delete_module(m_name, 0); + goto out; + } + + if (!new_init_module(m_name, f, m_size)) { + delete_module(m_name, 0); + goto out; + } + + if (flag_print_load_map) + print_load_map(f); + + exit_status = EXIT_SUCCESS; + + out: + free(image); + free(m_name); + + return exit_status; +} diff --git a/release/src/router/busybox/modutils/modutils.c b/release/src/router/busybox/modutils/modutils.c new file mode 100644 index 0000000000..0f6cb0f2db --- /dev/null +++ b/release/src/router/busybox/modutils/modutils.c @@ -0,0 +1,129 @@ +/* + * Common modutils related functions for busybox + * + * Copyright (C) 2008 by Timo Teras + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ +#include "modutils.h" + +#ifdef __UCLIBC__ +extern int init_module(void *module, unsigned long len, const char *options); +extern int delete_module(const char *module, unsigned int flags); +#else +# include +# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) +# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) +#endif + +void FAST_FUNC replace(char *s, char what, char with) +{ + while (*s) { + if (what == *s) + *s = with; + ++s; + } +} + +char * FAST_FUNC replace_underscores(char *s) +{ + replace(s, '-', '_'); + return s; +} + +int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) +{ + char *tok; + int len = 0; + + while ((tok = strsep(&string, delim)) != NULL) { + if (tok[0] == '\0') + continue; + llist_add_to_end(llist, xstrdup(tok)); + len += strlen(tok); + } + return len; +} + +char * FAST_FUNC filename2modname(const char *filename, char *modname) +{ + int i; + char *from; + + if (filename == NULL) + return NULL; + if (modname == NULL) + modname = xmalloc(MODULE_NAME_LEN); + from = bb_get_last_path_component_nostrip(filename); + for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) + modname[i] = (from[i] == '-') ? '_' : from[i]; + modname[i] = 0; + + return modname; +} + +const char * FAST_FUNC moderror(int err) +{ + switch (err) { + case -1: + return "no such module"; + case ENOEXEC: + return "invalid module format"; + case ENOENT: + return "unknown symbol in module, or unknown parameter"; + case ESRCH: + return "module has wrong symbol version"; + case ENOSYS: + return "kernel does not support requested operation"; + default: + return strerror(err); + } +} + +char * FAST_FUNC parse_cmdline_module_options(char **argv) +{ + char *options; + int optlen; + + options = xzalloc(1); + optlen = 0; + while (*++argv) { + options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); + /* Spaces handled by "" pairs, but no way of escaping quotes */ + optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv); + } + return options; +} + +int FAST_FUNC bb_init_module(const char *filename, const char *options) +{ + size_t len; + char *image; + int rc; + + if (!options) + options = ""; + +#if ENABLE_FEATURE_2_4_MODULES + if (get_linux_version_code() < KERNEL_VERSION(2,6,0)) + return bb_init_module_24(filename, options); +#endif + + /* Use the 2.6 way */ + len = INT_MAX - 4095; + rc = ENOENT; + image = xmalloc_open_zipped_read_close(filename, &len); + if (image) { + rc = 0; + if (init_module(image, len, options) != 0) + rc = errno; + free(image); + } + + return rc; +} + +int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) +{ + return delete_module(module, flags); +} diff --git a/release/src/router/busybox/modutils/modutils.h b/release/src/router/busybox/modutils/modutils.h new file mode 100644 index 0000000000..5104f1b6ed --- /dev/null +++ b/release/src/router/busybox/modutils/modutils.h @@ -0,0 +1,64 @@ +/* + * Common modutils related functions for busybox + * + * Copyright (C) 2008 by Timo Teras + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#ifndef MODUTILS_H +#define MODUTILS_H 1 + +#include "libbb.h" + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +/* linux/include/linux/module.h has 64, but this is also used + * internally for the maximum alias name length, which can be quite long */ +#define MODULE_NAME_LEN 256 + +const char *moderror(int err) FAST_FUNC; +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; + +#define INSMOD_OPTS \ + "vq" \ + USE_FEATURE_2_4_MODULES("sLo:fkx") \ + USE_FEATURE_INSMOD_LOAD_MAP("m") + +#define INSMOD_ARGS USE_FEATURE_2_4_MODULES(, NULL) + +enum { + INSMOD_OPT_VERBOSE = 0x0001, + INSMOD_OPT_SILENT = 0x0002, + INSMOD_OPT_SYSLOG = 0x0004 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_LOCK = 0x0008 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_OUTPUTNAME = 0x0010 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_FORCE = 0x0020 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_KERNELD = 0x0040 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_NO_EXPORT = 0x0080 * ENABLE_FEATURE_2_4_MODULES, + INSMOD_OPT_PRINT_MAP = 0x0100 * ENABLE_FEATURE_INSMOD_LOAD_MAP, +#if ENABLE_FEATURE_2_4_MODULES +# if ENABLE_FEATURE_INSMOD_LOAD_MAP + INSMOD_OPT_UNUSED = 0x0200, +# else + INSMOD_OPT_UNUSED = 0x0100, +# endif +#else + INSMOD_OPT_UNUSED = 0x0004, +#endif +}; + +int FAST_FUNC bb_init_module(const char *module, const char *options); +int FAST_FUNC bb_delete_module(const char *module, unsigned int flags); + +#if ENABLE_FEATURE_2_4_MODULES +int FAST_FUNC bb_init_module_24(const char *module, const char *options); +#endif + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/release/src/router/busybox/modutils/rmmod.c b/release/src/router/busybox/modutils/rmmod.c dissimilarity index 76% index 5129b34958..ee32dfdefc 100644 --- a/release/src/router/busybox/modutils/rmmod.c +++ b/release/src/router/busybox/modutils/rmmod.c @@ -1,100 +1,53 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rmmod implementation for busybox - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -#ifdef __UCLIBC__ -extern int delete_module(const char *module, unsigned int flags); -#else -# include -# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) -#endif - -#if ENABLE_FEATURE_2_6_MODULES -static void filename2modname(char *modname, const char *afterslash) -{ - unsigned int i; - int kr_chk = 1; - - if (ENABLE_FEATURE_2_4_MODULES - && get_linux_version_code() <= KERNEL_VERSION(2,6,0)) - kr_chk = 0; - - /* Convert to underscores, stop at first . */ - for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) { - if (kr_chk && (afterslash[i] == '-')) - modname[i] = '_'; - else - modname[i] = afterslash[i]; - } - modname[i] = '\0'; -} -#else -void filename2modname(char *modname, const char *afterslash); -#endif - -// There really should be a header file for this... - -int query_module(const char *name, int which, void *buf, - size_t bufsize, size_t *ret); - -int rmmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int rmmod_main(int argc, char **argv) -{ - int n, ret = EXIT_SUCCESS; - unsigned int flags = O_NONBLOCK|O_EXCL; - -#define misc_buf bb_common_bufsiz1 - - /* Parse command line. */ - n = getopt32(argv, "wfa"); - if (n & 1) // --wait - flags &= ~O_NONBLOCK; - if (n & 2) // --force - flags |= O_TRUNC; - if (n & 4) { - /* Unload _all_ unused modules via NULL delete_module() call */ - /* until the number of modules does not change */ - size_t nmod = 0; /* number of modules */ - size_t pnmod = -1; /* previous number of modules */ - - while (nmod != pnmod) { - if (delete_module(NULL, flags) != 0) { - if (errno == EFAULT) - return ret; - bb_perror_msg_and_die("rmmod"); - } - pnmod = nmod; - // the 1 here is QM_MODULES. - if (ENABLE_FEATURE_QUERY_MODULE_INTERFACE && query_module(NULL, - 1, misc_buf, sizeof(misc_buf), - &nmod)) - { - bb_perror_msg_and_die("QM_MODULES"); - } - } - return EXIT_SUCCESS; - } - - if (optind == argc) - bb_show_usage(); - - for (n = optind; n < argc; n++) { - if (ENABLE_FEATURE_2_6_MODULES) { - filename2modname(misc_buf, bb_basename(argv[n])); - } - - if (delete_module(ENABLE_FEATURE_2_6_MODULES ? misc_buf : argv[n], flags)) { - bb_simple_perror_msg(argv[n]); - ret = EXIT_FAILURE; - } - } - - return ret; -} +/* vi: set sw=4 ts=4: */ +/* + * Mini rmmod implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2008 Timo Teras + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "modutils.h" + +int rmmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rmmod_main(int argc UNUSED_PARAM, char **argv) +{ + int n; + unsigned flags = O_NONBLOCK | O_EXCL; + + /* Parse command line. */ + n = getopt32(argv, "wfas"); // -s ignored + argv += optind; + if (n & 1) // --wait + flags &= ~O_NONBLOCK; + if (n & 2) // --force + flags |= O_TRUNC; + if (n & 4) { + /* Unload _all_ unused modules via NULL delete_module() call */ + if (bb_delete_module(NULL, flags) != 0 && errno != EFAULT) + bb_perror_msg_and_die("rmmod"); + return EXIT_SUCCESS; + } + + if (!*argv) + bb_show_usage(); + + n = ENABLE_FEATURE_2_4_MODULES && get_linux_version_code() < KERNEL_VERSION(2,6,0); + while (*argv) { + char modname[MODULE_NAME_LEN]; + const char *bname; + + bname = bb_basename(*argv++); + if (n) + safe_strncpy(modname, bname, MODULE_NAME_LEN); + else + filename2modname(bname, modname); + if (bb_delete_module(modname, flags)) + bb_error_msg_and_die("can't unload '%s': %s", + modname, moderror(errno)); + } + + return EXIT_SUCCESS; +} diff --git a/release/src/router/busybox/networking/Config.in b/release/src/router/busybox/networking/Config.in index 91f172997d..392afcf891 100644 --- a/release/src/router/busybox/networking/Config.in +++ b/release/src/router/busybox/networking/Config.in @@ -13,7 +13,7 @@ config FEATURE_IPV6 This adds IPv6 support in the networking applets. config FEATURE_PREFER_IPV4_ADDRESS - bool "Preferentially use IPv4 addresses from DNS queries" + bool "Prefer IPv4 addresses from DNS queries" default y depends on FEATURE_IPV6 help @@ -93,6 +93,19 @@ config FAKEIDENTD fakeidentd listens on the ident port and returns a predefined fake value on any query. +config FTPD + bool "ftpd" + default n + help + simple FTP daemon. You have to run it via inetd. + +config FEATURE_FTP_WRITE + bool "Enable upload commands" + default y + depends on FTPD + help + Enable all kinds of FTP upload commands (-w option) + config FTPGET bool "ftpget" default n @@ -141,14 +154,6 @@ config FEATURE_HTTPD_USE_SENDFILE When enabled, httpd will use the kernel sendfile() function instead of read/write loop. -config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP - bool "Support reloading of global config file on HUP signal" - default n - depends on HTTPD - help - This option enables processing of SIGHUP to reload cached - configuration settings. - config FEATURE_HTTPD_SETUID bool "Enable -u option" default n @@ -175,14 +180,6 @@ config FEATURE_HTTPD_AUTH_MD5 Enables basic per URL authentication from /etc/httpd.conf using md5 passwords. -config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES - bool "Support loading additional MIME types at run-time" - default n - depends on HTTPD - help - This option enables support for additional MIME types at - run-time to be specified in the configuration file. - config FEATURE_HTTPD_CGI bool "Support Common Gateway Interface (CGI)" default y @@ -681,18 +678,6 @@ config ROUTE help Route displays or manipulates the kernel's IP routing tables. -config SENDMAIL - bool "sendmail" - default n - help - Barebones sendmail. - -config FETCHMAIL - bool "fetchmail" - default n - help - Barebones fetchmail. - config SLATTACH bool "slattach" default n @@ -700,6 +685,16 @@ config SLATTACH slattach is a small utility to attach network interfaces to serial lines. +#config TC +# bool "tc" +# default n +# help +# show / manipulate traffic control settings +# +#config FEATURE_TC_INGRESS +# def_bool n +# depends on TC + config TELNET bool "telnet" default n @@ -820,10 +815,10 @@ config FEATURE_TFTP_BLOCKSIZE Allow tftp to specify block size, and tftpd to understand "blksize" option. -config DEBUG_TFTP +config TFTP_DEBUG bool "Enable debug" default n - depends on TFTP + depends on TFTP || TFTPD help Enable debug settings for tftp. This is useful if you're running into problems with tftp as the protocol doesn't help you much when @@ -840,7 +835,7 @@ config FEATURE_TRACEROUTE_VERBOSE default n depends on TRACEROUTE help - Add some verbosity to traceroute. This includes amongst other things + Add some verbosity to traceroute. This includes among other things hostnames and ICMP response types. config FEATURE_TRACEROUTE_SOURCE_ROUTE @@ -856,10 +851,19 @@ config FEATURE_TRACEROUTE_USE_ICMP default n depends on TRACEROUTE help - Add feature to allow for ICMP ECHO instead of UDP datagrams. + Add option -I to use ICMP ECHO instead of UDP datagrams. source networking/udhcp/Config.in +config IFUPDOWN_UDHCPC_CMD_OPTIONS + string "ifup udhcpc command line options" + default "-R -n" + depends on IFUPDOWN && APP_UDHCPC + help + Command line options to pass to udhcpc from ifup. + Intended to alter options not available in /etc/network/interfaces. + (IE: --syslog --background etc...) + config VCONFIG bool "vconfig" default n @@ -913,6 +917,20 @@ config TCPSVD tcpsvd listens on a TCP port and runs a program for each new connection. +config TUNCTL + bool "tunctl" + default n + help + tunctl creates or deletes tun devices. + +config FEATURE_TUNCTL_UG + bool "Support owner:group assignment" + default n + depends on TUNCTL + help + Allow to specify owner and group of newly created interface. + 340 bytes of pure bloat. Say no here. + config UDPSVD bool "udpsvd" default n diff --git a/release/src/router/busybox/networking/Kbuild b/release/src/router/busybox/networking/Kbuild index be2ef94ddd..d632774ff1 100644 --- a/release/src/router/busybox/networking/Kbuild +++ b/release/src/router/busybox/networking/Kbuild @@ -11,7 +11,7 @@ lib-$(CONFIG_BRCTL) += brctl.o lib-$(CONFIG_DNSD) += dnsd.o lib-$(CONFIG_ETHER_WAKE) += ether-wake.o lib-$(CONFIG_FAKEIDENTD) += isrv_identd.o isrv.o -lib-$(CONFIG_FETCHMAIL) += sendmail.o +lib-$(CONFIG_FTPD) += ftpd.o lib-$(CONFIG_FTPGET) += ftpgetput.o lib-$(CONFIG_FTPPUT) += ftpgetput.o lib-$(CONFIG_HOSTNAME) += hostname.o @@ -30,13 +30,14 @@ lib-$(CONFIG_PING) += ping.o lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o -lib-$(CONFIG_SENDMAIL) += sendmail.o lib-$(CONFIG_SLATTACH) += slattach.o +lib-$(CONFIG_TC) += tc.o lib-$(CONFIG_TELNET) += telnet.o lib-$(CONFIG_TELNETD) += telnetd.o lib-$(CONFIG_TFTP) += tftp.o lib-$(CONFIG_TFTPD) += tftp.o lib-$(CONFIG_TRACEROUTE) += traceroute.o +lib-$(CONFIG_TUNCTL) += tunctl.o lib-$(CONFIG_VCONFIG) += vconfig.o lib-$(CONFIG_WGET) += wget.o lib-$(CONFIG_ZCIP) += zcip.o diff --git a/release/src/router/busybox/networking/arp.c b/release/src/router/busybox/networking/arp.c index e2c5bbb7f6..278f2dc9a3 100644 --- a/release/src/router/busybox/networking/arp.c +++ b/release/src/router/busybox/networking/arp.c @@ -27,24 +27,40 @@ #define DFLT_AF "inet" #define DFLT_HW "ether" -#define ARP_OPT_A (0x1) -#define ARP_OPT_p (0x2) -#define ARP_OPT_H (0x4) -#define ARP_OPT_t (0x8) -#define ARP_OPT_i (0x10) -#define ARP_OPT_a (0x20) -#define ARP_OPT_d (0x40) -#define ARP_OPT_n (0x80) /* do not resolve addresses */ -#define ARP_OPT_D (0x100) /* HW-address is devicename */ -#define ARP_OPT_s (0x200) -#define ARP_OPT_v (0x400 * DEBUG) /* debugging output flag */ - - -static const struct aftype *ap; /* current address family */ -static const struct hwtype *hw; /* current hardware type */ -static int sockfd; /* active socket descriptor */ -static smallint hw_set; /* flag if hw-type was set (-H) */ -static const char *device = ""; /* current device */ +enum { + ARP_OPT_A = (1 << 0), + ARP_OPT_p = (1 << 1), + ARP_OPT_H = (1 << 2), + ARP_OPT_t = (1 << 3), + ARP_OPT_i = (1 << 4), + ARP_OPT_a = (1 << 5), + ARP_OPT_d = (1 << 6), + ARP_OPT_n = (1 << 7), /* do not resolve addresses */ + ARP_OPT_D = (1 << 8), /* HW-address is devicename */ + ARP_OPT_s = (1 << 9), + ARP_OPT_v = (1 << 10) * DEBUG, /* debugging output flag */ +}; + +enum { + sockfd = 3, /* active socket descriptor */ +}; + +struct globals { + const struct aftype *ap; /* current address family */ + const struct hwtype *hw; /* current hardware type */ + const char *device; /* current device */ + smallint hw_set; /* flag if hw-type was set (-H) */ + +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define ap (G.ap ) +#define hw (G.hw ) +#define device (G.device ) +#define hw_set (G.hw_set ) +#define INIT_G() do { \ + device = ""; \ +} while (0) + static const char options[] ALIGN1 = "pub\0" @@ -445,27 +461,30 @@ int arp_main(int argc UNUSED_PARAM, char **argv) { const char *hw_type = "ether"; const char *protocol; + unsigned opts; + + INIT_G(); - /* Initialize variables... */ + xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sockfd); ap = get_aftype(DFLT_AF); if (!ap) bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family"); - getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol, + opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol, &hw_type, &hw_type, &device); argv += optind; - if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) { + if (opts & (ARP_OPT_A | ARP_OPT_p)) { ap = get_aftype(protocol); if (ap == NULL) bb_error_msg_and_die("%s: unknown %s", protocol, "address family"); } - if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) { + if (opts & (ARP_OPT_A | ARP_OPT_p)) { hw = get_hwtype(hw_type); if (hw == NULL) bb_error_msg_and_die("%s: unknown %s", hw_type, "hardware type"); hw_set = 1; } - //if (option_mask32 & ARP_OPT_i)... -i + //if (opts & ARP_OPT_i)... -i if (ap->af != AF_INET) { bb_error_msg_and_die("%s: kernel only supports 'inet'", ap->name); @@ -482,16 +501,15 @@ int arp_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("%s: %s without ARP support", hw->name, "hardware type"); } - sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); /* Now see what we have to do here... */ - if (option_mask32 & (ARP_OPT_d|ARP_OPT_s)) { + if (opts & (ARP_OPT_d | ARP_OPT_s)) { if (argv[0] == NULL) bb_error_msg_and_die("need host name"); - if (option_mask32 & ARP_OPT_s) + if (opts & ARP_OPT_s) return arp_set(argv); return arp_del(argv); } - //if (option_mask32 & ARP_OPT_a) - default + //if (opts & ARP_OPT_a) - default return arp_show(argv[0]); } diff --git a/release/src/router/busybox/networking/arping.c b/release/src/router/busybox/networking/arping.c index aba32b8692..915af32618 100644 --- a/release/src/router/busybox/networking/arping.c +++ b/release/src/router/busybox/networking/arping.c @@ -153,6 +153,15 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) struct arphdr *ah = (struct arphdr *) buf; unsigned char *p = (unsigned char *) (ah + 1); struct in_addr src_ip, dst_ip; + /* moves below assume in_addr is 4 bytes big, ensure that */ + struct BUG_in_addr_must_be_4 { + char BUG_in_addr_must_be_4[ + sizeof(struct in_addr) == 4 ? 1 : -1 + ]; + char BUG_s_addr_must_be_4[ + sizeof(src_ip.s_addr) == 4 ? 1 : -1 + ]; + }; /* Filter out wild packets */ if (FROM->sll_pkttype != PACKET_HOST @@ -171,13 +180,13 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) /* Protocol must be IP. */ if (ah->ar_pro != htons(ETH_P_IP) - || (ah->ar_pln != 4) - || (ah->ar_hln != me.sll_halen) - || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) + || (ah->ar_pln != 4) + || (ah->ar_hln != me.sll_halen) + || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) return false; - memcpy(&src_ip, p + ah->ar_hln, 4); - memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); + move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); + move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); if (dst.s_addr != src_ip.s_addr) return false; @@ -200,7 +209,7 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) dst_ip/dst_hw do not matter. */ if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0) - || (src.s_addr && src.s_addr != dst_ip.s_addr)) + || (src.s_addr && src.s_addr != dst_ip.s_addr)) return false; } if (!(option_mask32 & QUIET)) { @@ -286,7 +295,7 @@ int arping_main(int argc UNUSED_PARAM, char **argv) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); + strncpy_IFNAMSIZ(ifr.ifr_name, device); /* We use ifr.ifr_name in error msg so that problem * with truncated name will be visible */ ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found"); @@ -306,7 +315,7 @@ int arping_main(int argc UNUSED_PARAM, char **argv) /* if (!inet_aton(target, &dst)) - not needed */ { len_and_sockaddr *lsa; lsa = xhost_and_af2sockaddr(target, 0, AF_INET); - memcpy(&dst, &lsa->u.sin.sin_addr.s_addr, 4); + dst = lsa->u.sin.sin_addr; if (ENABLE_FEATURE_CLEAN_UP) free(lsa); } @@ -322,8 +331,7 @@ int arping_main(int argc UNUSED_PARAM, char **argv) struct sockaddr_in saddr; int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); - if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) - bb_perror_msg("cannot bind to device %s", device); + setsockopt_bindtodevice(probe_fd, device); memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; if (src.s_addr) { diff --git a/release/src/router/busybox/networking/brctl.c b/release/src/router/busybox/networking/brctl.c index 102776e806..1b52689473 100644 --- a/release/src/router/busybox/networking/brctl.c +++ b/release/src/router/busybox/networking/brctl.c @@ -2,7 +2,7 @@ /* * Small implementation of brctl for busybox. * - * Copyright (C) 2008 by Bernhard Fischer + * Copyright (C) 2008 by Bernhard Reutner-Fischer * * Some helper functions from bridge-utils are * Copyright (C) 2000 Lennert Buytenhek @@ -16,6 +16,20 @@ #include #include +#ifndef SIOCBRADDBR +# define SIOCBRADDBR BRCTL_ADD_BRIDGE +#endif +#ifndef SIOCBRDELBR +# define SIOCBRDELBR BRCTL_DEL_BRIDGE +#endif +#ifndef SIOCBRADDIF +# define SIOCBRADDIF BRCTL_ADD_IF +#endif +#ifndef SIOCBRDELIF +# define SIOCBRDELIF BRCTL_DEL_IF +#endif + + /* Maximum number of ports supported per bridge interface. */ #ifndef MAX_PORTS #define MAX_PORTS 32 @@ -137,7 +151,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) if (!if_indextoname(bridx[i], brname)) bb_perror_msg_and_die("can't get bridge name for index %d", i); - strncpy(ifr.ifr_name, brname, IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.ifr_name, brname); arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, (unsigned long) &bi, 0); @@ -191,7 +205,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) if (!*argv) /* all but 'addif/delif' need at least two arguments */ bb_show_usage(); - strncpy(ifr.ifr_name, br, IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.ifr_name, br); if (key == ARG_addif || key == ARG_delif) { /* addif or delif */ brif = *argv; ifr.ifr_ifindex = if_nametoindex(brif); diff --git a/release/src/router/busybox/networking/dnsd.c b/release/src/router/busybox/networking/dnsd.c dissimilarity index 64% index e8dcb404b0..56ede3fca2 100644 --- a/release/src/router/busybox/networking/dnsd.c +++ b/release/src/router/busybox/networking/dnsd.c @@ -1,380 +1,518 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini DNS server implementation for busybox - * - * Copyright (C) 2005 Roberto A. Foglietta (me@roberto.foglietta.name) - * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no) - * Copyright (C) 2003 Paul Sheer - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote - * it into a shape which I believe is both easier to understand and maintain. - * I also reused the input buffer for output and removed services he did not - * need. [1] http://threading.2038bug.com/sheerdns/ - * - * Some bugfix and minor changes was applied by Roberto A. Foglietta who made - * the first porting of oao' scdns to busybox also. - */ - -#include "libbb.h" -#include - -//#define DEBUG 1 -#define DEBUG 0 - -enum { - MAX_HOST_LEN = 16, // longest host name allowed is 15 - IP_STRING_LEN = 18, // .xxx.xxx.xxx.xxx\0 - -//must be strlen('.in-addr.arpa') larger than IP_STRING_LEN - MAX_NAME_LEN = (IP_STRING_LEN + 13), - -/* Cannot get bigger packets than 512 per RFC1035 - In practice this can be set considerably smaller: - Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) + - ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) + - 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte -*/ - MAX_PACK_LEN = 512, - - DEFAULT_TTL = 30, // increase this when not testing? - - REQ_A = 1, - REQ_PTR = 12 -}; - -struct dns_head { // the message from client and first part of response mag - uint16_t id; - uint16_t flags; - uint16_t nquer; // accepts 0 - uint16_t nansw; // 1 in response - uint16_t nauth; // 0 - uint16_t nadd; // 0 -}; -struct dns_prop { - uint16_t type; - uint16_t class; -}; -struct dns_entry { // element of known name, ip address and reversed ip address - struct dns_entry *next; - char ip[IP_STRING_LEN]; // dotted decimal IP - char rip[IP_STRING_LEN]; // length decimal reversed IP - char name[MAX_HOST_LEN]; -}; - -static struct dns_entry *dnsentry; -static uint32_t ttl = DEFAULT_TTL; - -static const char *fileconf = "/etc/dnsd.conf"; - -// Must match getopt32 call -#define OPT_daemon (option_mask32 & 0x10) -#define OPT_verbose (option_mask32 & 0x20) - - -/* - * Convert host name from C-string to dns length/string. - */ -static void convname(char *a, uint8_t *q) -{ - int i = (q[0] == '.') ? 0 : 1; - for (; i < MAX_HOST_LEN-1 && *q; i++, q++) - a[i] = tolower(*q); - a[0] = i - 1; - a[i] = 0; -} - -/* - * Insert length of substrings instead of dots - */ -static void undot(uint8_t * rip) -{ - int i = 0, s = 0; - while (rip[i]) - i++; - for (--i; i >= 0; i--) { - if (rip[i] == '.') { - rip[i] = s; - s = 0; - } else s++; - } -} - -/* - * Read hostname/IP records from file - */ -static void dnsentryinit(void) -{ - char *token[2]; - parser_t *parser; - struct dns_entry *m, *prev; - - prev = dnsentry = NULL; - parser = config_open(fileconf); - while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) { - unsigned a, b, c, d; - /* - * Assumes all host names are lower case only - * Hostnames with more than one label are not handled correctly. - * Presently the dot is copied into name without - * converting to a length/string substring for that label. - */ -// if (!token[1] || sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) - if (sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) - continue; - - m = xzalloc(sizeof(*m)); - /*m->next = NULL;*/ - sprintf(m->ip, ".%u.%u.%u.%u"+1, a, b, c, d); - sprintf(m->rip, ".%u.%u.%u.%u", d, c, b, a); - undot((uint8_t*)m->rip); - convname(m->name, (uint8_t*)token[0]); - - if (OPT_verbose) - fprintf(stderr, "\tname:%s, ip:%s\n", &(m->name[1]), m->ip); - - if (prev == NULL) - dnsentry = m; - else - prev->next = m; - prev = m; - } - config_close(parser); -} - -/* - * Look query up in dns records and return answer if found - * qs is the query string, first byte the string length - */ -static int table_lookup(uint16_t type, uint8_t * as, uint8_t * qs) -{ - int i; - struct dns_entry *d = dnsentry; - - do { -#if DEBUG - char *p,*q; - q = (char *)&(qs[1]); - p = &(d->name[1]); - fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d", - __FUNCTION__, (int)strlen(p), (int)(d->name[0]), - p, q, (int)strlen(q)); -#endif - if (type == REQ_A) { /* search by host name */ - for (i = 1; i <= (int)(d->name[0]); i++) - if (tolower(qs[i]) != d->name[i]) - break; - if (i > (int)(d->name[0]) || - (d->name[0] == 1 && d->name[1] == '*')) { - strcpy((char *)as, d->ip); -#if DEBUG - fprintf(stderr, " OK as:%s\n", as); -#endif - return 0; - } - } else if (type == REQ_PTR) { /* search by IP-address */ - if ((d->name[0] != 1 || d->name[1] != '*') && - !strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) { - strcpy((char *)as, d->name); - return 0; - } - } - d = d->next; - } while (d); - return -1; -} - -/* - * Decode message and generate answer - */ -static int process_packet(uint8_t *buf) -{ - uint8_t answstr[MAX_NAME_LEN + 1]; - struct dns_head *head; - struct dns_prop *qprop; - uint8_t *from, *answb; - uint16_t outr_rlen; - uint16_t outr_flags; - uint16_t flags; - int lookup_result, type, packet_len; - int querystr_len; - - answstr[0] = '\0'; - - head = (struct dns_head *)buf; - if (head->nquer == 0) { - bb_error_msg("no queries"); - return -1; - } - - if (head->flags & 0x8000) { - bb_error_msg("ignoring response packet"); - return -1; - } - - from = (void *)&head[1]; // start of query string -//FIXME: strlen of untrusted data??! - querystr_len = strlen((char *)from) + 1 + sizeof(struct dns_prop); - answb = from + querystr_len; // where to append answer block - - outr_rlen = 0; - outr_flags = 0; - - qprop = (struct dns_prop *)(answb - 4); - type = ntohs(qprop->type); - - // only let REQ_A and REQ_PTR pass - if (!(type == REQ_A || type == REQ_PTR)) { - goto empty_packet; /* we can't handle the query type */ - } - - if (ntohs(qprop->class) != 1 /* class INET */ ) { - outr_flags = 4; /* not supported */ - goto empty_packet; - } - /* we only support standard queries */ - - if ((ntohs(head->flags) & 0x7800) != 0) - goto empty_packet; - - // We have a standard query - bb_info_msg("%s", (char *)from); - lookup_result = table_lookup(type, answstr, from); - if (lookup_result != 0) { - outr_flags = 3 | 0x0400; // name do not exist and auth - goto empty_packet; - } - if (type == REQ_A) { // return an address - struct in_addr a; // NB! its "struct { unsigned __long__ s_addr; }" - uint32_t v32; - if (!inet_aton((char*)answstr, &a)) { //dotted dec to long conv - outr_flags = 1; /* Frmt err */ - goto empty_packet; - } - v32 = a.s_addr; /* in case long != int */ - memcpy(answstr, &v32, 4); - outr_rlen = 4; // uint32_t IP - } else - outr_rlen = strlen((char *)answstr) + 1; // a host name - outr_flags |= 0x0400; /* authority-bit */ - // we have an answer - head->nansw = htons(1); - - // copy query block to answer block - memcpy(answb, from, querystr_len); - answb += querystr_len; - - // and append answer rr -// FIXME: unaligned accesses?? - *(uint32_t *) answb = htonl(ttl); - answb += 4; - *(uint16_t *) answb = htons(outr_rlen); - answb += 2; - memcpy(answb, answstr, outr_rlen); - answb += outr_rlen; - - empty_packet: - - flags = ntohs(head->flags); - // clear rcode and RA, set responsebit and our new flags - flags |= (outr_flags & 0xff80) | 0x8000; - head->flags = htons(flags); - head->nauth = head->nadd = 0; - head->nquer = htons(1); - - packet_len = answb - buf; - return packet_len; -} - -/* - * Exit on signal - */ -static void interrupt(int sig) -{ - /* unlink("/var/run/dnsd.lock"); */ - bb_error_msg("interrupt, exiting\n"); - kill_myself_with_sig(sig); -} - -int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int dnsd_main(int argc UNUSED_PARAM, char **argv) -{ - const char *listen_interface = "0.0.0.0"; - char *sttl, *sport; - len_and_sockaddr *lsa, *from, *to; - unsigned lsa_size; - int udps; - uint16_t port = 53; - /* Paranoid sizing: querystring x2 + ttl + outr_rlen + answstr */ - /* I'd rather see process_packet() fixed instead... */ - uint8_t buf[MAX_PACK_LEN * 2 + 4 + 2 + (MAX_NAME_LEN+1)]; - - getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport); - //if (option_mask32 & 0x1) // -i - //if (option_mask32 & 0x2) // -c - if (option_mask32 & 0x4) // -t - ttl = xatou_range(sttl, 1, 0xffffffff); - if (option_mask32 & 0x8) // -p - port = xatou_range(sport, 1, 0xffff); - - if (OPT_verbose) { - bb_info_msg("listen_interface: %s", listen_interface); - bb_info_msg("ttl: %d, port: %d", ttl, port); - bb_info_msg("fileconf: %s", fileconf); - } - - if (OPT_daemon) { - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); - openlog(applet_name, LOG_PID, LOG_DAEMON); - logmode = LOGMODE_SYSLOG; - } - - dnsentryinit(); - - signal(SIGINT, interrupt); - bb_signals(0 - /* why? + (1 << SIGPIPE) */ - + (1 << SIGHUP) -#ifdef SIGTSTP - + (1 << SIGTSTP) -#endif -#ifdef SIGURG - + (1 << SIGURG) -#endif - , SIG_IGN); - - lsa = xdotted2sockaddr(listen_interface, port); - udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); - xbind(udps, &lsa->u.sa, lsa->len); - socket_want_pktinfo(udps); /* needed for recv_from_to to work */ - lsa_size = LSA_LEN_SIZE + lsa->len; - from = xzalloc(lsa_size); - to = xzalloc(lsa_size); - - bb_info_msg("Accepting UDP packets on %s", - xmalloc_sockaddr2dotted(&lsa->u.sa)); - - while (1) { - int r; - /* Try to get *DEST* address (to which of our addresses - * this query was directed), and reply from the same address. - * Or else we can exhibit usual UDP ugliness: - * [ip1.multihomed.ip2] <= query to ip1 <= peer - * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */ - memcpy(to, lsa, lsa_size); - r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len); - if (r < 12 || r > MAX_PACK_LEN) { - bb_error_msg("invalid packet size"); - continue; - } - if (OPT_verbose) - bb_info_msg("Got UDP packet"); - buf[r] = '\0'; /* paranoia */ - r = process_packet(buf); - if (r <= 0) - continue; - send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len); - } - return 0; -} +/* vi: set sw=4 ts=4: */ +/* + * Mini DNS server implementation for busybox + * + * Copyright (C) 2005 Roberto A. Foglietta (me@roberto.foglietta.name) + * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no) + * Copyright (C) 2003 Paul Sheer + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote + * it into a shape which I believe is both easier to understand and maintain. + * I also reused the input buffer for output and removed services he did not + * need. [1] http://threading.2038bug.com/sheerdns/ + * + * Some bugfix and minor changes was applied by Roberto A. Foglietta who made + * the first porting of oao' scdns to busybox also. + */ + +#include "libbb.h" +#include + +//#define DEBUG 1 +#define DEBUG 0 + +enum { + /* can tweak this */ + DEFAULT_TTL = 120, + + /* cannot get bigger packets than 512 per RFC1035. */ + MAX_PACK_LEN = 512, + IP_STRING_LEN = sizeof(".xxx.xxx.xxx.xxx"), + MAX_NAME_LEN = IP_STRING_LEN - 1 + sizeof(".in-addr.arpa"), + REQ_A = 1, + REQ_PTR = 12, +}; + +/* the message from client and first part of response msg */ +struct dns_head { + uint16_t id; + uint16_t flags; + uint16_t nquer; + uint16_t nansw; + uint16_t nauth; + uint16_t nadd; +}; +struct dns_prop { + uint16_t type; + uint16_t class; +}; +/* element of known name, ip address and reversed ip address */ +struct dns_entry { + struct dns_entry *next; + uint32_t ip; + char rip[IP_STRING_LEN]; /* length decimal reversed IP */ + char name[1]; +}; + +#define OPT_verbose (option_mask32) + + +/* + * Insert length of substrings instead of dots + */ +static void undot(char *rip) +{ + int i = 0; + int s = 0; + + while (rip[i]) + i++; + for (--i; i >= 0; i--) { + if (rip[i] == '.') { + rip[i] = s; + s = 0; + } else { + s++; + } + } +} + +/* + * Read hostname/IP records from file + */ +static struct dns_entry *parse_conf_file(const char *fileconf) +{ + char *token[2]; + parser_t *parser; + struct dns_entry *m, *conf_data; + struct dns_entry **nextp; + + conf_data = NULL; + nextp = &conf_data; + + parser = config_open(fileconf); + while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) { + struct in_addr ip; + uint32_t v32; + + if (inet_aton(token[1], &ip) == 0) { + bb_error_msg("error at line %u, skipping", parser->lineno); + continue; + } + + if (OPT_verbose) + bb_error_msg("name:%s, ip:%s", token[0], token[1]); + + /* sizeof(*m) includes 1 byte for m->name[0] */ + m = xzalloc(sizeof(*m) + strlen(token[0]) + 1); + /*m->next = NULL;*/ + *nextp = m; + nextp = &m->next; + + m->name[0] = '.'; + strcpy(m->name + 1, token[0]); + undot(m->name); + m->ip = ip.s_addr; /* in network order */ + v32 = ntohl(m->ip); + /* inverted order */ + sprintf(m->rip, ".%u.%u.%u.%u", + (uint8_t)(v32), + (uint8_t)(v32 >> 8), + (uint8_t)(v32 >> 16), + (v32 >> 24) + ); + undot(m->rip); + } + config_close(parser); + return conf_data; +} + +/* + * Look query up in dns records and return answer if found. + */ +static char *table_lookup(struct dns_entry *d, + uint16_t type, + char* query_string) +{ + while (d) { + unsigned len = d->name[0]; + /* d->name[len] is the last (non NUL) char */ +#if DEBUG + char *p, *q; + q = query_string + 1; + p = d->name + 1; + fprintf(stderr, "%d/%d p:%s q:%s %d\n", + (int)strlen(p), len, + p, q, (int)strlen(q) + ); +#endif + if (type == htons(REQ_A)) { + /* search by host name */ + if (len != 1 || d->name[1] != '*') { +/* we are lax, hope no name component is ever >64 so that length + * (which will be represented as 'A','B'...) matches a lowercase letter. + * Actually, I think false matches are hard to construct. + * Example. + * [31] len is represented as '1', [65] as 'A', [65+32] as 'a'. + * [65] <65 same chars>[31]<31 same chars>NUL + * [65+32]<65 same chars>1 <31 same chars>NUL + * This example seems to be the minimal case when false match occurs. + */ + if (strcasecmp(d->name, query_string) != 0) + goto next; + } + return (char *)&d->ip; +#if DEBUG + fprintf(stderr, "Found IP:%x\n", (int)d->ip); +#endif + return 0; + } + /* search by IP-address */ + if ((len != 1 || d->name[1] != '*') + /* we assume (do not check) that query_string + * ends in ".in-addr.arpa" */ + && strncmp(d->rip, query_string, strlen(d->rip)) == 0 + ) { +#if DEBUG + fprintf(stderr, "Found name:%s\n", d->name); +#endif + return d->name; + } + next: + d = d->next; + } + + return NULL; +} + +/* + * Decode message and generate answer + */ +/* RFC 1035 +... +Whenever an octet represents a numeric quantity, the left most bit +in the diagram is the high order or most significant bit. +That is, the bit labeled 0 is the most significant bit. +... + +4.1.1. Header section format + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ID | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QDCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ANCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | NSCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ARCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +ID 16 bit random identifier assigned by querying peer. + Used to match query/response. +QR message is a query (0), or a response (1). +OPCODE 0 standard query (QUERY) + 1 inverse query (IQUERY) + 2 server status request (STATUS) +AA Authoritative Answer - this bit is valid in responses. + Responding name server is an authority for the domain name + in question section. Answer section may have multiple owner names + because of aliases. The AA bit corresponds to the name which matches + the query name, or the first owner name in the answer section. +TC TrunCation - this message was truncated. +RD Recursion Desired - this bit may be set in a query and + is copied into the response. If RD is set, it directs + the name server to pursue the query recursively. + Recursive query support is optional. +RA Recursion Available - this be is set or cleared in a + response, and denotes whether recursive query support is + available in the name server. +RCODE Response code. + 0 No error condition + 1 Format error + 2 Server failure - server was unable to process the query + due to a problem with the name server. + 3 Name Error - meaningful only for responses from + an authoritative name server. The referenced domain name + does not exist. + 4 Not Implemented. + 5 Refused. +QDCOUNT number of entries in the question section. +ANCOUNT number of records in the answer section. +NSCOUNT number of records in the authority records section. +ARCOUNT number of records in the additional records section. + +4.1.2. Question section format + +The section contains QDCOUNT (usually 1) entries, each of this format: + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / QNAME / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QTYPE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QCLASS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +QNAME a domain name represented as a sequence of labels, where + each label consists of a length octet followed by that + number of octets. The domain name terminates with the + zero length octet for the null label of the root. Note + that this field may be an odd number of octets; no + padding is used. +QTYPE a two octet type of the query. + 1 a host address [REQ_A const] + 2 an authoritative name server + 3 a mail destination (Obsolete - use MX) + 4 a mail forwarder (Obsolete - use MX) + 5 the canonical name for an alias + 6 marks the start of a zone of authority + 7 a mailbox domain name (EXPERIMENTAL) + 8 a mail group member (EXPERIMENTAL) + 9 a mail rename domain name (EXPERIMENTAL) + 10 a null RR (EXPERIMENTAL) + 11 a well known service description + 12 a domain name pointer [REQ_PTR const] + 13 host information + 14 mailbox or mail list information + 15 mail exchange + 16 text strings + 0x1c IPv6? + 252 a request for a transfer of an entire zone + 253 a request for mailbox-related records (MB, MG or MR) + 254 a request for mail agent RRs (Obsolete - see MX) + 255 a request for all records +QCLASS a two octet code that specifies the class of the query. + 1 the Internet + (others are historic only) + 255 any class + +4.1.3. Resource record format + +The answer, authority, and additional sections all share the same format: +a variable number of resource records, where the number of records +is specified in the corresponding count field in the header. +Each resource record has this format: + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / / + / NAME / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | TYPE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | CLASS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | TTL | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | RDLENGTH | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RDATA / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +NAME a domain name to which this resource record pertains. +TYPE two octets containing one of the RR type codes. This + field specifies the meaning of the data in the RDATA field. +CLASS two octets which specify the class of the data in the RDATA field. +TTL a 32 bit unsigned integer that specifies the time interval + (in seconds) that the record may be cached. +RDLENGTH a 16 bit integer, length in octets of the RDATA field. +RDATA a variable length string of octets that describes the resource. + The format of this information varies according to the TYPE + and CLASS of the resource record. + If the TYPE is A and the CLASS is IN, it's a 4 octet IP address. + +4.1.4. Message compression + +In order to reduce the size of messages, domain names coan be compressed. +An entire domain name or a list of labels at the end of a domain name +is replaced with a pointer to a prior occurance of the same name. + +The pointer takes the form of a two octet sequence: + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1 1| OFFSET | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +The first two bits are ones. This allows a pointer to be distinguished +from a label, since the label must begin with two zero bits because +labels are restricted to 63 octets or less. The OFFSET field specifies +an offset from the start of the message (i.e., the first octet +of the ID field in the domain header). +A zero offset specifies the first byte of the ID field, etc. +Domain name in a message can be represented as either: + - a sequence of labels ending in a zero octet + - a pointer + - a sequence of labels ending with a pointer + */ +static int process_packet(struct dns_entry *conf_data, + uint32_t conf_ttl, + uint8_t *buf) +{ + char *answstr; + struct dns_head *head; + struct dns_prop *unaligned_qprop; + char *query_string; + uint8_t *answb; + uint16_t outr_rlen; + uint16_t outr_flags; + uint16_t type; + uint16_t class; + int querystr_len; + + head = (struct dns_head *)buf; + if (head->nquer == 0) { + bb_error_msg("packet has 0 queries, ignored"); + return -1; + } + + if (head->flags & htons(0x8000)) { /* QR bit */ + bb_error_msg("response packet, ignored"); + return -1; + } + + /* start of query string */ + query_string = (void *)(head + 1); + /* caller guarantees strlen is <= MAX_PACK_LEN */ + querystr_len = strlen(query_string) + 1; + /* may be unaligned! */ + unaligned_qprop = (void *)(query_string + querystr_len); + querystr_len += sizeof(unaligned_qprop); + /* where to append answer block */ + answb = (void *)(unaligned_qprop + 1); + + /* QR = 1 "response", RCODE = 4 "Not Implemented" */ + outr_flags = htons(0x8000 | 4); + + move_from_unaligned16(type, &unaligned_qprop->type); + if (type != htons(REQ_A) && type != htons(REQ_PTR)) { + /* we can't handle the query type */ + goto empty_packet; + } + move_from_unaligned16(class, &unaligned_qprop->class); + if (class != htons(1)) { /* not class INET? */ + goto empty_packet; + } + /* OPCODE != 0 "standard query" ? */ + if ((head->flags & htons(0x7800)) != 0) { + goto empty_packet; + } + + /* look up the name */ +#if DEBUG + /* need to convert lengths to dots before we can use it in non-debug */ + bb_info_msg("%s", query_string); +#endif + answstr = table_lookup(conf_data, type, query_string); + outr_rlen = 4; + if (answstr && type == htons(REQ_PTR)) { + /* return a host name */ + outr_rlen = strlen(answstr) + 1; + } + if (!answstr + || (unsigned)(answb - buf) + querystr_len + 4 + 2 + outr_rlen > MAX_PACK_LEN + ) { + /* QR = 1 "response" + * AA = 1 "Authoritative Answer" + * RCODE = 3 "Name Error" */ + outr_flags = htons(0x8000 | 0x0400 | 3); + goto empty_packet; + } + + /* copy query block to answer block */ + memcpy(answb, query_string, querystr_len); + answb += querystr_len; + /* append answer Resource Record */ + move_to_unaligned32((uint32_t *)answb, htonl(conf_ttl)); + answb += 4; + move_to_unaligned32((uint16_t *)answb, htons(outr_rlen)); + answb += 2; + memcpy(answb, answstr, outr_rlen); + answb += outr_rlen; + + /* QR = 1 "response", + * AA = 1 "Authoritative Answer", + * RCODE = 0 "success" */ + outr_flags = htons(0x8000 | 0x0400 | 0); + /* we have one answer */ + head->nansw = htons(1); + + empty_packet: + head->flags |= outr_flags; + head->nauth = head->nadd = 0; + head->nquer = htons(1); // why??? + + return answb - buf; +} + +int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dnsd_main(int argc UNUSED_PARAM, char **argv) +{ + const char *listen_interface = "0.0.0.0"; + const char *fileconf = "/etc/dnsd.conf"; + struct dns_entry *conf_data; + uint32_t conf_ttl = DEFAULT_TTL; + char *sttl, *sport; + len_and_sockaddr *lsa, *from, *to; + unsigned lsa_size; + int udps, opts; + uint16_t port = 53; + uint8_t buf[MAX_PACK_LEN + 1]; + + opts = getopt32(argv, "vi:c:t:p:d", &listen_interface, &fileconf, &sttl, &sport); + //if (opts & 0x1) // -v + //if (opts & 0x2) // -i + //if (opts & 0x4) // -c + if (opts & 0x8) // -t + conf_ttl = xatou_range(sttl, 1, 0xffffffff); + if (opts & 0x10) // -p + port = xatou_range(sport, 1, 0xffff); + if (opts & 0x20) { // -d + bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + } + /* Clear all except "verbose" bit */ + option_mask32 &= 1; + + conf_data = parse_conf_file(fileconf); + + lsa = xdotted2sockaddr(listen_interface, port); + udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); + xbind(udps, &lsa->u.sa, lsa->len); + socket_want_pktinfo(udps); /* needed for recv_from_to to work */ + lsa_size = LSA_LEN_SIZE + lsa->len; + from = xzalloc(lsa_size); + to = xzalloc(lsa_size); + + { + char *p = xmalloc_sockaddr2dotted(&lsa->u.sa); + bb_info_msg("Accepting UDP packets on %s", p); + free(p); + } + + while (1) { + int r; + /* Try to get *DEST* address (to which of our addresses + * this query was directed), and reply from the same address. + * Or else we can exhibit usual UDP ugliness: + * [ip1.multihomed.ip2] <= query to ip1 <= peer + * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */ + memcpy(to, lsa, lsa_size); + r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len); + if (r < 12 || r > MAX_PACK_LEN) { + bb_error_msg("packet size %d, ignored", r); + continue; + } + if (OPT_verbose) + bb_info_msg("Got UDP packet"); + buf[r] = '\0'; /* paranoia */ + r = process_packet(conf_data, conf_ttl, buf); + if (r <= 0) + continue; + send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len); + } + return 0; +} diff --git a/release/src/router/busybox/networking/ether-wake.c b/release/src/router/busybox/networking/ether-wake.c index a37b6eb79d..882429d1a9 100644 --- a/release/src/router/busybox/networking/ether-wake.c +++ b/release/src/router/busybox/networking/ether-wake.c @@ -219,7 +219,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) { struct ifreq if_hwaddr; - strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name)); + strncpy_IFNAMSIZ(if_hwaddr.ifr_name, ifname); ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname); memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6); @@ -255,7 +255,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) #if defined(PF_PACKET) { struct ifreq ifr; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); xioctl(s, SIOCGIFINDEX, &ifr); memset(&whereto, 0, sizeof(whereto)); whereto.sll_family = AF_PACKET; diff --git a/release/src/router/busybox/networking/ftpd.c b/release/src/router/busybox/networking/ftpd.c new file mode 100644 index 0000000000..ac68961170 --- /dev/null +++ b/release/src/router/busybox/networking/ftpd.c @@ -0,0 +1,1346 @@ +/* vi: set sw=4 ts=4: */ +/* + * Simple FTP daemon, based on vsftpd 2.0.7 (written by Chris Evans) + * + * Author: Adam Tkac + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + * + * Only subset of FTP protocol is implemented but vast majority of clients + * should not have any problem. + * + * You have to run this daemon via inetd. + */ + +#include "libbb.h" +#include +#include + +#define FTP_DATACONN 150 +#define FTP_NOOPOK 200 +#define FTP_TYPEOK 200 +#define FTP_PORTOK 200 +#define FTP_STRUOK 200 +#define FTP_MODEOK 200 +#define FTP_ALLOOK 202 +#define FTP_STATOK 211 +#define FTP_STATFILE_OK 213 +#define FTP_HELP 214 +#define FTP_SYSTOK 215 +#define FTP_GREET 220 +#define FTP_GOODBYE 221 +#define FTP_TRANSFEROK 226 +#define FTP_PASVOK 227 +/*#define FTP_EPRTOK 228*/ +#define FTP_EPSVOK 229 +#define FTP_LOGINOK 230 +#define FTP_CWDOK 250 +#define FTP_RMDIROK 250 +#define FTP_DELEOK 250 +#define FTP_RENAMEOK 250 +#define FTP_PWDOK 257 +#define FTP_MKDIROK 257 +#define FTP_GIVEPWORD 331 +#define FTP_RESTOK 350 +#define FTP_RNFROK 350 +#define FTP_TIMEOUT 421 +#define FTP_BADSENDCONN 425 +#define FTP_BADSENDNET 426 +#define FTP_BADSENDFILE 451 +#define FTP_BADCMD 500 +#define FTP_COMMANDNOTIMPL 502 +#define FTP_NEEDUSER 503 +#define FTP_NEEDRNFR 503 +#define FTP_BADSTRU 504 +#define FTP_BADMODE 504 +#define FTP_LOGINERR 530 +#define FTP_FILEFAIL 550 +#define FTP_NOPERM 550 +#define FTP_UPLOADFAIL 553 + +#define STR1(s) #s +#define STR(s) STR1(s) + +/* Convert a constant to 3-digit string, packed into uint32_t */ +enum { + /* Shift for Nth decimal digit */ + SHIFT2 = 0 * BB_LITTLE_ENDIAN + 24 * BB_BIG_ENDIAN, + SHIFT1 = 8 * BB_LITTLE_ENDIAN + 16 * BB_BIG_ENDIAN, + SHIFT0 = 16 * BB_LITTLE_ENDIAN + 8 * BB_BIG_ENDIAN, + /* And for 4th position (space) */ + SHIFTsp = 24 * BB_LITTLE_ENDIAN + 0 * BB_BIG_ENDIAN, +}; +#define STRNUM32(s) (uint32_t)(0 \ + | (('0' + ((s) / 1 % 10)) << SHIFT0) \ + | (('0' + ((s) / 10 % 10)) << SHIFT1) \ + | (('0' + ((s) / 100 % 10)) << SHIFT2) \ +) +#define STRNUM32sp(s) (uint32_t)(0 \ + | (' ' << SHIFTsp) \ + | (('0' + ((s) / 1 % 10)) << SHIFT0) \ + | (('0' + ((s) / 10 % 10)) << SHIFT1) \ + | (('0' + ((s) / 100 % 10)) << SHIFT2) \ +) + +#define MSG_OK "Operation successful\r\n" +#define MSG_ERR "Error\r\n" + +struct globals { + int pasv_listen_fd; +#if !BB_MMU + int root_fd; +#endif + int local_file_fd; + unsigned end_time; + unsigned timeout; + unsigned verbose; + off_t local_file_pos; + off_t restart_pos; + len_and_sockaddr *local_addr; + len_and_sockaddr *port_addr; + char *ftp_cmd; + char *ftp_arg; +#if ENABLE_FEATURE_FTP_WRITE + char *rnfr_filename; +#endif + /* We need these aligned to uint32_t */ + char msg_ok [(sizeof("NNN " MSG_OK ) + 3) & 0xfffc]; + char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc]; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { \ + /* Moved to main */ \ + /*strcpy(G.msg_ok + 4, MSG_OK );*/ \ + /*strcpy(G.msg_err + 4, MSG_ERR);*/ \ +} while (0) + + +static char * +escape_text(const char *prepend, const char *str, unsigned escapee) +{ + unsigned retlen, remainlen, chunklen; + char *ret, *found; + char append; + + append = (char)escapee; + escapee >>= 8; + + remainlen = strlen(str); + retlen = strlen(prepend); + ret = xmalloc(retlen + remainlen * 2 + 1 + 1); + strcpy(ret, prepend); + + for (;;) { + found = strchrnul(str, escapee); + chunklen = found - str + 1; + + /* Copy chunk up to and including escapee (or NUL) to ret */ + memcpy(ret + retlen, str, chunklen); + retlen += chunklen; + + if (*found == '\0') { + /* It wasn't escapee, it was NUL! */ + ret[retlen - 1] = append; /* replace NUL */ + ret[retlen] = '\0'; /* add NUL */ + break; + } + ret[retlen++] = escapee; /* duplicate escapee */ + str = found + 1; + } + return ret; +} + +/* Returns strlen as a bonus */ +static unsigned +replace_char(char *str, char from, char to) +{ + char *p = str; + while (*p) { + if (*p == from) + *p = to; + p++; + } + return p - str; +} + +static void +verbose_log(const char *str) +{ + bb_error_msg("%.*s", (int)strcspn(str, "\r\n"), str); +} + +/* NB: status_str is char[4] packed into uint32_t */ +static void +cmdio_write(uint32_t status_str, const char *str) +{ + char *response; + int len; + + /* FTP uses telnet protocol for command link. + * In telnet, 0xff is an escape char, and needs to be escaped: */ + response = escape_text((char *) &status_str, str, (0xff << 8) + '\r'); + + /* FTP sends embedded LFs as NULs */ + len = replace_char(response, '\n', '\0'); + + response[len++] = '\n'; /* tack on trailing '\n' */ + xwrite(STDOUT_FILENO, response, len); + if (G.verbose > 1) + verbose_log(response); + free(response); +} + +static void +cmdio_write_ok(unsigned status) +{ + *(uint32_t *) G.msg_ok = status; + xwrite(STDOUT_FILENO, G.msg_ok, sizeof("NNN " MSG_OK) - 1); + if (G.verbose > 1) + verbose_log(G.msg_ok); +} +#define WRITE_OK(a) cmdio_write_ok(STRNUM32sp(a)) + +/* TODO: output strerr(errno) if errno != 0? */ +static void +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) + verbose_log(G.msg_err); +} +#define WRITE_ERR(a) cmdio_write_error(STRNUM32sp(a)) + +static void +cmdio_write_raw(const char *p_text) +{ + xwrite_str(STDOUT_FILENO, p_text); + if (G.verbose > 1) + verbose_log(p_text); +} + +static void +timeout_handler(int sig UNUSED_PARAM) +{ + off_t pos; + int sv_errno = errno; + + if ((int)(monotonic_sec() - G.end_time) >= 0) + goto timed_out; + + if (!G.local_file_fd) + goto timed_out; + + pos = xlseek(G.local_file_fd, 0, SEEK_CUR); + if (pos == G.local_file_pos) + goto timed_out; + G.local_file_pos = pos; + + alarm(G.timeout); + errno = sv_errno; + return; + + timed_out: + cmdio_write_raw(STR(FTP_TIMEOUT)" Timeout\r\n"); +/* TODO: do we need to abort (as opposed to usual shutdown) data transfer? */ + exit(1); +} + +/* Simple commands */ + +static void +handle_pwd(void) +{ + char *cwd, *response; + + cwd = xrealloc_getcwd_or_warn(NULL); + if (cwd == NULL) + cwd = xstrdup(""); + + /* We have to promote each " to "" */ + response = escape_text(" \"", cwd, ('"' << 8) + '"'); + free(cwd); + cmdio_write(STRNUM32(FTP_PWDOK), response); + free(response); +} + +static void +handle_cwd(void) +{ + if (!G.ftp_arg || chdir(G.ftp_arg) != 0) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + WRITE_OK(FTP_CWDOK); +} + +static void +handle_cdup(void) +{ + G.ftp_arg = (char*)".."; + handle_cwd(); +} + +static void +handle_stat(void) +{ + cmdio_write_raw(STR(FTP_STATOK)"-Server status:\r\n" + " TYPE: BINARY\r\n" + STR(FTP_STATOK)" Ok\r\n"); +} + +/* Examples of HELP and FEAT: +# nc -vvv ftp.kernel.org 21 +ftp.kernel.org (130.239.17.4:21) open +220 Welcome to ftp.kernel.org. +FEAT +211-Features: + EPRT + EPSV + MDTM + PASV + REST STREAM + SIZE + TVFS + UTF8 +211 End +HELP +214-The following commands are recognized. + ABOR ACCT ALLO APPE CDUP CWD DELE EPRT EPSV FEAT HELP LIST MDTM MKD + MODE NLST NOOP OPTS PASS PASV PORT PWD QUIT REIN REST RETR RMD RNFR + RNTO SITE SIZE SMNT STAT STOR STOU STRU SYST TYPE USER XCUP XCWD XMKD + XPWD XRMD +214 Help OK. +*/ +static void +handle_feat(unsigned status) +{ + cmdio_write(status, "-Features:"); + cmdio_write_raw(" EPSV\r\n" + " PASV\r\n" + " REST STREAM\r\n" + " MDTM\r\n" + " SIZE\r\n"); + cmdio_write(status, " Ok"); +} + +/* Download commands */ + +static inline int +port_active(void) +{ + return (G.port_addr != NULL); +} + +static inline int +pasv_active(void) +{ + return (G.pasv_listen_fd > STDOUT_FILENO); +} + +static void +port_pasv_cleanup(void) +{ + free(G.port_addr); + G.port_addr = NULL; + if (G.pasv_listen_fd > STDOUT_FILENO) + close(G.pasv_listen_fd); + G.pasv_listen_fd = -1; +} + +/* On error, emits error code to the peer */ +static int +ftpdataio_get_pasv_fd(void) +{ + int remote_fd; + + remote_fd = accept(G.pasv_listen_fd, NULL, 0); + + if (remote_fd < 0) { + WRITE_ERR(FTP_BADSENDCONN); + return remote_fd; + } + + setsockopt(remote_fd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); + return remote_fd; +} + +/* Clears port/pasv data. + * This means we dont waste resources, for example, keeping + * PASV listening socket open when it is no longer needed. + * On error, emits error code to the peer (or exits). + * On success, emits p_status_msg to the peer. + */ +static int +get_remote_transfer_fd(const char *p_status_msg) +{ + int remote_fd; + + if (pasv_active()) + /* On error, emits error code to the peer */ + remote_fd = ftpdataio_get_pasv_fd(); + else + /* Exits on error */ + remote_fd = xconnect_stream(G.port_addr); + + port_pasv_cleanup(); + + if (remote_fd < 0) + return remote_fd; + + cmdio_write(STRNUM32(FTP_DATACONN), p_status_msg); + return remote_fd; +} + +/* If there were neither PASV nor PORT, emits error code to the peer */ +static int +port_or_pasv_was_seen(void) +{ + if (!pasv_active() && !port_active()) { + cmdio_write_raw(STR(FTP_BADSENDCONN)" Use PORT/PASV first\r\n"); + return 0; + } + + return 1; +} + +/* Exits on error */ +static unsigned +bind_for_passive_mode(void) +{ + int fd; + unsigned port; + + port_pasv_cleanup(); + + 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); + 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); + + port = get_nport(&G.local_addr->u.sa); + port = ntohs(port); + return port; +} + +/* Exits on error */ +static void +handle_pasv(void) +{ + unsigned port; + char *addr, *response; + + port = bind_for_passive_mode(); + + if (G.local_addr->u.sa.sa_family == AF_INET) + addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa); + else /* seen this in the wild done by other ftp servers: */ + addr = xstrdup("0.0.0.0"); + replace_char(addr, '.', ','); + + response = xasprintf(STR(FTP_PASVOK)" PASV ok (%s,%u,%u)\r\n", + addr, (int)(port >> 8), (int)(port & 255)); + free(addr); + cmdio_write_raw(response); + free(response); +} + +/* Exits on error */ +static void +handle_epsv(void) +{ + unsigned port; + char *response; + + port = bind_for_passive_mode(); + response = xasprintf(STR(FTP_EPSVOK)" EPSV ok (|||%u|)\r\n", port); + cmdio_write_raw(response); + free(response); +} + +/* libbb candidate */ +static +len_and_sockaddr* get_peer_lsa(int fd) +{ + len_and_sockaddr *lsa; + socklen_t len = 0; + + if (getpeername(fd, NULL, &len) != 0) + return NULL; + lsa = xzalloc(LSA_LEN_SIZE + len); + lsa->len = len; + getpeername(fd, &lsa->u.sa, &lsa->len); + return lsa; +} + +static void +handle_port(void) +{ + unsigned port, port_hi; + char *raw, *comma; +#ifdef WHY_BOTHER_WE_CAN_ASSUME_IP_MATCHES + socklen_t peer_ipv4_len; + struct sockaddr_in peer_ipv4; + struct in_addr port_ipv4_sin_addr; +#endif + + port_pasv_cleanup(); + + raw = G.ftp_arg; + + /* PORT command format makes sense only over IPv4 */ + if (!raw +#ifdef WHY_BOTHER_WE_CAN_ASSUME_IP_MATCHES + || G.local_addr->u.sa.sa_family != AF_INET +#endif + ) { + bail: + WRITE_ERR(FTP_BADCMD); + return; + } + + comma = strrchr(raw, ','); + if (comma == NULL) + goto bail; + *comma = '\0'; + port = bb_strtou(&comma[1], NULL, 10); + if (errno || port > 0xff) + goto bail; + + comma = strrchr(raw, ','); + if (comma == NULL) + goto bail; + *comma = '\0'; + port_hi = bb_strtou(&comma[1], NULL, 10); + if (errno || port_hi > 0xff) + goto bail; + port |= port_hi << 8; + +#ifdef WHY_BOTHER_WE_CAN_ASSUME_IP_MATCHES + replace_char(raw, ',', '.'); + + /* We are verifying that PORT's IP matches getpeername(). + * Otherwise peer can make us open data connections + * to other hosts (security problem!) + * This code would be too simplistic: + * lsa = xdotted2sockaddr(raw, port); + * if (lsa == NULL) goto bail; + */ + if (!inet_aton(raw, &port_ipv4_sin_addr)) + goto bail; + peer_ipv4_len = sizeof(peer_ipv4); + if (getpeername(STDIN_FILENO, &peer_ipv4, &peer_ipv4_len) != 0) + goto bail; + if (memcmp(&port_ipv4_sin_addr, &peer_ipv4.sin_addr, sizeof(struct in_addr)) != 0) + goto bail; + + G.port_addr = xdotted2sockaddr(raw, port); +#else + G.port_addr = get_peer_lsa(STDIN_FILENO); + set_nport(G.port_addr, htons(port)); +#endif + WRITE_OK(FTP_PORTOK); +} + +static void +handle_rest(void) +{ + /* When ftp_arg == NULL simply restart from beginning */ + G.restart_pos = G.ftp_arg ? xatoi_u(G.ftp_arg) : 0; + WRITE_OK(FTP_RESTOK); +} + +static void +handle_retr(void) +{ + struct stat statbuf; + off_t bytes_transferred; + int remote_fd; + int local_file_fd; + off_t offset = G.restart_pos; + char *response; + + G.restart_pos = 0; + + if (!port_or_pasv_was_seen()) + return; /* port_or_pasv_was_seen emitted error response */ + + /* O_NONBLOCK is useful if file happens to be a device node */ + local_file_fd = G.ftp_arg ? open(G.ftp_arg, O_RDONLY | O_NONBLOCK) : -1; + if (local_file_fd < 0) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + + if (fstat(local_file_fd, &statbuf) != 0 || !S_ISREG(statbuf.st_mode)) { + /* Note - pretend open failed */ + WRITE_ERR(FTP_FILEFAIL); + goto file_close_out; + } + G.local_file_fd = local_file_fd; + + /* Now deactive O_NONBLOCK, otherwise we have a problem + * on DMAPI filesystems such as XFS DMAPI. + */ + ndelay_off(local_file_fd); + + /* Set the download offset (from REST) if any */ + if (offset != 0) + xlseek(local_file_fd, offset, SEEK_SET); + + response = xasprintf( + " Opening BINARY connection for %s (%"OFF_FMT"u bytes)", + G.ftp_arg, statbuf.st_size); + remote_fd = get_remote_transfer_fd(response); + free(response); + if (remote_fd < 0) + goto file_close_out; + + bytes_transferred = bb_copyfd_eof(local_file_fd, remote_fd); + close(remote_fd); + if (bytes_transferred < 0) + WRITE_ERR(FTP_BADSENDFILE); + else + WRITE_OK(FTP_TRANSFEROK); + + file_close_out: + close(local_file_fd); + G.local_file_fd = 0; +} + +/* List commands */ + +static int +popen_ls(const char *opt) +{ + char *cwd; + const char *argv[] = { + "ftpd", + opt, + BB_MMU ? "--" : NULL, + G.ftp_arg, + NULL + }; + struct fd_pair outfd; + pid_t pid; + + cwd = xrealloc_getcwd_or_warn(NULL); + xpiped_pair(outfd); + + /*fflush(NULL); - so far we dont use stdio on output */ + pid = BB_MMU ? fork() : vfork(); + if (pid < 0) + bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); + + if (pid == 0) { + /* child */ +#if !BB_MMU + if (fchdir(G.root_fd) != 0) + _exit(127); + close(G.root_fd); +#endif + /* NB: close _first_, then move fd! */ + close(outfd.rd); + xmove_fd(outfd.wr, STDOUT_FILENO); + /* Opening /dev/null in chroot is hard. + * Just making sure STDIN_FILENO is opened + * to something harmless. Paranoia, + * ls won't read it anyway */ + close(STDIN_FILENO); + dup(STDOUT_FILENO); /* copy will become STDIN_FILENO */ +#if !BB_MMU + /* ftpd ls helper chdirs to argv[2], + * preventing peer from seeing real root we are in now + */ + argv[2] = cwd; + /* + 1: we must use relative path here if in chroot. + * For example, execv("/proc/self/exe") will fail, since + * it looks for "/proc/self/exe" _relative to chroot!_ */ + execv(bb_busybox_exec_path + 1, (char**) argv); + _exit(127); +#else + memset(&G, 0, sizeof(G)); + exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv)); +#endif + } + + /* parent */ + close(outfd.wr); + free(cwd); + return outfd.rd; +} + +enum { + USE_CTRL_CONN = 1, + LONG_LISTING = 2, +}; + +static void +handle_dir_common(int opts) +{ + FILE *ls_fp; + char *line; + int ls_fd; + + if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen()) + return; /* port_or_pasv_was_seen emitted error response */ + + /* -n prevents user/groupname display, + * which can be problematic in chroot */ + ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); + ls_fp = fdopen(ls_fd, "r"); + if (!ls_fp) /* never happens. paranoia */ + bb_perror_msg_and_die("fdopen"); + + if (opts & USE_CTRL_CONN) { + /* STAT */ + cmdio_write_raw(STR(FTP_STATFILE_OK)"-File status:\r\n"); + while (1) { + line = xmalloc_fgetline(ls_fp); + if (!line) + break; + /* Hack: 0 results in no status at all */ + /* Note: it's ok that we don't prepend space, + * ftp.kernel.org doesn't do that too */ + cmdio_write(0, line); + free(line); + } + WRITE_OK(FTP_STATFILE_OK); + } else { + /* LIST/NLST [] */ + int remote_fd = get_remote_transfer_fd(" Directory listing"); + if (remote_fd >= 0) { + while (1) { + line = xmalloc_fgetline(ls_fp); + if (!line) + break; + /* I've seen clients complaining when they + * are fed with ls output with bare '\n'. + * Pity... that would be much simpler. + */ +/* TODO: need to s/LF/NUL/g here */ + xwrite_str(remote_fd, line); + xwrite(remote_fd, "\r\n", 2); + free(line); + } + } + close(remote_fd); + WRITE_OK(FTP_TRANSFEROK); + } + fclose(ls_fp); /* closes ls_fd too */ +} +static void +handle_list(void) +{ + handle_dir_common(LONG_LISTING); +} +static void +handle_nlst(void) +{ + /* NLST returns list of names, "\r\n" terminated without regard + * to the current binary flag. Names may start with "/", + * then they represent full names (we don't produce such names), + * otherwise names are relative to current directory. + * Embedded "\n" are replaced by NULs. This is safe since names + * can never contain NUL. + */ + handle_dir_common(0); +} +static void +handle_stat_file(void) +{ + handle_dir_common(LONG_LISTING + USE_CTRL_CONN); +} + +/* This can be extended to handle MLST, as all info is available + * in struct stat for that: + * MLST file_name + * 250-Listing file_name + * type=file;size=4161;modify=19970214165800; /dir/dir/file_name + * 250 End + * Nano-doc: + * MLST [] + * Returned name should be either the same as requested, or fully qualified. + * If there was no parameter, return "" or (preferred) fully-qualified name. + * Returned "facts" (case is not important): + * size - size in octets + * modify - last modification time + * type - entry type (file,dir,OS.unix=block) + * (+ cdir and pdir types for MLSD) + * unique - unique id of file/directory (inode#) + * perm - + * a: can be appended to (APPE) + * d: can be deleted (RMD/DELE) + * f: can be renamed (RNFR) + * r: can be read (RETR) + * w: can be written (STOR) + * e: can CWD into this dir + * l: this dir can be listed (dir only!) + * c: can create files in this dir + * m: can create dirs in this dir (MKD) + * p: can delete files in this dir + * UNIX.mode - unix file mode + */ +static void +handle_size_or_mdtm(int need_size) +{ + struct stat statbuf; + struct tm broken_out; + char buf[(sizeof("NNN %"OFF_FMT"u\r\n") + sizeof(off_t) * 3) + | sizeof("NNN YYYYMMDDhhmmss\r\n") + ]; + + if (!G.ftp_arg + || stat(G.ftp_arg, &statbuf) != 0 + || !S_ISREG(statbuf.st_mode) + ) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + if (need_size) { + sprintf(buf, STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n", statbuf.st_size); + } else { + gmtime_r(&statbuf.st_mtime, &broken_out); + sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n", + broken_out.tm_year + 1900, + broken_out.tm_mon, + broken_out.tm_mday, + broken_out.tm_hour, + broken_out.tm_min, + broken_out.tm_sec); + } + cmdio_write_raw(buf); +} + +/* Upload commands */ + +#if ENABLE_FEATURE_FTP_WRITE +static void +handle_mkd(void) +{ + if (!G.ftp_arg || mkdir(G.ftp_arg, 0777) != 0) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + WRITE_OK(FTP_MKDIROK); +} + +static void +handle_rmd(void) +{ + if (!G.ftp_arg || rmdir(G.ftp_arg) != 0) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + WRITE_OK(FTP_RMDIROK); +} + +static void +handle_dele(void) +{ + if (!G.ftp_arg || unlink(G.ftp_arg) != 0) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + WRITE_OK(FTP_DELEOK); +} + +static void +handle_rnfr(void) +{ + free(G.rnfr_filename); + G.rnfr_filename = xstrdup(G.ftp_arg); + WRITE_OK(FTP_RNFROK); +} + +static void +handle_rnto(void) +{ + int retval; + + /* If we didn't get a RNFR, throw a wobbly */ + if (G.rnfr_filename == NULL || G.ftp_arg == NULL) { + cmdio_write_raw(STR(FTP_NEEDRNFR)" Use RNFR first\r\n"); + return; + } + + retval = rename(G.rnfr_filename, G.ftp_arg); + free(G.rnfr_filename); + G.rnfr_filename = NULL; + + if (retval) { + WRITE_ERR(FTP_FILEFAIL); + return; + } + WRITE_OK(FTP_RENAMEOK); +} + +static void +handle_upload_common(int is_append, int is_unique) +{ + struct stat statbuf; + char *tempname; + off_t bytes_transferred; + off_t offset; + int local_file_fd; + int remote_fd; + + offset = G.restart_pos; + G.restart_pos = 0; + + if (!port_or_pasv_was_seen()) + return; /* port_or_pasv_was_seen emitted error response */ + + tempname = NULL; + local_file_fd = -1; + if (is_unique) { + tempname = xstrdup(" FILE: uniq.XXXXXX"); + local_file_fd = mkstemp(tempname + 7); + } else if (G.ftp_arg) { + int flags = O_WRONLY | O_CREAT | O_TRUNC; + if (is_append) + flags = O_WRONLY | O_CREAT | O_APPEND; + if (offset) + flags = O_WRONLY | O_CREAT; + local_file_fd = open(G.ftp_arg, flags, 0666); + } + + if (local_file_fd < 0 + || fstat(local_file_fd, &statbuf) != 0 + || !S_ISREG(statbuf.st_mode) + ) { + WRITE_ERR(FTP_UPLOADFAIL); + if (local_file_fd >= 0) + goto close_local_and_bail; + return; + } + G.local_file_fd = local_file_fd; + + if (offset) + xlseek(local_file_fd, offset, SEEK_SET); + + remote_fd = get_remote_transfer_fd(tempname ? tempname : " Ok to send data"); + free(tempname); + + if (remote_fd < 0) + goto close_local_and_bail; + + bytes_transferred = bb_copyfd_eof(remote_fd, local_file_fd); + close(remote_fd); + if (bytes_transferred < 0) + WRITE_ERR(FTP_BADSENDFILE); + else + WRITE_OK(FTP_TRANSFEROK); + + close_local_and_bail: + close(local_file_fd); + G.local_file_fd = 0; +} + +static void +handle_stor(void) +{ + handle_upload_common(0, 0); +} + +static void +handle_appe(void) +{ + G.restart_pos = 0; + handle_upload_common(1, 0); +} + +static void +handle_stou(void) +{ + G.restart_pos = 0; + handle_upload_common(0, 1); +} +#endif /* ENABLE_FEATURE_FTP_WRITE */ + +static uint32_t +cmdio_get_cmd_and_arg(void) +{ + size_t len; + uint32_t cmdval; + char *cmd; + + alarm(G.timeout); + + free(G.ftp_cmd); + len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */ + G.ftp_cmd = cmd = xmalloc_fgets_str_len(stdin, "\r\n", &len); + if (!cmd) + exit(0); + + /* De-escape telnet: 0xff,0xff => 0xff */ + /* RFC959 says that ABOR, STAT, QUIT may be sent even during + * data transfer, and may be preceded by telnet's "Interrupt Process" + * code (two-byte sequence 255,244) and then by telnet "Synch" code + * 255,242 (byte 242 is sent with TCP URG bit using send(MSG_OOB) + * and may generate SIGURG on our side. See RFC854). + * So far we don't support that (may install SIGURG handler if we'd want to), + * but we need to at least remove 255,xxx pairs. lftp sends those. */ + /* Then de-escape FTP: NUL => '\n' */ + /* Testing for \xff: + * Create file named '\xff': echo Hello >`echo -ne "\xff"` + * Try to get it: ftpget -v 127.0.0.1 Eff `echo -ne "\xff\xff"` + * (need "\xff\xff" until ftpget applet is fixed to do escaping :) + * Testing for embedded LF: + * LF_HERE=`echo -ne "LF\nHERE"` + * echo Hello >"$LF_HERE" + * ftpget -v 127.0.0.1 LF_HERE "$LF_HERE" + */ + { + int dst, src; + + /* Strip "\r\n" if it is there */ + if (len != 0 && cmd[len - 1] == '\n') { + len--; + if (len != 0 && cmd[len - 1] == '\r') + len--; + cmd[len] = '\0'; + } + src = strchrnul(cmd, 0xff) - cmd; + /* 99,99% there are neither NULs nor 255s and src == len */ + if (src < len) { + dst = src; + do { + if ((unsigned char)(cmd[src]) == 255) { + src++; + /* 255,xxx - skip 255 */ + if ((unsigned char)(cmd[src]) != 255) { + /* 255,!255 - skip both */ + src++; + continue; + } + /* 255,255 - retain one 255 */ + } + /* NUL => '\n' */ + cmd[dst++] = cmd[src] ? cmd[src] : '\n'; + src++; + } while (src < len); + cmd[dst] = '\0'; + } + } + + if (G.verbose > 1) + verbose_log(cmd); + + G.ftp_arg = strchr(cmd, ' '); + if (G.ftp_arg != NULL) + *G.ftp_arg++ = '\0'; + + /* Uppercase and pack into uint32_t first word of the command */ + cmdval = 0; + while (*cmd) + cmdval = (cmdval << 8) + ((unsigned char)*cmd++ & (unsigned char)~0x20); + + return cmdval; +} + +#define mk_const4(a,b,c,d) (((a * 0x100 + b) * 0x100 + c) * 0x100 + d) +#define mk_const3(a,b,c) ((a * 0x100 + b) * 0x100 + c) +enum { + const_ALLO = mk_const4('A', 'L', 'L', 'O'), + const_APPE = mk_const4('A', 'P', 'P', 'E'), + const_CDUP = mk_const4('C', 'D', 'U', 'P'), + const_CWD = mk_const3('C', 'W', 'D'), + const_DELE = mk_const4('D', 'E', 'L', 'E'), + const_EPSV = mk_const4('E', 'P', 'S', 'V'), + const_FEAT = mk_const4('F', 'E', 'A', 'T'), + const_HELP = mk_const4('H', 'E', 'L', 'P'), + const_LIST = mk_const4('L', 'I', 'S', 'T'), + const_MDTM = mk_const4('M', 'D', 'T', 'M'), + const_MKD = mk_const3('M', 'K', 'D'), + const_MODE = mk_const4('M', 'O', 'D', 'E'), + const_NLST = mk_const4('N', 'L', 'S', 'T'), + const_NOOP = mk_const4('N', 'O', 'O', 'P'), + const_PASS = mk_const4('P', 'A', 'S', 'S'), + const_PASV = mk_const4('P', 'A', 'S', 'V'), + const_PORT = mk_const4('P', 'O', 'R', 'T'), + const_PWD = mk_const3('P', 'W', 'D'), + const_QUIT = mk_const4('Q', 'U', 'I', 'T'), + const_REST = mk_const4('R', 'E', 'S', 'T'), + const_RETR = mk_const4('R', 'E', 'T', 'R'), + const_RMD = mk_const3('R', 'M', 'D'), + const_RNFR = mk_const4('R', 'N', 'F', 'R'), + const_RNTO = mk_const4('R', 'N', 'T', 'O'), + const_SIZE = mk_const4('S', 'I', 'Z', 'E'), + const_STAT = mk_const4('S', 'T', 'A', 'T'), + const_STOR = mk_const4('S', 'T', 'O', 'R'), + const_STOU = mk_const4('S', 'T', 'O', 'U'), + const_STRU = mk_const4('S', 'T', 'R', 'U'), + const_SYST = mk_const4('S', 'Y', 'S', 'T'), + const_TYPE = mk_const4('T', 'Y', 'P', 'E'), + const_USER = mk_const4('U', 'S', 'E', 'R'), + +#if !BB_MMU + OPT_l = (1 << 0), + OPT_1 = (1 << 1), +#endif + OPT_v = (1 << ((!BB_MMU) * 2 + 0)), + OPT_S = (1 << ((!BB_MMU) * 2 + 1)), + OPT_w = (1 << ((!BB_MMU) * 2 + 2)) * ENABLE_FEATURE_FTP_WRITE, +}; + +int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +#if !BB_MMU +int ftpd_main(int argc, char **argv) +#else +int ftpd_main(int argc UNUSED_PARAM, char **argv) +#endif +{ + unsigned abs_timeout; + smallint opts; + + INIT_G(); + + abs_timeout = 1 * 60 * 60; + G.timeout = 2 * 60; + opt_complementary = "t+:T+:vv"; +#if BB_MMU + opts = getopt32(argv, "vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose); +#else + opts = getopt32(argv, "l1vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose); + if (opts & (OPT_l|OPT_1)) { + /* Our secret backdoor to ls */ +/* TODO: pass -n too? */ +/* --group-directories-first would be nice, but ls don't do that yet */ + xchdir(argv[2]); + argv[2] = (char*)"--"; + memset(&G, 0, sizeof(G)); + return ls_main(argc, argv); + } +#endif + if (abs_timeout | G.timeout) { + if (abs_timeout == 0) + abs_timeout = INT_MAX; + G.end_time = monotonic_sec() + abs_timeout; + if (G.timeout > abs_timeout) + G.timeout = abs_timeout; + } + strcpy(G.msg_ok + 4, MSG_OK ); + strcpy(G.msg_err + 4, MSG_ERR); + + G.local_addr = get_sock_lsa(STDIN_FILENO); + if (!G.local_addr) { + /* This is confusing: + * bb_error_msg_and_die("stdin is not a socket"); + * Better: */ + bb_show_usage(); + /* Help text says that ftpd must be used as inetd service, + * which is by far the most usual cause of get_sock_lsa + * failure */ + } + + if (!(opts & OPT_v)) + logmode = LOGMODE_NONE; + if (opts & OPT_S) { + /* LOG_NDELAY is needed since we may chroot later */ + openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON); + logmode |= LOGMODE_SYSLOG; + } + if (logmode) + applet_name = xasprintf("%s[%u]", applet_name, (int)getpid()); + +#if !BB_MMU + G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); +#endif + + if (argv[optind]) { + xchdir(argv[optind]); + chroot("."); + } + + //umask(077); - admin can set umask before starting us + + /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ + signal(SIGPIPE, SIG_IGN); + + /* Set up options on the command socket (do we need these all? why?) */ + setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); + setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); + /* Telnet protocol over command link may send "urgent" data, + * we prefer it to be received in the "normal" data stream: */ + setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1)); + + WRITE_OK(FTP_GREET); + signal(SIGALRM, timeout_handler); + +#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN + { + smallint user_was_specified = 0; + while (1) { + uint32_t cmdval = cmdio_get_cmd_and_arg(); + + if (cmdval == const_USER) { + if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) + cmdio_write_raw(STR(FTP_LOGINERR)" Server is anonymous only\r\n"); + else { + user_was_specified = 1; + cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify the password\r\n"); + } + } else if (cmdval == const_PASS) { + if (user_was_specified) + break; + cmdio_write_raw(STR(FTP_NEEDUSER)" Login with USER\r\n"); + } else if (cmdval == const_QUIT) { + WRITE_OK(FTP_GOODBYE); + return 0; + } else { + cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); + } + } + } + WRITE_OK(FTP_LOGINOK); +#endif + + /* RFC-959 Section 5.1 + * The following commands and options MUST be supported by every + * server-FTP and user-FTP, except in cases where the underlying + * file system or operating system does not allow or support + * a particular command. + * Type: ASCII Non-print, IMAGE, LOCAL 8 + * Mode: Stream + * Structure: File, Record* + * (Record structure is REQUIRED only for hosts whose file + * systems support record structure). + * Commands: + * USER, PASS, ACCT, [bbox: ACCT not supported] + * PORT, PASV, + * TYPE, MODE, STRU, + * RETR, STOR, APPE, + * RNFR, RNTO, DELE, + * CWD, CDUP, RMD, MKD, PWD, + * LIST, NLST, + * SYST, STAT, + * HELP, NOOP, QUIT. + */ + /* ACCOUNT (ACCT) + * "The argument field is a Telnet string identifying the user's account. + * The command is not necessarily related to the USER command, as some + * sites may require an account for login and others only for specific + * access, such as storing files. In the latter case the command may + * arrive at any time. + * There are reply codes to differentiate these cases for the automation: + * when account information is required for login, the response to + * a successful PASSword command is reply code 332. On the other hand, + * if account information is NOT required for login, the reply to + * a successful PASSword command is 230; and if the account information + * is needed for a command issued later in the dialogue, the server + * should return a 332 or 532 reply depending on whether it stores + * (pending receipt of the ACCounT command) or discards the command, + * respectively." + */ + + while (1) { + uint32_t cmdval = cmdio_get_cmd_and_arg(); + + if (cmdval == const_QUIT) { + WRITE_OK(FTP_GOODBYE); + return 0; + } + else if (cmdval == const_USER) + /* This would mean "ok, now give me PASS". */ + /*WRITE_OK(FTP_GIVEPWORD);*/ + /* vsftpd can be configured to not require that, + * and this also saves one roundtrip: + */ + WRITE_OK(FTP_LOGINOK); + else if (cmdval == const_PASS) + WRITE_OK(FTP_LOGINOK); + else if (cmdval == const_NOOP) + WRITE_OK(FTP_NOOPOK); + else if (cmdval == const_TYPE) + WRITE_OK(FTP_TYPEOK); + else if (cmdval == const_STRU) + WRITE_OK(FTP_STRUOK); + else if (cmdval == const_MODE) + WRITE_OK(FTP_MODEOK); + else if (cmdval == const_ALLO) + WRITE_OK(FTP_ALLOOK); + else if (cmdval == const_SYST) + cmdio_write_raw(STR(FTP_SYSTOK)" UNIX Type: L8\r\n"); + else if (cmdval == const_PWD) + handle_pwd(); + else if (cmdval == const_CWD) + handle_cwd(); + else if (cmdval == const_CDUP) /* cd .. */ + handle_cdup(); + /* HELP is nearly useless, but we can reuse FEAT for it */ + /* lftp uses FEAT */ + else if (cmdval == const_HELP || cmdval == const_FEAT) + handle_feat(cmdval == const_HELP + ? STRNUM32(FTP_HELP) + : STRNUM32(FTP_STATOK) + ); + else if (cmdval == const_LIST) /* ls -l */ + handle_list(); + else if (cmdval == const_NLST) /* "name list", bare ls */ + handle_nlst(); + /* SIZE is crucial for wget's download indicator etc */ + /* Mozilla, lftp use MDTM (presumably for caching) */ + else if (cmdval == const_SIZE || cmdval == const_MDTM) + handle_size_or_mdtm(cmdval == const_SIZE); + else if (cmdval == const_STAT) { + if (G.ftp_arg == NULL) + handle_stat(); + else + handle_stat_file(); + } + else if (cmdval == const_PASV) + handle_pasv(); + else if (cmdval == const_EPSV) + handle_epsv(); + else if (cmdval == const_RETR) + handle_retr(); + else if (cmdval == const_PORT) + handle_port(); + else if (cmdval == const_REST) + handle_rest(); +#if ENABLE_FEATURE_FTP_WRITE + else if (opts & OPT_w) { + if (cmdval == const_STOR) + handle_stor(); + else if (cmdval == const_MKD) + handle_mkd(); + else if (cmdval == const_RMD) + handle_rmd(); + else if (cmdval == const_DELE) + handle_dele(); + else if (cmdval == const_RNFR) /* "rename from" */ + handle_rnfr(); + else if (cmdval == const_RNTO) /* "rename to" */ + handle_rnto(); + else if (cmdval == const_APPE) + handle_appe(); + else if (cmdval == const_STOU) /* "store unique" */ + handle_stou(); + } +#endif +#if 0 + else if (cmdval == const_STOR + || cmdval == const_MKD + || cmdval == const_RMD + || cmdval == const_DELE + || cmdval == const_RNFR + || cmdval == const_RNTO + || cmdval == const_APPE + || cmdval == const_STOU + ) { + cmdio_write_raw(STR(FTP_NOPERM)" Permission denied\r\n"); + } +#endif + else { + /* Which unsupported commands were seen in the wild? + * (doesn't necessarily mean "we must support them") + * foo 1.2.3: XXXX - comment + */ + cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n"); + } + } +} diff --git a/release/src/router/busybox/networking/httpd.c b/release/src/router/busybox/networking/httpd.c index 82891f121e..6bf103c56f 100644 --- a/release/src/router/busybox/networking/httpd.c +++ b/release/src/router/busybox/networking/httpd.c @@ -97,7 +97,7 @@ #include "libbb.h" #if ENABLE_FEATURE_HTTPD_USE_SENDFILE -#include +# include #endif //#define DEBUG 1 @@ -254,6 +254,9 @@ struct globals { USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) USE_FEATURE_HTTPD_CGI(char *referer;) USE_FEATURE_HTTPD_CGI(char *user_agent;) + USE_FEATURE_HTTPD_CGI(char *host;) + USE_FEATURE_HTTPD_CGI(char *http_accept;) + USE_FEATURE_HTTPD_CGI(char *http_accept_language;) off_t file_size; /* -1 - unknown */ #if ENABLE_FEATURE_HTTPD_RANGES @@ -265,9 +268,7 @@ struct globals { #if ENABLE_FEATURE_HTTPD_BASIC_AUTH Htaccess *g_auth; /* config user:password lines */ #endif -#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES Htaccess *mime_a; /* config mime types */ -#endif #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR Htaccess *script_i; /* config script interpreters */ #endif @@ -299,11 +300,20 @@ struct globals { #define remoteuser (G.remoteuser ) #define referer (G.referer ) #define user_agent (G.user_agent ) +#define host (G.host ) +#define http_accept (G.http_accept ) +#define http_accept_language (G.http_accept_language) #define file_size (G.file_size ) #if ENABLE_FEATURE_HTTPD_RANGES #define range_start (G.range_start ) #define range_end (G.range_end ) #define range_len (G.range_len ) +#else +enum { + range_start = 0, + range_end = MAXINT(off_t) - 1, + range_len = MAXINT(off_t), +}; #endif #define rmt_ip_str (G.rmt_ip_str ) #define g_auth (G.g_auth ) @@ -322,14 +332,6 @@ struct globals { file_size = -1; \ } while (0) -#if !ENABLE_FEATURE_HTTPD_RANGES -enum { - range_start = 0, - range_end = MAXINT(off_t) - 1, - range_len = MAXINT(off_t), -}; -#endif - #define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) @@ -352,14 +354,10 @@ static void free_llist(has_next_ptr **pptr) *pptr = NULL; } -#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr) { free_llist((has_next_ptr**)pptr); } -#endif static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr) { @@ -482,11 +480,7 @@ static void parse_conf(const char *path, int flag) #if ENABLE_FEATURE_HTTPD_BASIC_AUTH Htaccess *prev; #endif -#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR Htaccess *cur; -#endif const char *filename = configFile; char buf[160]; char *p, *p0; @@ -496,22 +490,16 @@ static void parse_conf(const char *path, int flag) /* discard old rules */ free_Htaccess_IP_list(&ip_a_d); flg_deny_all = 0; -#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR /* retain previous auth and mime config only for subdir parse */ if (flag != SUBDIR_PARSE) { #if ENABLE_FEATURE_HTTPD_BASIC_AUTH free_Htaccess_list(&g_auth); #endif -#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES free_Htaccess_list(&mime_a); -#endif #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR free_Htaccess_list(&script_i); #endif } -#endif if (flag == SUBDIR_PARSE || filename == NULL) { filename = alloca(strlen(path) + sizeof(httpd_conf) + 2); @@ -695,9 +683,6 @@ static void parse_conf(const char *path, int flag) continue; } -#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ - || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR /* storing current config line */ cur = xzalloc(sizeof(Htaccess) + strlen(p0)); strcpy(cur->before_colon, p0); @@ -707,14 +692,12 @@ static void parse_conf(const char *path, int flag) #endif cur->after_colon = strchr(cur->before_colon, ':'); *cur->after_colon++ = '\0'; -#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES if (cur->before_colon[0] == '.') { /* .mime line: prepend to mime_a list */ cur->next = mime_a; mime_a = cur; continue; } -#endif #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR if (cur->before_colon[0] == '*' && cur->before_colon[1] == '.') { /* script interpreter line: prepend to script_i list */ @@ -756,7 +739,6 @@ static void parse_conf(const char *path, int flag) } } #endif /* BASIC_AUTH */ -#endif /* BASIC_AUTH || MIME_TYPES || SCRIPT_INTERPR */ } /* while (fgets) */ fclose(f); } @@ -963,7 +945,7 @@ static void send_headers(int responseNum) const char *error_page = NULL; #endif unsigned i; - time_t timer = time(0); + time_t timer = time(NULL); char tmp_str[80]; int len; @@ -1077,6 +1059,7 @@ static int get_line(void) int count = 0; char c; + alarm(HEADER_READ_TIMEOUT); while (1) { if (hdr_cnt <= 0) { hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf)); @@ -1091,7 +1074,7 @@ static int get_line(void) continue; if (c == '\n') { iobuf[count] = '\0'; - return count; + break; } if (count < (IOBUF_SIZE - 1)) /* check overflow */ count++; @@ -1384,6 +1367,10 @@ static void send_cgi_and_exit( } } setenv1("HTTP_USER_AGENT", user_agent); + if (http_accept) + setenv1("HTTP_ACCEPT", http_accept); + if (http_accept_language) + setenv1("HTTP_ACCEPT_LANGUAGE", http_accept_language); if (post_len) putenv(xasprintf("CONTENT_LENGTH=%d", post_len)); if (cookie) @@ -1398,6 +1385,9 @@ static void send_cgi_and_exit( #endif if (referer) setenv1("HTTP_REFERER", referer); + setenv1("HTTP_HOST", host); /* set to "" if NULL */ + /* setenv1("SERVER_NAME", safe_gethostname()); - don't do this, + * just run "env SERVER_NAME=xyz httpd ..." instead */ xpiped_pair(fromCgi); xpiped_pair(toCgi); @@ -1496,7 +1486,7 @@ static void send_cgi_and_exit( * const char *url The requested URL (with leading /). * what What to send (headers/body/both). */ -static void send_file_and_exit(const char *url, int what) +static NOINLINE void send_file_and_exit(const char *url, int what) { static const char *const suffixTable[] = { /* Warning: shorter equivalent suffix in one line must be first */ @@ -1521,13 +1511,26 @@ static void send_file_and_exit(const char *url, int what) }; char *suffix; - int f; + int fd; const char *const *table; const char *try_suffix; ssize_t count; -#if ENABLE_FEATURE_HTTPD_USE_SENDFILE - off_t offset; -#endif + + fd = open(url, O_RDONLY); + if (fd < 0) { + if (DEBUG) + bb_perror_msg("can't open '%s'", url); + /* Error pages are sent by using send_file_and_exit(SEND_BODY). + * IOW: it is unsafe to call send_headers_and_exit + * if what is SEND_BODY! Can recurse! */ + if (what != SEND_BODY) + send_headers_and_exit(HTTP_NOT_FOUND); + log_and_exit(); + } + + if (DEBUG) + bb_error_msg("sending file '%s' content-type: %s", + url, found_mime_type); /* If you want to know about EPIPE below * (happens if you abort downloads from local httpd): */ @@ -1538,9 +1541,7 @@ static void send_file_and_exit(const char *url, int what) /* If not found, set default as "application/octet-stream"; */ found_mime_type = "application/octet-stream"; if (suffix) { -#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES Htaccess *cur; -#endif for (table = suffixTable; *table; table += 2) { try_suffix = strstr(table[0], suffix); if (try_suffix) { @@ -1551,30 +1552,12 @@ static void send_file_and_exit(const char *url, int what) } } } -#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES for (cur = mime_a; cur; cur = cur->next) { if (strcmp(cur->before_colon, suffix) == 0) { found_mime_type = cur->after_colon; break; } } -#endif - } - - if (DEBUG) - bb_error_msg("sending file '%s' content-type: %s", - url, found_mime_type); - - f = open(url, O_RDONLY); - if (f < 0) { - if (DEBUG) - bb_perror_msg("can't open '%s'", url); - /* Error pages are sent by using send_file_and_exit(SEND_BODY). - * IOW: it is unsafe to call send_headers_and_exit - * if what is SEND_BODY! Can recurse! */ - if (what != SEND_BODY) - send_headers_and_exit(HTTP_NOT_FOUND); - log_and_exit(); } #if ENABLE_FEATURE_HTTPD_RANGES if (what == SEND_BODY) @@ -1585,9 +1568,9 @@ static void send_file_and_exit(const char *url, int what) range_end = file_size - 1; } if (range_end < range_start - || lseek(f, range_start, SEEK_SET) != range_start + || lseek(fd, range_start, SEEK_SET) != range_start ) { - lseek(f, 0, SEEK_SET); + lseek(fd, 0, SEEK_SET); range_start = 0; } else { range_len = range_end - range_start + 1; @@ -1596,43 +1579,42 @@ static void send_file_and_exit(const char *url, int what) } } #endif - if (what & SEND_HEADERS) send_headers(HTTP_OK); - #if ENABLE_FEATURE_HTTPD_USE_SENDFILE - offset = range_start; - do { - /* sz is rounded down to 64k */ - ssize_t sz = MAXINT(ssize_t) - 0xffff; - USE_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;) - count = sendfile(1, f, &offset, sz); - if (count < 0) { - if (offset == range_start) - goto fallback; - goto fin; + { + off_t offset = range_start; + while (1) { + /* sz is rounded down to 64k */ + ssize_t sz = MAXINT(ssize_t) - 0xffff; + USE_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;) + count = sendfile(STDOUT_FILENO, fd, &offset, sz); + if (count < 0) { + if (offset == range_start) + break; /* fall back to read/write loop */ + goto fin; + } + USE_FEATURE_HTTPD_RANGES(range_len -= sz;) + if (count == 0 || range_len == 0) + log_and_exit(); } - USE_FEATURE_HTTPD_RANGES(range_len -= sz;) - } while (count > 0 && range_len); - log_and_exit(); - - fallback: + } #endif - while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) { + while ((count = safe_read(fd, iobuf, IOBUF_SIZE)) > 0) { ssize_t n; USE_FEATURE_HTTPD_RANGES(if (count > range_len) count = range_len;) n = full_write(STDOUT_FILENO, iobuf, count); if (count != n) break; USE_FEATURE_HTTPD_RANGES(range_len -= count;) - if (!range_len) + if (range_len == 0) break; } -#if ENABLE_FEATURE_HTTPD_USE_SENDFILE - fin: -#endif - if (count < 0 && verbose > 1) - bb_perror_msg("error"); + if (count < 0) { + USE_FEATURE_HTTPD_USE_SENDFILE(fin:) + if (verbose > 1) + bb_perror_msg("error"); + } log_and_exit(); } @@ -1760,8 +1742,8 @@ static Htaccess_Proxy *find_proxy_entry(const char *url) /* * Handle timeouts */ -static void exit_on_signal(int sig) NORETURN; -static void exit_on_signal(int sig UNUSED_PARAM) +static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; +static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) { send_headers_and_exit(HTTP_REQUEST_TIMEOUT); } @@ -1826,9 +1808,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) bb_error_msg("connected"); } - /* Install timeout handler */ - signal_no_SA_RESTART_empty_mask(SIGALRM, exit_on_signal); - alarm(HEADER_READ_TIMEOUT); + /* Install timeout handler. get_line() needs it. */ + signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); if (!get_line()) /* EOF or error or empty line */ send_headers_and_exit(HTTP_BAD_REQUEST); @@ -1955,7 +1936,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Read until blank line for HTTP version specified, else parse immediate */ while (1) { - alarm(HEADER_READ_TIMEOUT); if (!get_line()) break; /* EOF or error or empty line */ if (DEBUG) @@ -2005,6 +1985,12 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1)); } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) { user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1)); + } else if (STRNCASECMP(iobuf, "Host:") == 0) { + host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1)); + } else if (STRNCASECMP(iobuf, "Accept:") == 0) { + http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1)); + } else if (STRNCASECMP(iobuf, "Accept-Language:") == 0) { + http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1)); } #endif #if ENABLE_FEATURE_HTTPD_BASIC_AUTH @@ -2182,10 +2168,8 @@ static void mini_httpd(int server_socket) if (fork() == 0) { /* child */ -#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP /* Do not reload config on HUP */ signal(SIGHUP, SIG_IGN); -#endif close(server_socket); xmove_fd(n, 0); xdup2(0, 1); @@ -2227,10 +2211,8 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) if (vfork() == 0) { /* child */ -#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP /* Do not reload config on HUP */ signal(SIGHUP, SIG_IGN); -#endif close(server_socket); xmove_fd(n, 0); xdup2(0, 1); @@ -2261,13 +2243,10 @@ static void mini_httpd_inetd(void) handle_incoming_and_exit(&fromAddr); } -#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP -static void sighup_handler(int sig) +static void sighup_handler(int sig UNUSED_PARAM) { - parse_conf(default_path_httpd_conf, sig ? SIGNALED_PARSE : FIRST_PARSE); - signal_SA_RESTART_empty_mask(SIGHUP, sighup_handler); + parse_conf(default_path_httpd_conf, SIGNALED_PARSE); } -#endif enum { c_opt_config_file = 0, @@ -2378,7 +2357,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) #endif } -#if 0 /*was #if ENABLE_FEATURE_HTTPD_CGI*/ +#if 0 /* User can do it himself: 'env - PATH="$PATH" httpd' * We don't do it because we don't want to screw users * which want to do @@ -2396,15 +2375,9 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) } #endif -#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP - if (!(opt & OPT_INETD)) { - /* runs parse_conf() inside */ - sighup_handler(0); - } else -#endif - { - parse_conf(default_path_httpd_conf, FIRST_PARSE); - } + parse_conf(default_path_httpd_conf, FIRST_PARSE); + if (!(opt & OPT_INETD)) + signal(SIGHUP, sighup_handler); xfunc_error_retval = 0; if (opt & OPT_INETD) diff --git a/release/src/router/busybox/networking/ifconfig.c b/release/src/router/busybox/networking/ifconfig.c index e999741d12..22b1682bc8 100644 --- a/release/src/router/busybox/networking/ifconfig.c +++ b/release/src/router/busybox/networking/ifconfig.c @@ -313,7 +313,7 @@ int ifconfig_main(int argc, char **argv) sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); /* get interface name */ - strncpy(ifr.ifr_name, *argv, IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.ifr_name, *argv); /* Process the remaining arguments. */ while (*++argv != (char *) NULL) { diff --git a/release/src/router/busybox/networking/ifenslave.c b/release/src/router/busybox/networking/ifenslave.c index 13a32efc8d..fa226425aa 100644 --- a/release/src/router/busybox/networking/ifenslave.c +++ b/release/src/router/busybox/networking/ifenslave.c @@ -100,14 +100,19 @@ #include "libbb.h" +/* #include - no. linux/if_bonding.h pulls in linux/if.h */ #include #include #include -typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */ -typedef uint32_t u32; /* ditto */ -typedef uint16_t u16; /* ditto */ -typedef uint8_t u8; /* ditto */ +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +typedef uint64_t u64; /* hack, so we may include kernel's ethtool.h */ +typedef uint32_t u32; /* ditto */ +typedef uint16_t u16; /* ditto */ +typedef uint8_t u8; /* ditto */ #include @@ -135,11 +140,6 @@ struct globals { /* NOINLINEs are placed where it results in smaller code (gcc 4.3.1) */ -static void strncpy_IFNAMSIZ(char *dst, const char *src) -{ - strncpy(dst, src, IFNAMSIZ); -} - static int ioctl_on_skfd(unsigned request, struct ifreq *ifr) { return ioctl(skfd, request, ifr); diff --git a/release/src/router/busybox/networking/ifupdown.c b/release/src/router/busybox/networking/ifupdown.c index c232d86a6f..dc7ed490b3 100644 --- a/release/src/router/busybox/networking/ifupdown.c +++ b/release/src/router/busybox/networking/ifupdown.c @@ -31,6 +31,8 @@ #define MAX_INTERFACE_LENGTH 10 #endif +#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS + #define debug_noise(args...) /*fprintf(stderr, args)*/ /* Forward declaration */ @@ -349,7 +351,7 @@ static int static_up6(struct interface_defn_t *ifd, execfn *exec) int result; #if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); - result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", 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); #else @@ -433,7 +435,7 @@ static int static_up(struct interface_defn_t *ifd, execfn *exec) #if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); - result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", 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); return ((result == 3) ? 3 : 0); #else @@ -487,7 +489,7 @@ static const struct dhcp_client_t ext_dhcp_clients[] = { "pump -i %iface% -k", }, { "udhcpc", - "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]]" + "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]]" "[[ -s %script%]][[ %udhcpc_opts%]]", "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", }, @@ -500,7 +502,7 @@ static int dhcp_up(struct interface_defn_t *ifd, execfn *exec) unsigned i; #if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ - if (!execute("ip link set[[ address %hwaddress%]] %iface% up", ifd, exec)) + if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; #else /* needed if we have hwaddress on dhcp iface */ @@ -519,14 +521,14 @@ static int dhcp_up(struct interface_defn_t *ifd, execfn *exec) { #if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ - if (!execute("ip link set[[ address %hwaddress%]] %iface% up", ifd, exec)) + if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; #else /* needed if we have hwaddress on dhcp iface */ if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) return 0; #endif - return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid " + return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid " "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]][[ %udhcpc_opts%]]", ifd, exec); } @@ -690,20 +692,6 @@ static const struct method_t *get_method(const struct address_family_t *af, char return NULL; } -static const llist_t *find_list_string(const llist_t *list, const char *string) -{ - if (string == NULL) - return NULL; - - while (list) { - if (strcmp(list->data, string) == 0) { - return list; - } - list = list->link; - } - return NULL; -} - static struct interfaces_file_t *read_interfaces(const char *filename) { /* Let's try to be compatible. @@ -834,7 +822,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) while ((first_word = next_word(&rest_of_line)) != NULL) { /* Check the interface isnt already listed */ - if (find_list_string(defn->autointerfaces, first_word)) { + if (llist_find_str(defn->autointerfaces, first_word)) { bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf); } @@ -980,7 +968,7 @@ static int doit(char *str) case -1: /* failure */ return 0; case 0: /* child */ - execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ); + execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, (char *) NULL, my_environ); _exit(127); } safe_waitpid(child, &status, 0); diff --git a/release/src/router/busybox/networking/inetd.c b/release/src/router/busybox/networking/inetd.c index 9ebec19a51..590bf23d2f 100644 --- a/release/src/router/busybox/networking/inetd.c +++ b/release/src/router/busybox/networking/inetd.c @@ -223,7 +223,7 @@ typedef struct servtab_t { smallint se_checked; /* looked at during merge */ unsigned se_max; /* allowed instances per minute */ unsigned se_count; /* number started since se_time */ - unsigned se_time; /* whem we started counting */ + unsigned se_time; /* when we started counting */ char *se_user; /* user name to run as */ char *se_group; /* group name to run as, can be NULL */ #ifdef INETD_BUILTINS_ENABLED @@ -295,14 +295,15 @@ struct globals { struct rlimit rlim_ofile; servtab_t *serv_list; int global_queuelen; + int maxsock; /* max fd# in allsock, -1: unknown */ + /* whenever maxsock grows, prev_maxsock is set to new maxsock, + * but if maxsock is set to -1, prev_maxsock is not changed */ int prev_maxsock; - int maxsock; unsigned max_concurrency; smallint alarm_armed; uid_t real_uid; /* user ID who ran us */ - unsigned config_lineno; const char *config_filename; - FILE *fconfig; + parser_t *parser; char *default_local_hostname; #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN char *end_ring; @@ -322,14 +323,13 @@ struct BUG_G_too_big { #define rlim_ofile (G.rlim_ofile ) #define serv_list (G.serv_list ) #define global_queuelen (G.global_queuelen) -#define prev_maxsock (G.prev_maxsock ) #define maxsock (G.maxsock ) +#define prev_maxsock (G.prev_maxsock ) #define max_concurrency (G.max_concurrency) #define alarm_armed (G.alarm_armed ) #define real_uid (G.real_uid ) -#define config_lineno (G.config_lineno ) #define config_filename (G.config_filename) -#define fconfig (G.fconfig ) +#define parser (G.parser ) #define default_local_hostname (G.default_local_hostname) #define first_ps_byte (G.first_ps_byte ) #define last_ps_byte (G.last_ps_byte ) @@ -461,7 +461,7 @@ static void add_fd_to_set(int fd) FD_SET(fd, &allsock); if (maxsock >= 0 && fd > maxsock) { prev_maxsock = maxsock = fd; - if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) + if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) bump_nofile(); } } @@ -470,6 +470,10 @@ static void add_fd_to_set(int fd) static void recalculate_maxsock(void) { int fd = 0; + + /* We may have no services, in this case maxsock should still be >= 0 + * (code elsewhere is not happy with maxsock == -1) */ + maxsock = 0; while (fd <= prev_maxsock) { if (FD_ISSET(fd, &allsock)) maxsock = fd; @@ -543,59 +547,18 @@ static int reopen_config_file(void) { free(default_local_hostname); default_local_hostname = xstrdup("*"); - if (fconfig != NULL) - fclose(fconfig); - config_lineno = 0; - fconfig = fopen_or_warn(config_filename, "r"); - return (fconfig != NULL); + if (parser != NULL) + config_close(parser); + parser = config_open(config_filename); + return (parser != NULL); } static void close_config_file(void) { - if (fconfig) { - fclose(fconfig); - fconfig = NULL; - } -} - -static char *next_line(void) -{ - if (fgets(line, LINE_SIZE, fconfig) == NULL) - return NULL; - config_lineno++; - *strchrnul(line, '\n') = '\0'; - return line; -} - -static char *next_word(char **cpp) -{ - char *start; - char *cp = *cpp; - - if (cp == NULL) - return NULL; - again: - while (*cp == ' ' || *cp == '\t') - cp++; - if (*cp == '\0') { - int c = getc(fconfig); - ungetc(c, fconfig); - if (c == ' ' || c == '\t') { - cp = next_line(); - if (cp) - goto again; - } - *cpp = NULL; - return NULL; + if (parser) { + config_close(parser); + parser = NULL; } - start = cp; - while (*cp && *cp != ' ' && *cp != '\t') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - *cpp = cp; - return start; } static void free_servtab_strings(servtab_t *cp) @@ -643,55 +606,49 @@ static servtab_t *dup_servtab(servtab_t *sep) } /* gcc generates much more code if this is inlined */ -static NOINLINE servtab_t *parse_one_line(void) +static servtab_t *parse_one_line(void) { int argc; - char *p, *cp, *arg; + char *token[6+MAXARGV]; + char *p, *arg; char *hostdelim; servtab_t *sep; servtab_t *nsep; new: sep = new_servtab(); more: - while ((cp = next_line()) && *cp == '#') - continue; /* skip comment lines */ - if (cp == NULL) { + argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL); + if (!argc) { free(sep); return NULL; } - arg = next_word(&cp); - if (arg == NULL) /* a blank line. */ - goto more; - /* [host:]service socktype proto wait user[:group] prog [args] */ /* Check for "host:...." line */ + arg = token[0]; hostdelim = strrchr(arg, ':'); if (hostdelim) { *hostdelim = '\0'; sep->se_local_hostname = xstrdup(arg); arg = hostdelim + 1; - if (*arg == '\0') { - arg = next_word(&cp); - if (arg == NULL) { - /* Line has just "host:", change the - * default host for the following lines. */ - free(default_local_hostname); - default_local_hostname = sep->se_local_hostname; - goto more; - } + if (*arg == '\0' && argc == 1) { + /* Line has just "host:", change the + * default host for the following lines. */ + free(default_local_hostname); + default_local_hostname = sep->se_local_hostname; + goto more; } } else sep->se_local_hostname = xstrdup(default_local_hostname); /* service socktype proto wait user[:group] prog [args] */ sep->se_service = xstrdup(arg); + /* socktype proto wait user[:group] prog [args] */ - arg = next_word(&cp); - if (arg == NULL) { + if (argc < 6) { parse_err: bb_error_msg("parse error on line %u, line is ignored", - config_lineno); + parser->lineno); free_servtab_strings(sep); /* Just "goto more" can make sep to carry over e.g. * "rpc"-ness (by having se_rpcver_lo != 0). @@ -699,6 +656,7 @@ static NOINLINE servtab_t *parse_one_line(void) free(sep); goto new; } + { static int8_t SOCK_xxx[] ALIGN1 = { -1, @@ -708,13 +666,11 @@ static NOINLINE servtab_t *parse_one_line(void) sep->se_socktype = SOCK_xxx[1 + index_in_strings( "stream""\0" "dgram""\0" "rdm""\0" "seqpacket""\0" "raw""\0" - , arg)]; + , token[1])]; } /* {unix,[rpc/]{tcp,udp}[6]} wait user[:group] prog [args] */ - sep->se_proto = arg = xstrdup(next_word(&cp)); - if (arg == NULL) - goto parse_err; + sep->se_proto = arg = xstrdup(token[2]); if (strcmp(arg, "unix") == 0) { sep->se_family = AF_UNIX; } else { @@ -773,9 +729,7 @@ static NOINLINE servtab_t *parse_one_line(void) } /* [no]wait[.max] user[:group] prog [args] */ - arg = next_word(&cp); - if (arg == NULL) - goto parse_err; + arg = token[3]; sep->se_max = max_concurrency; p = strchr(arg, '.'); if (p) { @@ -791,9 +745,7 @@ static NOINLINE servtab_t *parse_one_line(void) goto parse_err; /* user[:group] prog [args] */ - sep->se_user = xstrdup(next_word(&cp)); - if (sep->se_user == NULL) - goto parse_err; + sep->se_user = xstrdup(token[4]); arg = strchr(sep->se_user, '.'); if (arg == NULL) arg = strchr(sep->se_user, ':'); @@ -803,9 +755,7 @@ static NOINLINE servtab_t *parse_one_line(void) } /* prog [args] */ - sep->se_program = xstrdup(next_word(&cp)); - if (sep->se_program == NULL) - goto parse_err; + sep->se_program = xstrdup(token[5]); #ifdef INETD_BUILTINS_ENABLED if (strcmp(sep->se_program, "internal") == 0 && strlen(sep->se_service) <= 7 @@ -826,7 +776,7 @@ static NOINLINE servtab_t *parse_one_line(void) } #endif argc = 0; - while ((arg = next_word(&cp)) != NULL && argc < MAXARGV) + while ((arg = token[6+argc]) != NULL && argc < MAXARGV) sep->se_argv[argc++] = xstrdup(arg); /* catch mixups. " stream udp ..." == wtf */ @@ -839,6 +789,11 @@ static NOINLINE servtab_t *parse_one_line(void) goto parse_err; } +// bb_info_msg( +// "ENTRY[%s][%s][%s][%d][%d][%d][%d][%d][%s][%s][%s]", +// sep->se_local_hostname, sep->se_service, sep->se_proto, sep->se_wait, sep->se_proto_no, +// sep->se_max, sep->se_count, sep->se_time, sep->se_user, sep->se_group, sep->se_program); + /* check if the hostname specifier is a comma separated list * of hostnames. we'll make new entries for each address. */ while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) { @@ -1164,7 +1119,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) else bb_sanitize_stdio(); if (!(opt & 4)) { - openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); + openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } @@ -1212,7 +1167,8 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) readable = allsock; /* struct copy */ /* if there are no fds to wait on, we will block - * until signal wakes us up */ + * until signal wakes us up (maxsock == 0, but readable + * never contains fds 0 and 1...) */ ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL); if (ready_fd_cnt < 0) { if (errno != EINTR) { @@ -1343,7 +1299,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) if (sep->se_builtin) { if (pid) { /* "pid" is -1: we did vfork */ close(sep->se_fd); /* listening socket */ - logmode = 0; /* make xwrite etc silent */ + logmode = LOGMODE_NONE; /* make xwrite etc silent */ } restore_sigmask(&omask); if (sep->se_socktype == SOCK_STREAM) @@ -1469,7 +1425,7 @@ static void echo_dg(int s, servtab_t *sep) #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD -/* Discard service -- ignore data. MMU arches only. */ +/* Discard service -- ignore data. */ /* ARGSUSED */ static void discard_stream(int s, servtab_t *sep UNUSED_PARAM) { diff --git a/release/src/router/busybox/networking/interface.c b/release/src/router/busybox/networking/interface.c index d22972fb88..a4b58ec699 100644 --- a/release/src/router/busybox/networking/interface.c +++ b/release/src/router/busybox/networking/interface.c @@ -91,7 +91,7 @@ struct in6_ifreq { /* Display an Internet socket address. */ static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric) { - static char *buff; + static char *buff; /* defaults to NULL */ free(buff); if (sap->sa_family == 0xFFFF || sap->sa_family == 0) @@ -395,7 +395,7 @@ static struct interface *add_interface(char *name) } new = xzalloc(sizeof(*new)); - strncpy(new->name, name, IFNAMSIZ); + strncpy_IFNAMSIZ(new->name, name); nextp = ife ? &ife->next : &int_list; new->prev = ife; new->next = *nextp; @@ -614,39 +614,39 @@ static int if_fetch(struct interface *ife) skfd = xsocket(AF_INET, SOCK_DGRAM, 0); - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { close(skfd); return -1; } ife->flags = ifr.ifr_flags; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(ife->hwaddr, 0, 32); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); ife->type = ifr.ifr_hwaddr.sa_family; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->metric = 0; if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) ife->metric = ifr.ifr_metric; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->mtu = 0; if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) ife->mtu = ifr.ifr_mtu; memset(&ife->map, 0, sizeof(struct ifmap)); #ifdef SIOCGIFMAP - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) ife->map = ifr.ifr_map; #endif #ifdef HAVE_TXQUEUELEN - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->tx_queue_len = -1; /* unknown value */ if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) ife->tx_queue_len = ifr.ifr_qlen; @@ -654,23 +654,23 @@ static int if_fetch(struct interface *ife) ife->tx_queue_len = -1; /* unknown value */ #endif - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ifr.ifr_addr.sa_family = AF_INET; memset(&ife->addr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { ife->has_ip = 1; ife->addr = ifr.ifr_addr; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) ife->dstaddr = ifr.ifr_dstaddr; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) ife->broadaddr = ifr.ifr_broadaddr; - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->netmask, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) ife->netmask = ifr.ifr_netmask; @@ -916,21 +916,91 @@ static void print_bytes_scaled(unsigned long long ull, const char *end) printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end); } -static void ife_print(struct interface *ptr) -{ - const struct aftype *ap; - const struct hwtype *hw; - int hf; - int can_compress = 0; #ifdef HAVE_AFINET6 +#define IPV6_ADDR_ANY 0x0000U + +#define IPV6_ADDR_UNICAST 0x0001U +#define IPV6_ADDR_MULTICAST 0x0002U +#define IPV6_ADDR_ANYCAST 0x0004U + +#define IPV6_ADDR_LOOPBACK 0x0010U +#define IPV6_ADDR_LINKLOCAL 0x0020U +#define IPV6_ADDR_SITELOCAL 0x0040U + +#define IPV6_ADDR_COMPATv4 0x0080U + +#define IPV6_ADDR_SCOPE_MASK 0x00f0U + +#define IPV6_ADDR_MAPPED 0x1000U +#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */ + + +static void ife_print6(struct interface *ptr) +{ + FILE *f; char addr6[40], devname[20]; struct sockaddr_in6 sap; int plen, scope, dad_status, if_idx; char addr6p[8][5]; + + f = fopen_for_read(_PATH_PROCNET_IFINET6); + if (f == NULL) + return; + + while (fscanf + (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], + addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, + &dad_status, devname) != EOF + ) { + if (!strcmp(devname, ptr->name)) { + sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + inet_pton(AF_INET6, addr6, + (struct sockaddr *) &sap.sin6_addr); + sap.sin6_family = AF_INET6; + printf(" inet6 addr: %s/%d", + INET6_sprint((struct sockaddr *) &sap, 1), + plen); + printf(" Scope:"); + switch (scope & IPV6_ADDR_SCOPE_MASK) { + case 0: + puts("Global"); + break; + case IPV6_ADDR_LINKLOCAL: + puts("Link"); + break; + case IPV6_ADDR_SITELOCAL: + puts("Site"); + break; + case IPV6_ADDR_COMPATv4: + puts("Compat"); + break; + case IPV6_ADDR_LOOPBACK: + puts("Host"); + break; + default: + puts("Unknown"); + } + } + } + fclose(f); +} +#else +#define ife_print6(a) ((void)0) #endif + +static void ife_print(struct interface *ptr) +{ + const struct aftype *ap; + const struct hwtype *hw; + int hf; + int can_compress = 0; + ap = get_afntype(ptr->addr.sa_family); if (ap == NULL) ap = get_afntype(0); @@ -947,9 +1017,11 @@ static void ife_print(struct interface *ptr) printf("%-10.10s Link encap:%s ", ptr->name, hw->title); /* For some hardware types (eg Ash, ATM) we don't print the hardware address if it's null. */ - if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) && - hw->suppress_null_addr))) + if (hw->print != NULL + && !(hw_null_address(hw, ptr->hwaddr) && hw->suppress_null_addr) + ) { printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr)); + } #ifdef IFF_PORTSEL if (ptr->flags & IFF_PORTSEL) { printf("Media:%s", if_port_text[ptr->map.port] /* [0] */); @@ -971,68 +1043,7 @@ static void ife_print(struct interface *ptr) printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1)); } -#ifdef HAVE_AFINET6 - -#define IPV6_ADDR_ANY 0x0000U - -#define IPV6_ADDR_UNICAST 0x0001U -#define IPV6_ADDR_MULTICAST 0x0002U -#define IPV6_ADDR_ANYCAST 0x0004U - -#define IPV6_ADDR_LOOPBACK 0x0010U -#define IPV6_ADDR_LINKLOCAL 0x0020U -#define IPV6_ADDR_SITELOCAL 0x0040U - -#define IPV6_ADDR_COMPATv4 0x0080U - -#define IPV6_ADDR_SCOPE_MASK 0x00f0U - -#define IPV6_ADDR_MAPPED 0x1000U -#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */ - - f = fopen_for_read(_PATH_PROCNET_IFINET6); - if (f != NULL) { - while (fscanf - (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], - addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, - &dad_status, devname) != EOF - ) { - if (!strcmp(devname, ptr->name)) { - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], - addr6p[4], addr6p[5], addr6p[6], addr6p[7]); - inet_pton(AF_INET6, addr6, - (struct sockaddr *) &sap.sin6_addr); - sap.sin6_family = AF_INET6; - printf(" inet6 addr: %s/%d", - INET6_sprint((struct sockaddr *) &sap, 1), - plen); - printf(" Scope:"); - switch (scope & IPV6_ADDR_SCOPE_MASK) { - case 0: - puts("Global"); - break; - case IPV6_ADDR_LINKLOCAL: - puts("Link"); - break; - case IPV6_ADDR_SITELOCAL: - puts("Site"); - break; - case IPV6_ADDR_COMPATv4: - puts("Compat"); - break; - case IPV6_ADDR_LOOPBACK: - puts("Host"); - break; - default: - puts("Unknown"); - } - } - } - fclose(f); - } -#endif + ife_print6(ptr); printf(" "); /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */ @@ -1124,11 +1135,11 @@ static void ife_print(struct interface *ptr) printf("\n R"); print_bytes_scaled(ptr->stats.rx_bytes, " T"); print_bytes_scaled(ptr->stats.tx_bytes, "\n"); - } - if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma || - ptr->map.base_addr)) { + if (ptr->map.irq || ptr->map.mem_start + || ptr->map.dma || ptr->map.base_addr + ) { printf(" "); if (ptr->map.irq) printf("Interrupt:%d ", ptr->map.irq); @@ -1147,7 +1158,6 @@ static void ife_print(struct interface *ptr) bb_putchar('\n'); } - static int do_if_print(struct interface *ife) /*, int *opt_a)*/ { int res; diff --git a/release/src/router/busybox/networking/ip.c b/release/src/router/busybox/networking/ip.c index 7dcddfd8c6..9903c6800c 100644 --- a/release/src/router/busybox/networking/ip.c +++ b/release/src/router/busybox/networking/ip.c @@ -10,7 +10,7 @@ * Changes: * * Rani Assaf 980929: resolve addresses - * Bernhard Fischer rewrote to use index_in_substr_array + * Bernhard Reutner-Fischer rewrote to use index_in_substr_array */ #include "libbb.h" @@ -31,7 +31,7 @@ static int NORETURN ip_print_help(char **argv UNUSED_PARAM) static int ip_do(int (*ip_func)(char **argv), char **argv) { - argv = ip_parse_common_args(argv); + argv = ip_parse_common_args(argv + 1); return ip_func(argv); } diff --git a/release/src/router/busybox/networking/isrv.h b/release/src/router/busybox/networking/isrv.h index c0158a3e31..f20714df8d 100644 --- a/release/src/router/busybox/networking/isrv.h +++ b/release/src/router/busybox/networking/isrv.h @@ -8,9 +8,7 @@ * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* opaque structure */ struct isrv_state_t; @@ -36,6 +34,4 @@ void isrv_run( int linger_timeout ); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY diff --git a/release/src/router/busybox/networking/isrv_identd.c b/release/src/router/busybox/networking/isrv_identd.c index e08ebd4b3d..e8ba007667 100644 --- a/release/src/router/busybox/networking/isrv_identd.c +++ b/release/src/router/busybox/networking/isrv_identd.c @@ -122,7 +122,7 @@ int fakeidentd_main(int argc UNUSED_PARAM, char **argv) * log to stderr. I like daemontools more. Go their way. * (Or maybe we need yet another option "log to syslog") */ if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) { - openlog(applet_name, 0, LOG_DAEMON); + openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } diff --git a/release/src/router/busybox/networking/libiproute/ip_common.h b/release/src/router/busybox/networking/libiproute/ip_common.h index 305b491c67..aef325281f 100644 --- a/release/src/router/busybox/networking/libiproute/ip_common.h +++ b/release/src/router/busybox/networking/libiproute/ip_common.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ -#ifndef _IP_COMMON_H -#define _IP_COMMON_H 1 +#ifndef IP_COMMON_H +#define IP_COMMON_H 1 #include "libbb.h" #include @@ -13,9 +13,7 @@ #include #endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN extern char **ip_parse_common_args(char **argv); extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); @@ -34,8 +32,6 @@ extern int do_ipmonitor(char **argv); extern int do_multiaddr(char **argv); extern int do_multiroute(char **argv); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* ip_common.h */ +#endif diff --git a/release/src/router/busybox/networking/libiproute/ipaddress.c b/release/src/router/busybox/networking/libiproute/ipaddress.c index 288dccae72..644874f464 100644 --- a/release/src/router/busybox/networking/libiproute/ipaddress.c +++ b/release/src/router/busybox/networking/libiproute/ipaddress.c @@ -83,7 +83,7 @@ static void print_queuelen(char *name) return; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, name); if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) { close(s); return; @@ -280,17 +280,16 @@ static int print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, if (rta_tb[IFA_LOCAL]) { fputs(rt_addr_n2a(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf)), stdout); - if (rta_tb[IFA_ADDRESS] == NULL || - memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) { + if (rta_tb[IFA_ADDRESS] == NULL + || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0 + ) { printf("/%d ", ifa->ifa_prefixlen); } else { printf(" peer %s/%d ", rt_addr_n2a(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), ifa->ifa_prefixlen); @@ -300,14 +299,12 @@ static int print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, if (rta_tb[IFA_BROADCAST]) { printf("brd %s ", rt_addr_n2a(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { printf("any %s ", rt_addr_n2a(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); } diff --git a/release/src/router/busybox/networking/libiproute/iplink.c b/release/src/router/busybox/networking/libiproute/iplink.c index 3b212eed9e..1e7ee07d22 100644 --- a/release/src/router/busybox/networking/libiproute/iplink.c +++ b/release/src/router/busybox/networking/libiproute/iplink.c @@ -41,7 +41,7 @@ static void do_chflags(char *dev, uint32_t flags, uint32_t mask) struct ifreq ifr; int fd; - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); fd = get_ctl_fd(); xioctl(fd, SIOCGIFFLAGS, &ifr); if ((ifr.ifr_flags ^ flags) & mask) { @@ -58,8 +58,8 @@ static void do_changename(char *dev, char *newdev) struct ifreq ifr; int fd; - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); + strncpy_IFNAMSIZ(ifr.ifr_newname, newdev); fd = get_ctl_fd(); xioctl(fd, SIOCSIFNAME, &ifr); close(fd); @@ -73,7 +73,7 @@ static void set_qlen(char *dev, int qlen) s = get_ctl_fd(); memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); ifr.ifr_qlen = qlen; xioctl(s, SIOCSIFTXQLEN, &ifr); close(s); @@ -87,7 +87,7 @@ static void set_mtu(char *dev, int mtu) s = get_ctl_fd(); memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); ifr.ifr_mtu = mtu; xioctl(s, SIOCSIFMTU, &ifr); close(s); @@ -104,7 +104,7 @@ static int get_address(char *dev, int *htype) s = xsocket(PF_PACKET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); xioctl(s, SIOCGIFINDEX, &ifr); memset(&me, 0, sizeof(me)); @@ -128,7 +128,7 @@ static void parse_address(char *dev, int hatype, int halen, char *lla, struct if int alen; memset(ifr, 0, sizeof(*ifr)); - strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name)); + strncpy_IFNAMSIZ(ifr->ifr_name, dev); ifr->ifr_hwaddr.sa_family = hatype; alen = hatype == 1/*ARPHRD_ETHER*/ ? 14/*ETH_HLEN*/ : 19/*INFINIBAND_HLEN*/; @@ -174,15 +174,18 @@ static int do_set(char **argv) char *newname = NULL; int htype, halen; static const char keywords[] ALIGN1 = - "up\0""down\0""name\0""mtu\0""multicast\0""arp\0""addr\0""dev\0"; - enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast, ARG_arp, - ARG_addr, ARG_dev }; + "up\0""down\0""name\0""mtu\0""multicast\0" + "arp\0""address\0""dev\0"; + enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast, + ARG_arp, ARG_addr, ARG_dev }; static const char str_on_off[] ALIGN1 = "on\0""off\0"; enum { PARM_on = 0, PARM_off }; smalluint key; while (*argv) { - key = index_in_strings(keywords, *argv); + /* substring search ensures that e.g. "addr" and "address" + * are both accepted */ + key = index_in_substrings(keywords, *argv); if (key == ARG_up) { mask |= IFF_UP; flags |= IFF_UP; @@ -199,8 +202,7 @@ static int do_set(char **argv) NEXT_ARG(); if (mtu != -1) duparg("mtu", *argv); - if (get_integer(&mtu, *argv, 0)) - invarg(*argv, "mtu"); + mtu = get_unsigned(*argv, "mtu"); } if (key == ARG_multicast) { int param; diff --git a/release/src/router/busybox/networking/libiproute/iproute.c b/release/src/router/busybox/networking/libiproute/iproute.c index bdccad69de..66557d8fdb 100644 --- a/release/src/router/busybox/networking/libiproute/iproute.c +++ b/release/src/router/busybox/networking/libiproute/iproute.c @@ -202,7 +202,6 @@ static int print_route(const struct sockaddr_nl *who UNUSED_PARAM, if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { printf("%s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len @@ -222,7 +221,6 @@ static int print_route(const struct sockaddr_nl *who UNUSED_PARAM, if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { printf("from %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len @@ -252,7 +250,6 @@ static int print_route(const struct sockaddr_nl *who UNUSED_PARAM, and symbolic name will not be useful. */ printf(" src %s ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } @@ -291,7 +288,7 @@ static int iproute_modify(int cmd, unsigned flags, char **argv) { static const char keywords[] ALIGN1 = "src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0") - "dev\0""oif\0""to\0"; + "dev\0""oif\0""to\0""metric\0"; enum { ARG_src, ARG_via, @@ -300,7 +297,8 @@ static int iproute_modify(int cmd, unsigned flags, char **argv) USE_FEATURE_IP_RULE(ARG_table,) ARG_dev, ARG_oif, - ARG_to + ARG_to, + ARG_metric, }; enum { gw_ok = 1 << 0, @@ -366,8 +364,7 @@ USE_FEATURE_IP_RULE(ARG_table,) mxlock |= (1 << RTAX_MTU); NEXT_ARG(); } - if (get_unsigned(&mtu, *argv, 0)) - invarg(*argv, "mtu"); + mtu = get_unsigned(*argv, "mtu"); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); } else if (arg == ARG_protocol) { uint32_t prot; @@ -387,6 +384,11 @@ USE_FEATURE_IP_RULE(ARG_table,) } else if (arg == ARG_dev || arg == ARG_oif) { NEXT_ARG(); d = *argv; + } else if (arg == ARG_metric) { + uint32_t metric; + NEXT_ARG(); + metric = get_u32(*argv, "metric"); + addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); } else { int type; inet_prefix dst; diff --git a/release/src/router/busybox/networking/libiproute/iprule.c b/release/src/router/busybox/networking/libiproute/iprule.c index f92607830e..6c90c6d217 100644 --- a/release/src/router/busybox/networking/libiproute/iprule.c +++ b/release/src/router/busybox/networking/libiproute/iprule.c @@ -13,7 +13,7 @@ * Changes: * * Rani Assaf 980929: resolve addresses - * initially integrated into busybox by Bernhard Fischer + * initially integrated into busybox by Bernhard Reutner-Fischer */ #include @@ -78,7 +78,6 @@ static int print_rule(const struct sockaddr_nl *who UNUSED_PARAM, if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { printf("%s/%u", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len @@ -99,7 +98,6 @@ static int print_rule(const struct sockaddr_nl *who UNUSED_PARAM, if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { printf("to %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len @@ -238,8 +236,7 @@ static int iprule_modify(int cmd, char **argv) key == ARG_priority) { uint32_t pref; NEXT_ARG(); - if (get_u32(&pref, *argv, 0)) - invarg(*argv, "preference"); + pref = get_u32(*argv, "preference"); addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref); } else if (key == ARG_tos) { uint32_t tos; @@ -250,8 +247,7 @@ static int iprule_modify(int cmd, char **argv) } else if (key == ARG_fwmark) { uint32_t fwmark; NEXT_ARG(); - if (get_u32(&fwmark, *argv, 0)) - invarg(*argv, "fwmark"); + fwmark = get_u32(*argv, "fwmark"); addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); } else if (key == ARG_realms) { uint32_t realm; diff --git a/release/src/router/busybox/networking/libiproute/iptunnel.c b/release/src/router/busybox/networking/libiproute/iptunnel.c index 752d81264d..6a841aadbb 100644 --- a/release/src/router/busybox/networking/libiproute/iptunnel.c +++ b/release/src/router/busybox/networking/libiproute/iptunnel.c @@ -6,7 +6,6 @@ * * Authors: Alexey Kuznetsov, * - * * Changes: * * Rani Assaf 980929: resolve addresses @@ -18,10 +17,52 @@ #include #include #include + #ifndef __constant_htons #define __constant_htons htons #endif -#include + +// FYI: #define SIOCDEVPRIVATE 0x89F0 + +/* From linux/if_tunnel.h. #including it proved troublesome + * (redefiniton errors due to name collisions in linux/ and net[inet]/) */ +#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0) +#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) +#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) +#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +//#define SIOCGETPRL (SIOCDEVPRIVATE + 4) +//#define SIOCADDPRL (SIOCDEVPRIVATE + 5) +//#define SIOCDELPRL (SIOCDEVPRIVATE + 6) +//#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) +#define GRE_CSUM __constant_htons(0x8000) +//#define GRE_ROUTING __constant_htons(0x4000) +#define GRE_KEY __constant_htons(0x2000) +#define GRE_SEQ __constant_htons(0x1000) +//#define GRE_STRICT __constant_htons(0x0800) +//#define GRE_REC __constant_htons(0x0700) +//#define GRE_FLAGS __constant_htons(0x00F8) +//#define GRE_VERSION __constant_htons(0x0007) +struct ip_tunnel_parm { + char name[IFNAMSIZ]; + int link; + uint16_t i_flags; + uint16_t o_flags; + uint32_t i_key; + uint32_t o_key; + struct iphdr iph; +}; +/* SIT-mode i_flags */ +//#define SIT_ISATAP 0x0001 +//struct ip_tunnel_prl { +// uint32_t addr; +// uint16_t flags; +// uint16_t __reserved; +// uint32_t datalen; +// uint32_t __reserved2; +// /* data follows */ +//}; +///* PRL flags */ +//#define PRL_DEFAULT 0x0001 #include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" @@ -34,7 +75,7 @@ static int do_ioctl_get_ifindex(char *dev) struct ifreq ifr; int fd; - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); fd = xsocket(AF_INET, SOCK_DGRAM, 0); xioctl(fd, SIOCGIFINDEX, &ifr); close(fd); @@ -47,7 +88,7 @@ static int do_ioctl_get_iftype(char *dev) int fd; int err; - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, dev); fd = xsocket(AF_INET, SOCK_DGRAM, 0); err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr); close(fd); @@ -73,7 +114,7 @@ static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p) int fd; int err; - strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, basedev); ifr.ifr_ifru.ifru_data = (void*)p; fd = xsocket(AF_INET, SOCK_DGRAM, 0); err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr); @@ -88,9 +129,9 @@ static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p) int fd; if (cmd == SIOCCHGTUNNEL && p->name[0]) { - strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, p->name); } else { - strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, basedev); } ifr.ifr_ifru.ifru_data = (void*)p; fd = xsocket(AF_INET, SOCK_DGRAM, 0); @@ -114,9 +155,9 @@ static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p) int fd; if (p->name[0]) { - strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, p->name); } else { - strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, basedev); } ifr.ifr_ifru.ifru_data = (void*)p; fd = xsocket(AF_INET, SOCK_DGRAM, 0); @@ -148,7 +189,7 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) int key; memset(p, 0, sizeof(*p)); - memset(&medium, 0, sizeof(medium)); + medium[0] = '\0'; p->iph.version = 4; p->iph.ihl = 5; @@ -165,23 +206,23 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) if (key == ARG_ipip || key == ARG_ip_ip) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { - bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); + bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_IPIP; } else if (key == ARG_gre || key == ARG_gre_ip) { if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { - bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); + bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_GRE; } else if (key == ARG_sit || key == ARG_ip6_ip) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { - bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); + bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_IPV6; } else { - bb_error_msg_and_die("cannot guess tunnel mode"); + bb_error_msg_and_die("%s tunnel mode", "cannot guess"); } } else if (key == ARG_key) { unsigned uval; @@ -191,9 +232,7 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) if (strchr(*argv, '.')) p->i_key = p->o_key = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0) < 0) { - bb_error_msg_and_die("invalid value of \"key\""); - } + uval = get_unsigned(*argv, "key"); p->i_key = p->o_key = htonl(uval); } } else if (key == ARG_ikey) { @@ -203,9 +242,7 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) if (strchr(*argv, '.')) p->o_key = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0) < 0) { - bb_error_msg_and_die("invalid value of \"ikey\""); - } + uval = get_unsigned(*argv, "ikey"); p->i_key = htonl(uval); } } else if (key == ARG_okey) { @@ -215,9 +252,7 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) if (strchr(*argv, '.')) p->o_key = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0) < 0) { - bb_error_msg_and_die("invalid value of \"okey\""); - } + uval = get_unsigned(*argv, "okey"); p->o_key = htonl(uval); } } else if (key == ARG_seq) { @@ -250,14 +285,13 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) p->iph.saddr = get_addr32(*argv); } else if (key == ARG_dev) { NEXT_ARG(); - strncpy(medium, *argv, IFNAMSIZ-1); + strncpy_IFNAMSIZ(medium, *argv); } else if (key == ARG_ttl) { unsigned uval; NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key != ARG_inherit) { - if (get_unsigned(&uval, *argv, 0)) - invarg(*argv, "TTL"); + uval = get_unsigned(*argv, "TTL"); if (uval > 255) invarg(*argv, "TTL must be <=255"); p->iph.ttl = uval; @@ -279,7 +313,7 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) } if (p->name[0]) duparg2("name", *argv); - strncpy(p->name, *argv, IFNAMSIZ); + strncpy_IFNAMSIZ(p->name, *argv); if (cmd == SIOCCHGTUNNEL && count == 0) { struct ip_tunnel_parm old_p; memset(&old_p, 0, sizeof(old_p)); @@ -324,7 +358,6 @@ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) } } - /* Return value becomes exitcode. It's okay to not return at all */ static int do_add(int cmd, char **argv) { @@ -442,7 +475,7 @@ static void do_tunnels_list(struct ip_tunnel_parm *p) if (fp == NULL) { return; } - + /* skip headers */ fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); diff --git a/release/src/router/busybox/networking/libiproute/libnetlink.c b/release/src/router/busybox/networking/libiproute/libnetlink.c index 01454fbf57..6d51d8deba 100644 --- a/release/src/router/busybox/networking/libiproute/libnetlink.c +++ b/release/src/router/busybox/networking/libiproute/libnetlink.c @@ -341,7 +341,7 @@ int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; - memcpy(RTA_DATA(rta), &data, 4); + move_to_unaligned32(RTA_DATA(rta), data); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } @@ -372,7 +372,7 @@ int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t d subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; - memcpy(RTA_DATA(subrta), &data, 4); + move_to_unaligned32(RTA_DATA(subrta), data); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; return 0; } diff --git a/release/src/router/busybox/networking/libiproute/libnetlink.h b/release/src/router/busybox/networking/libiproute/libnetlink.h index 079153b922..e5fee4dd81 100644 --- a/release/src/router/busybox/networking/libiproute/libnetlink.h +++ b/release/src/router/busybox/networking/libiproute/libnetlink.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ -#ifndef __LIBNETLINK_H__ -#define __LIBNETLINK_H__ 1 +#ifndef LIBNETLINK_H +#define LIBNETLINK_H 1 #include /* We need linux/types.h because older kernels use __u32 etc @@ -8,10 +8,7 @@ #include #include - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct rtnl_handle { @@ -48,8 +45,6 @@ extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, i extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* __LIBNETLINK_H__ */ +#endif diff --git a/release/src/router/busybox/networking/libiproute/ll_addr.c b/release/src/router/busybox/networking/libiproute/ll_addr.c index e732efdb2c..f50e371933 100644 --- a/release/src/router/busybox/networking/libiproute/ll_addr.c +++ b/release/src/router/busybox/networking/libiproute/ll_addr.c @@ -43,6 +43,8 @@ const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int int ll_addr_a2n(unsigned char *lladdr, int len, char *arg) { + int i; + if (strchr(arg, '.')) { inet_prefix pfx; if (get_addr_1(&pfx, arg, AF_INET)) { @@ -54,26 +56,24 @@ int ll_addr_a2n(unsigned char *lladdr, int len, char *arg) } memcpy(lladdr, pfx.data, 4); return 4; - } else { - int i; + } - for (i=0; i 255)) { - bb_error_msg("\"%s\" is invalid lladdr", arg); - return -1; - } - lladdr[i] = temp; - if (!cp) { - break; - } - arg = cp; + for (i = 0; i < len; i++) { + int temp; + char *cp = strchr(arg, ':'); + if (cp) { + *cp = 0; + cp++; + } + if (sscanf(arg, "%x", &temp) != 1 || (temp < 0 || temp > 255)) { + bb_error_msg("\"%s\" is invalid lladdr", arg); + return -1; + } + lladdr[i] = temp; + if (!cp) { + break; } - return i+1; + arg = cp; } + return i+1; } diff --git a/release/src/router/busybox/networking/libiproute/ll_map.c b/release/src/router/busybox/networking/libiproute/ll_map.c index eeae4e252c..2ed7fbbb39 100644 --- a/release/src/router/busybox/networking/libiproute/ll_map.c +++ b/release/src/router/busybox/networking/libiproute/ll_map.c @@ -172,11 +172,11 @@ int xll_name_to_index(const char *const name) #endif sock_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (sock_fd) { + if (sock_fd >= 0) { struct ifreq ifr; int tmp; - strncpy(ifr.ifr_name, name, IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.ifr_name, name); ifr.ifr_ifindex = -1; tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr); close(sock_fd); diff --git a/release/src/router/busybox/networking/libiproute/ll_map.h b/release/src/router/busybox/networking/libiproute/ll_map.h index 6d64ac15a6..3966def100 100644 --- a/release/src/router/busybox/networking/libiproute/ll_map.h +++ b/release/src/router/busybox/networking/libiproute/ll_map.h @@ -1,10 +1,8 @@ /* vi: set sw=4 ts=4: */ -#ifndef __LL_MAP_H__ -#define __LL_MAP_H__ 1 +#ifndef LL_MAP_H +#define LL_MAP_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); int ll_init_map(struct rtnl_handle *rth); @@ -14,8 +12,6 @@ const char *ll_idx_n2a(int idx, char *buf); /* int ll_index_to_type(int idx); */ unsigned ll_index_to_flags(int idx); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* __LL_MAP_H__ */ +#endif diff --git a/release/src/router/busybox/networking/libiproute/ll_proto.c b/release/src/router/busybox/networking/libiproute/ll_proto.c index 8d96374080..a93493538c 100644 --- a/release/src/router/busybox/networking/libiproute/ll_proto.c +++ b/release/src/router/busybox/networking/libiproute/ll_proto.c @@ -20,7 +20,9 @@ #include #endif -#ifdef UNUSED +#if !ENABLE_WERROR +#warning de-bloat +#endif /* Before re-enabling this, please (1) conditionalize exotic protocols * on CONFIG_something, and (2) decouple strings and numbers * (use llproto_ids[] = n,n,n..; and llproto_names[] = "loop\0" "pup\0" ...;) @@ -113,14 +115,15 @@ int ll_proto_a2n(unsigned short *id, char *buf) unsigned i; for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { if (strcasecmp(llproto_names[i].name, buf) == 0) { - *id = htons(llproto_names[i].id); - return 0; + i = llproto_names[i].id; + goto good; } } - if (get_u16(id, buf, 0)) + i = bb_strtou(buf, NULL, 0); + if (errno || i > 0xffff) return -1; - *id = htons(*id); + good: + *id = htons(i); return 0; } -#endif /* UNUSED */ diff --git a/release/src/router/busybox/networking/libiproute/rt_names.h b/release/src/router/busybox/networking/libiproute/rt_names.h index 60baa3f165..a2d4fd1425 100644 --- a/release/src/router/busybox/networking/libiproute/rt_names.h +++ b/release/src/router/busybox/networking/libiproute/rt_names.h @@ -1,10 +1,8 @@ /* vi: set sw=4 ts=4: */ -#ifndef RT_NAMES_H_ -#define RT_NAMES_H_ 1 +#ifndef RT_NAMES_H +#define RT_NAMES_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN extern const char* rtnl_rtprot_n2a(int id, char *buf, int len); extern const char* rtnl_rtscope_n2a(int id, char *buf, int len); @@ -17,20 +15,15 @@ extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg); extern int rtnl_dsfield_a2n(uint32_t *id, char *arg); extern int rtnl_rttable_a2n(uint32_t *id, char *arg); - extern const char* ll_type_n2a(int type, char *buf, int len); extern const char* ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen); extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg); -#ifdef UNUSED extern const char* ll_proto_n2a(unsigned short id, char *buf, int len); extern int ll_proto_a2n(unsigned short *id, char *buf); -#endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/libiproute/rtm_map.h b/release/src/router/busybox/networking/libiproute/rtm_map.h index 02fa77e429..ab1b70e454 100644 --- a/release/src/router/busybox/networking/libiproute/rtm_map.h +++ b/release/src/router/busybox/networking/libiproute/rtm_map.h @@ -1,18 +1,14 @@ /* vi: set sw=4 ts=4: */ -#ifndef __RTM_MAP_H__ -#define __RTM_MAP_H__ 1 +#ifndef RTM_MAP_H +#define RTM_MAP_H 1 -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN const char *rtnl_rtntype_n2a(int id, char *buf, int len); int rtnl_rtntype_a2n(int *id, char *arg); int get_rt_realms(uint32_t *realms, char *arg); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* __RTM_MAP_H__ */ +#endif diff --git a/release/src/router/busybox/networking/libiproute/utils.c b/release/src/router/busybox/networking/libiproute/utils.c index 706710e1f3..c84d018eb7 100644 --- a/release/src/router/busybox/networking/libiproute/utils.c +++ b/release/src/router/busybox/networking/libiproute/utils.c @@ -15,114 +15,56 @@ #include "utils.h" #include "inet_common.h" -int get_integer(int *val, char *arg, int base) -{ - long res; - char *ptr; - - if (!arg || !*arg) - return -1; - res = strtol(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) - return -1; - *val = res; - return 0; -} -//XXX: FIXME: use some libbb function instead -int get_unsigned(unsigned *val, char *arg, int base) -{ - unsigned long res; - char *ptr; - - if (!arg || !*arg) - return -1; - res = strtoul(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > UINT_MAX) - return -1; - *val = res; - return 0; -} - -int get_u32(uint32_t * val, char *arg, int base) +unsigned get_unsigned(char *arg, const char *errmsg) { unsigned long res; char *ptr; - if (!arg || !*arg) - return -1; - res = strtoul(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) - return -1; - *val = res; - return 0; + if (*arg) { + res = strtoul(arg, &ptr, 0); + if (!*ptr && res <= UINT_MAX) { + return res; + } + } + invarg(arg, errmsg); /* does not return */ } -int get_u16(uint16_t * val, char *arg, int base) +uint32_t get_u32(char *arg, const char *errmsg) { unsigned long res; char *ptr; - if (!arg || !*arg) - return -1; - res = strtoul(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > 0xFFFF) - return -1; - *val = res; - return 0; + if (*arg) { + res = strtoul(arg, &ptr, 0); + if (!*ptr && res <= 0xFFFFFFFFUL) { + return res; + } + } + invarg(arg, errmsg); /* does not return */ } -int get_u8(uint8_t * val, char *arg, int base) +uint16_t get_u16(char *arg, const char *errmsg) { unsigned long res; char *ptr; - if (!arg || !*arg) - return -1; - res = strtoul(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > 0xFF) - return -1; - *val = res; - return 0; -} - -int get_s16(int16_t * val, char *arg, int base) -{ - long res; - char *ptr; - - if (!arg || !*arg) - return -1; - res = strtol(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) - return -1; - *val = res; - return 0; -} - -int get_s8(int8_t * val, char *arg, int base) -{ - long res; - char *ptr; - - if (!arg || !*arg) - return -1; - res = strtol(arg, &ptr, base); - if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) - return -1; - *val = res; - return 0; + if (*arg) { + res = strtoul(arg, &ptr, 0); + if (!*ptr && res <= 0xFFFF) { + return res; + } + } + invarg(arg, errmsg); /* does not return */ } -int get_addr_1(inet_prefix * addr, char *name, int family) +int get_addr_1(inet_prefix *addr, char *name, int family) { - char *cp; - unsigned char *ap = (unsigned char *) addr->data; - int i; - memset(addr, 0, sizeof(*addr)); - if (strcmp(name, bb_str_default) == 0 || - strcmp(name, "all") == 0 || strcmp(name, "any") == 0) { + if (strcmp(name, bb_str_default) == 0 + || strcmp(name, "all") == 0 + || strcmp(name, "any") == 0 + ) { addr->family = family; addr->bytelen = (family == AF_INET6 ? 16 : 4); addr->bitlen = -1; @@ -143,32 +85,28 @@ int get_addr_1(inet_prefix * addr, char *name, int family) addr->family = AF_INET; if (family != AF_UNSPEC && family != AF_INET) return -1; + if (inet_pton(AF_INET, name, addr->data) <= 0) + return -1; addr->bytelen = 4; addr->bitlen = -1; - for (cp = name, i = 0; *cp; cp++) { - if (*cp <= '9' && *cp >= '0') { - ap[i] = 10 * ap[i] + (*cp - '0'); - continue; - } - if (*cp == '.' && ++i <= 3) - continue; - return -1; - } return 0; } -int get_prefix_1(inet_prefix * dst, char *arg, int family) +static int get_prefix_1(inet_prefix *dst, char *arg, int family) { int err; - int plen; + unsigned plen; char *slash; memset(dst, 0, sizeof(*dst)); - if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) { + if (strcmp(arg, bb_str_default) == 0 + || strcmp(arg, "all") == 0 + || strcmp(arg, "any") == 0 + ) { dst->family = family; - dst->bytelen = 0; - dst->bitlen = 0; + /*dst->bytelen = 0; - done by memset */ + /*dst->bitlen = 0;*/ return 0; } @@ -177,46 +115,60 @@ int get_prefix_1(inet_prefix * dst, char *arg, int family) *slash = '\0'; err = get_addr_1(dst, arg, family); if (err == 0) { - switch (dst->family) { - case AF_INET6: - dst->bitlen = 128; - break; - default: - case AF_INET: - dst->bitlen = 32; - } + dst->bitlen = (dst->family == AF_INET6) ? 128 : 32; if (slash) { - if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) { + 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; - goto done; + else 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 >= 0 && plen <= dst->bitlen) { + dst->bitlen = plen; + /* dst->flags |= PREFIXLEN_SPECIFIED; */ + } else + err = -1; + } else + err = -1; + } else { + /* plain prefix */ + dst->bitlen = plen; } - dst->bitlen = plen; } } - done: if (slash) *slash = '/'; return err; } -int get_addr(inet_prefix * dst, char *arg, int family) +int get_addr(inet_prefix *dst, char *arg, int family) { if (family == AF_PACKET) { - bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); + bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address"); } if (get_addr_1(dst, arg, family)) { - bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg); + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg); } return 0; } -int get_prefix(inet_prefix * dst, char *arg, int family) +int get_prefix(inet_prefix *dst, char *arg, int family) { if (family == AF_PACKET) { - bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); + 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 inet address is expected rather than \"%s\"", arg); + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); } return 0; } @@ -226,7 +178,7 @@ uint32_t get_addr32(char *name) inet_prefix addr; if (get_addr_1(&addr, name, AF_INET)) { - bb_error_msg_and_die("an IP address is expected rather than \"%s\"", name); + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name); } return addr.data[0]; } @@ -251,11 +203,11 @@ 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(inet_prefix *a, inet_prefix *b, int bits) { uint32_t *a1 = a->data; uint32_t *a2 = b->data; - int words = bits >> 0x05; + int words = bits >> 5; bits &= 0x1f; @@ -279,7 +231,7 @@ int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits) return 0; } -const char *rt_addr_n2a(int af, int UNUSED_PARAM len, +const char *rt_addr_n2a(int af, void *addr, char *buf, int buflen) { switch (af) { @@ -291,10 +243,9 @@ const char *rt_addr_n2a(int af, int UNUSED_PARAM len, } } - +#ifdef RESOLVE_HOSTNAMES const char *format_host(int af, int len, void *addr, char *buf, int buflen) { -#ifdef RESOLVE_HOSTNAMES if (resolve_hosts) { struct hostent *h_ent; @@ -317,6 +268,6 @@ const char *format_host(int af, int len, void *addr, char *buf, int buflen) } } } -#endif - return rt_addr_n2a(af, len, addr, buf, buflen); + return rt_addr_n2a(af, addr, buf, buflen); } +#endif diff --git a/release/src/router/busybox/networking/libiproute/utils.h b/release/src/router/busybox/networking/libiproute/utils.h index 607083af87..ed03e785a9 100644 --- a/release/src/router/busybox/networking/libiproute/utils.h +++ b/release/src/router/busybox/networking/libiproute/utils.h @@ -1,14 +1,12 @@ /* vi: set sw=4 ts=4: */ -#ifndef __UTILS_H__ -#define __UTILS_H__ 1 +#ifndef UTILS_H +#define UTILS_H 1 #include "libnetlink.h" #include "ll_map.h" #include "rtm_map.h" -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN extern family_t preferred_family; extern smallint show_stats; /* UNUSED */ @@ -39,6 +37,8 @@ typedef struct { uint32_t data[4]; } inet_prefix; +#define PREFIXLEN_SPECIFIED 1 + #define DN_MAXADDL 20 #ifndef AF_DECnet #define AF_DECnet 12 @@ -58,23 +58,21 @@ 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 int 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 int get_integer(int *val, char *arg, int base); -extern int get_unsigned(unsigned *val, char *arg, int base); -#define get_byte get_u8 -#define get_ushort get_u16 -#define get_short get_s16 -extern int get_u32(uint32_t *val, char *arg, int base); -extern int get_u16(uint16_t *val, char *arg, int base); -extern int get_s16(int16_t *val, char *arg, int base); -extern int get_u8(uint8_t *val, char *arg, int base); -extern int get_s8(int8_t *val, char *arg, int base); +extern unsigned get_unsigned(char *arg, const char *errmsg); +extern uint32_t get_u32(char *arg, const char *errmsg); +extern uint16_t get_u16(char *arg, const char *errmsg); +extern const char *rt_addr_n2a(int af, void *addr, char *buf, int buflen); +#ifdef RESOLVE_HOSTNAMES extern const char *format_host(int af, int len, void *addr, char *buf, int buflen); -extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen); +#else +#define format_host(af, len, addr, buf, buflen) \ + rt_addr_n2a(af, addr, buf, buflen) +#endif void invarg(const char *, const char *) NORETURN; void duparg(const char *, const char *) NORETURN; @@ -87,8 +85,6 @@ int dnet_pton(int af, const char *src, void *addr); const char *ipx_ntop(int af, const void *addr, char *str, size_t len); int ipx_pton(int af, const char *src, void *addr); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY -#endif /* __UTILS_H__ */ +#endif diff --git a/release/src/router/busybox/networking/nameif.c b/release/src/router/busybox/networking/nameif.c index 75829fac35..fb31fbfff5 100644 --- a/release/src/router/busybox/networking/nameif.c +++ b/release/src/router/busybox/networking/nameif.c @@ -144,7 +144,9 @@ int nameif_main(int argc, char **argv) if (1 & getopt32(argv, "sc:", &fname)) { openlog(applet_name, 0, LOG_LOCAL0); - logmode = LOGMODE_SYSLOG; + /* Why not just "="? I assume logging to stderr + * can't hurt. 2>/dev/null if you don't like it: */ + logmode |= LOGMODE_SYSLOG; } argc -= optind; argv += optind; @@ -177,7 +179,7 @@ int nameif_main(int argc, char **argv) /* Find the current interface name and copy it to ifr.ifr_name */ memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifr.ifr_name, token[0], sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, token[0]); #if ENABLE_FEATURE_NAMEIF_EXTENDED /* Check for driver etc. */ diff --git a/release/src/router/busybox/networking/nc.c b/release/src/router/busybox/networking/nc.c index 1a99f91ccf..fe845f5829 100644 --- a/release/src/router/busybox/networking/nc.c +++ b/release/src/router/busybox/networking/nc.c @@ -131,7 +131,8 @@ int nc_main(int argc, char **argv) if (wsecs) { alarm(0); - signal(SIGALRM, SIG_DFL); + /* Non-ignored siganls revert to SIG_DFL on exec anyway */ + /*signal(SIGALRM, SIG_DFL);*/ } /* -e given? */ diff --git a/release/src/router/busybox/networking/nslookup.c b/release/src/router/busybox/networking/nslookup.c index 183ae152de..26287114ca 100644 --- a/release/src/router/busybox/networking/nslookup.c +++ b/release/src/router/busybox/networking/nslookup.c @@ -15,8 +15,11 @@ #include "libbb.h" /* - * I'm only implementing non-interactive mode; - * I totally forgot nslookup even had an interactive mode. + * I'm only implementing non-interactive mode; + * I totally forgot nslookup even had an interactive mode. + * + * This applet is the only user of res_init(). Without it, + * you may avoid pulling in _res global from libc. */ /* Examples of 'standard' nslookup output @@ -51,7 +54,6 @@ static int print_host(const char *hostname, const char *header) { /* We can't use xhost2sockaddr() - we want to get ALL addresses, * not just one */ - struct addrinfo *result = NULL; int rc; struct addrinfo hint; @@ -101,14 +103,15 @@ static int print_host(const char *hostname, const char *header) static void server_print(void) { char *server; + struct sockaddr *sa; + +#if ENABLE_FEATURE_IPV6 + sa = (struct sockaddr*)_res._u._ext.nsaddrs[0]; + if (!sa) +#endif + sa = (struct sockaddr*)&_res.nsaddr_list[0]; + server = xmalloc_sockaddr2dotted_noport(sa); - server = xmalloc_sockaddr2dotted_noport((struct sockaddr*)&_res.nsaddr_list[0]); - /* I honestly don't know what to do if DNS server has _IPv6 address_. - * Probably it is listed in - * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each) - * but how to find out whether resolver uses - * _res.nsaddr_list[] or _res._u._ext_.nsaddrs[], or both? - * Looks like classic design from hell, BIND-grade. Hard to surpass. */ print_host(server, "Server:"); if (ENABLE_FEATURE_CLEAN_UP) free(server); @@ -116,15 +119,34 @@ static void server_print(void) } /* alter the global _res nameserver structure to use - an explicit dns server instead of what is in /etc/resolv.h */ -static void set_default_dns(char *server) + an explicit dns server instead of what is in /etc/resolv.conf */ +static void set_default_dns(const char *server) { - struct in_addr server_in_addr; + len_and_sockaddr *lsa; - if (inet_pton(AF_INET, server, &server_in_addr) > 0) { + /* NB: this works even with, say, "[::1]:5353"! :) */ + lsa = xhost2sockaddr(server, 53); + + if (lsa->u.sa.sa_family == AF_INET) { _res.nscount = 1; - _res.nsaddr_list[0].sin_addr = server_in_addr; + /* struct copy */ + _res.nsaddr_list[0] = lsa->u.sin; + } +#if ENABLE_FEATURE_IPV6 + /* Hoped libc can cope with IPv4 address there too. + * No such luck, glibc 2.4 segfaults even with IPv6, + * maybe I misunderstand how to make glibc use IPv6 addr? + * (uclibc 0.9.31+ should work) */ + if (lsa->u.sa.sa_family == AF_INET6) { + // glibc neither SEGVs nor sends any dgrams with this + // (strace shows no socket ops): + //_res.nscount = 0; + _res._u._ext.nscount = 1; + /* store a pointer to part of malloc'ed lsa */ + _res._u._ext.nsaddrs[0] = &lsa->u.sin6; + /* must not free(lsa)! */ } +#endif } int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -135,18 +157,17 @@ int nslookup_main(int argc, char **argv) * optional DNS server with which to do the lookup. * More than 3 arguments is an error to follow the pattern of the * standard nslookup */ - - if (argc < 2 || *argv[1] == '-' || argc > 3) + if (!argv[1] || argv[1][0] == '-' || argc > 3) bb_show_usage(); /* initialize DNS structure _res used in printing the default * name server and in the explicit name server option feature. */ res_init(); /* rfc2133 says this enables IPv6 lookups */ - /* (but it also says "may be enabled in /etc/resolv.conf|) */ + /* (but it also says "may be enabled in /etc/resolv.conf") */ /*_res.options |= RES_USE_INET6;*/ - if (argc == 3) + if (argv[2]) set_default_dns(argv[2]); server_print(); diff --git a/release/src/router/busybox/networking/ping.c b/release/src/router/busybox/networking/ping.c index 5def8c3356..f2a612fde4 100644 --- a/release/src/router/busybox/networking/ping.c +++ b/release/src/router/busybox/networking/ping.c @@ -241,10 +241,11 @@ enum { struct globals { int pingsock; int if_index; - char *opt_I; + char *str_I; len_and_sockaddr *source_lsa; unsigned datalen; - unsigned long ntransmitted, nreceived, nrepeats, pingcount; + unsigned pingcount; /* must be int-sized */ + unsigned long ntransmitted, nreceived, nrepeats; uint16_t myid; unsigned tmin, tmax; /* in us */ unsigned long long tsum; /* in us, sum of all times */ @@ -266,7 +267,7 @@ struct globals { #define pingsock (G.pingsock ) #define if_index (G.if_index ) #define source_lsa (G.source_lsa ) -#define opt_I (G.opt_I ) +#define str_I (G.str_I ) #define datalen (G.datalen ) #define ntransmitted (G.ntransmitted) #define nreceived (G.nreceived ) @@ -570,14 +571,15 @@ static void ping4(len_and_sockaddr *lsa) bb_error_msg_and_die("can't set multicast source interface"); xbind(pingsock, &source_lsa->u.sa, source_lsa->len); } - if (opt_I) - setsockopt(pingsock, SOL_SOCKET, SO_BINDTODEVICE, opt_I, strlen(opt_I) + 1); + if (str_I) + setsockopt_bindtodevice(pingsock, str_I); /* enable broadcast pings */ setsockopt_broadcast(pingsock); - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; /* explain why 48k? */ + /* set recv buf (needed if we can get lots of responses: flood ping, + * broadcast ping etc) */ + sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); signal(SIGINT, print_stats_and_exit); @@ -619,8 +621,8 @@ static void ping6(len_and_sockaddr *lsa) /* untested whether "-I addr" really works for IPv6: */ if (source_lsa) xbind(pingsock, &source_lsa->u.sa, source_lsa->len); - if (opt_I) - setsockopt(pingsock, SOL_SOCKET, SO_BINDTODEVICE, opt_I, strlen(opt_I) + 1); + if (str_I) + setsockopt_bindtodevice(pingsock, str_I); #ifdef ICMP6_FILTER { @@ -640,8 +642,9 @@ static void ping6(len_and_sockaddr *lsa) /* enable broadcast pings */ setsockopt_broadcast(pingsock); - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; /* explain why 48k? */ + /* set recv buf (needed if we can get lots of responses: flood ping, + * broadcast ping etc) */ + sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); @@ -717,34 +720,35 @@ int ping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ping_main(int argc UNUSED_PARAM, char **argv) { len_and_sockaddr *lsa; - char *opt_c, *opt_s; - USE_PING6(sa_family_t af = AF_UNSPEC;) + char *str_s; + int opt; INIT_G(); - /* exactly one argument needed; -v and -q don't mix; -w NUM, -W NUM */ - opt_complementary = "=1:q--v:v--q:w+:W+"; - getopt32(argv, OPT_STRING, &opt_c, &opt_s, &deadline, &timeout, &opt_I); - if (option_mask32 & OPT_c) - pingcount = xatoul(opt_c); // -c - if (option_mask32 & OPT_s) - datalen = xatou16(opt_s); // -s - if (option_mask32 & OPT_I) { // -I - if_index = if_nametoindex(opt_I); + /* 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); + if (opt & OPT_s) + datalen = xatou16(str_s); // -s + if (opt & OPT_I) { // -I + if_index = if_nametoindex(str_I); if (!if_index) { /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */ - source_lsa = xdotted2sockaddr(opt_I, 0); - opt_I = NULL; /* don't try to bind to device later */ + source_lsa = xdotted2sockaddr(str_I, 0); + str_I = NULL; /* don't try to bind to device later */ } } myid = (uint16_t) getpid(); hostname = argv[optind]; #if ENABLE_PING6 - if (option_mask32 & OPT_IPV4) - af = AF_INET; - if (option_mask32 & OPT_IPV6) - af = AF_INET6; - lsa = xhost_and_af2sockaddr(hostname, 0, af); + { + sa_family_t af = AF_UNSPEC; + if (opt & OPT_IPV4) + af = AF_INET; + if (opt & OPT_IPV6) + af = AF_INET6; + lsa = xhost_and_af2sockaddr(hostname, 0, af); + } #else lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); #endif @@ -763,10 +767,11 @@ int ping_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_PING6 int ping6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int ping6_main(int argc, char **argv) +int ping6_main(int argc UNUSED_PARAM, char **argv) { argv[0] = (char*)"-6"; - return ping_main(argc + 1, argv - 1); + return ping_main(0 /* argc+1 - but it's unused anyway */, + argv - 1); } #endif diff --git a/release/src/router/busybox/networking/route.c b/release/src/router/busybox/networking/route.c index 2bc2f9210c..5d2540802c 100644 --- a/release/src/router/busybox/networking/route.c +++ b/release/src/router/busybox/networking/route.c @@ -302,7 +302,7 @@ static void INET_setroute(int action, char **args) /* sanity checks.. */ if (mask_in_addr(rt)) { - unsigned long mask = mask_in_addr(rt); + uint32_t mask = mask_in_addr(rt); mask = ~ntohl(mask); if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { @@ -313,7 +313,7 @@ static void INET_setroute(int action, char **args) bb_error_msg_and_die("bogus netmask %s", netmask); } mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; - if (mask & ~mask_in_addr(rt)) { + if (mask & ~(uint32_t)mask_in_addr(rt)) { bb_error_msg_and_die("netmask and route address conflict"); } } @@ -423,7 +423,7 @@ static void INET6_setroute(int action, char **args) if (devname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, devname); xioctl(skfd, SIOGIFINDEX, &ifr); rt.rtmsg_ifindex = ifr.ifr_ifindex; } diff --git a/release/src/router/busybox/networking/sendmail.c b/release/src/router/busybox/networking/sendmail.c deleted file mode 100644 index c605d7c1b2..0000000000 --- a/release/src/router/busybox/networking/sendmail.c +++ /dev/null @@ -1,675 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * bare bones sendmail/fetchmail - * - * Copyright (C) 2008 by Vladimir Dronnikov - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ -#include "libbb.h" - -#define INITIAL_STDIN_FILENO 3 - -static void uuencode(char *fname, const char *text) -{ - enum { - SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ - DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), - }; - -#define src_buf text - int fd; -#define len fd - char dst_buf[DST_BUF_SIZE + 1]; - - if (fname) { - fd = INITIAL_STDIN_FILENO; - if (NOT_LONE_DASH(fname)) - fd = xopen(fname, O_RDONLY); - src_buf = bb_common_bufsiz1; - // N.B. strlen(NULL) segfaults! - } else if (text) { - // though we do not call uuencode(NULL, NULL) explicitly - // still we do not want to break things suddenly - len = strlen(text); - } else - return; - - fflush(stdout); // sync stdio and unistd output - while (1) { - size_t size; - if (fname) { - size = full_read(fd, (char *)src_buf, SRC_BUF_SIZE); - if ((ssize_t)size < 0) - bb_perror_msg_and_die(bb_msg_read_error); - } else { - size = len; - if (len > SRC_BUF_SIZE) - size = SRC_BUF_SIZE; - } - if (!size) - break; - // encode the buffer we just read in - bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); - if (fname) { - xwrite(STDOUT_FILENO, "\r\n", 2); - } else { - src_buf += size; - len -= size; - } - xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3)); - } - if (fname) - close(fd); -#undef src_buf -#undef len -} - -struct globals { - pid_t helper_pid; - unsigned timeout; - // arguments for SSL connection helper - const char *xargs[9]; - // arguments for postprocess helper - const char *fargs[3]; -}; -#define G (*ptr_to_globals) -#define helper_pid (G.helper_pid) -#define timeout (G.timeout ) -#define xargs (G.xargs ) -#define fargs (G.fargs ) -#define INIT_G() do { \ - SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ - xargs[0] = "openssl"; \ - xargs[1] = "s_client"; \ - xargs[2] = "-quiet"; \ - xargs[3] = "-connect"; \ - /*xargs[4] = "localhost";*/ \ - xargs[5] = "-tls1"; \ - xargs[6] = "-starttls"; \ - xargs[7] = "smtp"; \ - fargs[0] = "utf-8"; \ -} while (0) - -#define opt_connect (xargs[4]) -#define opt_after_connect (xargs[5]) -#define opt_charset (fargs[0]) -#define opt_subject (fargs[1]) - -static void kill_helper(void) -{ - // TODO!!!: is there more elegant way to terminate child on program failure? - if (helper_pid > 0) - kill(helper_pid, SIGTERM); -} - -// generic signal handler -static void signal_handler(int signo) -{ -#define err signo - - if (SIGALRM == signo) { - kill_helper(); - bb_error_msg_and_die("timed out"); - } - - // SIGCHLD. reap zombies - if (wait_any_nohang(&err) > 0) - if (WIFEXITED(err) && WEXITSTATUS(err)) - bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err)); -#undef err -} - -static void launch_helper(const char **argv) -{ - // setup vanilla unidirectional pipes interchange - int idx; - int pipes[4]; - - xpipe(pipes); - xpipe(pipes+2); - helper_pid = vfork(); - if (helper_pid < 0) - bb_perror_msg_and_die("vfork"); - idx = (!helper_pid) * 2; - xdup2(pipes[idx], STDIN_FILENO); - xdup2(pipes[3-idx], STDOUT_FILENO); - if (ENABLE_FEATURE_CLEAN_UP) - for (int i = 4; --i >= 0; ) - if (pipes[i] > STDOUT_FILENO) - close(pipes[i]); - if (!helper_pid) { - // child: try to execute connection helper - BB_EXECVP(*argv, (char **)argv); - _exit(127); - } - // parent: check whether child is alive - bb_signals(0 - + (1 << SIGCHLD) - + (1 << SIGALRM) - , signal_handler); - signal_handler(SIGCHLD); - // child seems OK -> parent goes on -} - -static const char *command(const char *fmt, const char *param) -{ - const char *msg = fmt; - alarm(timeout); - if (msg) { - msg = xasprintf(fmt, param); - printf("%s\r\n", msg); - } - fflush(stdout); - return msg; -} - -static int smtp_checkp(const char *fmt, const char *param, int code) -{ - char *answer; - const char *msg = command(fmt, param); - // read stdin - // if the string has a form \d\d\d- -- read next string. E.g. EHLO response - // parse first bytes to a number - // if code = -1 then just return this number - // if code != -1 then checks whether the number equals the code - // if not equal -> die saying msg - while ((answer = xmalloc_fgetline(stdin)) != NULL) - if (strlen(answer) <= 3 || '-' != answer[3]) - break; - if (answer) { - int n = atoi(answer); - alarm(0); - if (ENABLE_FEATURE_CLEAN_UP) { - free(answer); - } - if (-1 == code || n == code) { - return n; - } - } - kill_helper(); - bb_error_msg_and_die("%s failed", msg); -} - -static inline int smtp_check(const char *fmt, int code) -{ - return smtp_checkp(fmt, NULL, code); -} - -// strip argument of bad chars -static char *sane(char *str) -{ - char *s = str; - char *p = s; - while (*s) { - if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { - *p++ = *s; - } - s++; - } - *p = '\0'; - return str; -} - -#if ENABLE_FETCHMAIL -static void pop3_checkr(const char *fmt, const char *param, char **ret) -{ - const char *msg = command(fmt, param); - char *answer = xmalloc_fgetline(stdin); - if (answer && '+' == *answer) { - alarm(0); - if (ret) - *ret = answer+4; // skip "+OK " - else if (ENABLE_FEATURE_CLEAN_UP) - free(answer); - return; - } - kill_helper(); - bb_error_msg_and_die("%s failed", msg); -} - -static inline void pop3_check(const char *fmt, const char *param) -{ - pop3_checkr(fmt, param, NULL); -} - -static void pop3_message(const char *filename) -{ - int fd; - char *answer; - // create and open file filename - // read stdin, copy to created file - fd = xopen(filename, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL); - while ((answer = xmalloc_fgets_str(stdin, "\r\n")) != NULL) { - char *s = answer; - if ('.' == *answer) { - if ('.' == answer[1]) - s++; - else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) - break; - } - xwrite(fd, s, strlen(s)); - free(answer); - } - close(fd); -} -#endif - -// NB: parse_url can modify url[] (despite const), but only if '@' is there -static const char *parse_url(const char *url, const char **user, const char **pass) -{ - // parse [user[:pass]@]host - // return host - char *s = strchr(url, '@'); - *user = *pass = NULL; - if (s) { - *s++ = '\0'; - *user = url; - url = s; - s = strchr(*user, ':'); - if (s) { - *s++ = '\0'; - *pass = s; - } - } - return url; -} - -static void rcptto(const char *s) -{ - smtp_checkp("RCPT TO:<%s>", s, 250); -} - -int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int sendgetmail_main(int argc UNUSED_PARAM, char **argv) -{ - llist_t *opt_attachments = NULL; - char *opt_from; - const char *opt_user; - const char *opt_pass; - enum { - OPT_w = 1 << 0, // network timeout - OPT_H = 1 << 1, // [user:password@]server[:port] - OPT_S = 1 << 2, // connect using openssl s_client helper - - OPTS_t = 1 << 3, // sendmail: read addresses from body - OPTF_t = 1 << 3, // fetchmail: use "TOP" not "RETR" - - OPTS_s = 1 << 4, // sendmail: subject - OPTF_z = 1 << 4, // fetchmail: delete from server - - OPTS_c = 1 << 5, // sendmail: assumed charset - OPTS_a = 1 << 6, // sendmail: attachment(s) - OPTS_i = 1 << 7, // sendmail: ignore lone dots in message body (implied) - - OPTS_N = 1 << 8, // sendmail: request notification - OPTS_f = 1 << 9, // sendmail: sender address - }; - const char *options; - int opts; - - // init global variables - INIT_G(); - - // parse options, different option sets for sendmail and fetchmail - // N.B. opt_after_connect hereafter is NULL if we are called as fetchmail - // and is NOT NULL if we are called as sendmail - if (!ENABLE_FETCHMAIL || 's' == applet_name[0]) { - // SENDMAIL - // save initial stdin since body is piped! - xdup2(STDIN_FILENO, INITIAL_STDIN_FILENO); - opt_complementary = "w+:a::"; - options = "w:H:St" "s:c:a:iN:f:"; - // body is pseudo attachment read from stdin - llist_add_to_end(&opt_attachments, (char *)"-"); - } else { - // FETCHMAIL - opt_after_connect = NULL; - opt_complementary = "-1:w+"; - options = "w:H:St" "z"; - } - opts = getopt32(argv, options, - &timeout /* -w */, &opt_connect /* -H */, - &opt_subject, &opt_charset, &opt_attachments, NULL, &opt_from - ); - //argc -= optind; - argv += optind; - - // connect to server - // host[:port] not specified ? -> use $HOSTNAME. no $HOSTNAME ? -> use localhost - if (!(opts & OPT_H)) { - opt_connect = getenv("HOSTNAME"); - if (!opt_connect) - opt_connect = "127.0.0.1"; - } - // fetch username and password, if any - // NB: parse_url modifies opt_connect[] ONLY if '@' is there. - // Thus "127.0.0.1" won't be modified, an is ok that it is RO. - opt_connect = parse_url(opt_connect, &opt_user, &opt_pass); -// bb_error_msg("H[%s] U[%s] P[%s]", opt_connect, opt_user, opt_pass); - - // username must be defined! - if (!opt_user) { - // N.B. IMHO getenv("USER") can be way easily spoofed! - opt_user = bb_getpwuid(NULL, -1, getuid()); - } - - // SSL ordered? -> - if (opts & OPT_S) { - // ... use openssl helper - launch_helper(xargs); - // no SSL ordered? -> - } else { - // ... make plain connect - int fd = create_and_connect_stream_or_die(opt_connect, 25); - // make ourselves a simple IO filter - // from now we know nothing about network :) - xmove_fd(fd, STDIN_FILENO); - xdup2(STDIN_FILENO, STDOUT_FILENO); - } - - // are we sendmail? - if (!ENABLE_FETCHMAIL || opt_after_connect) -/*************************************************** - * SENDMAIL - ***************************************************/ - { - int code; - char *boundary; - const char *fmt; - const char *p; - char *q; - llist_t *l; - llist_t *headers = NULL; - - // got no sender address? -> use username as a resort - if (!(opts & OPTS_f)) { - char *domain = safe_getdomainname(); - opt_from = xasprintf("%s@%s", opt_user, domain); - if (ENABLE_FEATURE_CLEAN_UP) - free(domain); - } - - // introduce to server - - // we didn't use SSL helper? -> - if (!(opts & OPT_S)) { - // ... wait for initial server OK - smtp_check(NULL, 220); - } - - // we should start with modern EHLO - if (250 != smtp_checkp("EHLO %s", sane(opt_from), -1)) { - smtp_checkp("HELO %s", opt_from, 250); - } - - // set sender - // NOTE: if password has not been specified - // then no authentication is possible - code = (opt_pass ? -1 : 250); - // first try softly without authentication - while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) { - // MAIL FROM failed -> authentication needed - if (334 == smtp_check("AUTH LOGIN", -1)) { - uuencode(NULL, opt_user); // opt_user != NULL - smtp_check("", 334); - uuencode(NULL, opt_pass); - smtp_check("", 235); - } - // authenticated OK? -> retry to set sender - // but this time die on failure! - code = 250; - } - - // recipients specified as arguments - while (*argv) { - // loose test on email address validity - if (strchr(sane(*argv), '@')) { - rcptto(sane(*argv)); - llist_add_to_end(&headers, xasprintf("To: %s", *argv)); - } - argv++; - } - - // if -t specified or no recipients specified -> enter all-included mode - // i.e. scan stdin for To:, Cc:, Bcc:, and Subject: lines ... - // ... and then use the rest of stdin as message body - // N.B. subject read from body has priority - // over that specified on command line. - // recipients are merged - // N.B. other headers are collected and will be dumped verbatim - if (opts & OPTS_t || !headers) { - // fetch recipients and (optionally) subject - char *s; - while ((s = xmalloc_reads(INITIAL_STDIN_FILENO, NULL, NULL)) != NULL) { - if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Cc: ", s, 4)) { - rcptto(sane(s+4)); - llist_add_to_end(&headers, s); - } else if (0 == strncasecmp("Bcc: ", s, 5)) { - rcptto(sane(s+5)); - if (ENABLE_FEATURE_CLEAN_UP) - free(s); - // N.B. Bcc vanishes from headers! -/* } else if (0 == strncmp("From: ", s, 6)) { - opt_from = s+6; - opts |= OPTS_f; -*/ } else if (0 == strncmp("Subject: ", s, 9)) { - opt_subject = s+9; - opts |= OPTS_s; - } else if (s[0]) { - // misc header - llist_add_to_end(&headers, s); - } else { - free(s); - break; // empty line - } - } - } - - // enter "put message" mode - smtp_check("DATA", 354); - - // put headers we could have preread with -t - for (l = headers; l; l = l->link) { - printf("%s\r\n", l->data); - if (ENABLE_FEATURE_CLEAN_UP) - free(l->data); - } - - // put address header - printf("From: %s\r\n", opt_from); - - // put encoded subject - if (opts & OPTS_c) - sane((char *)opt_charset); - if (opts & OPTS_s) { - printf("Subject: =?%s?B?", opt_charset); - uuencode(NULL, opt_subject); - printf("?=\r\n"); - } - - // put notification - if (opts & OPTS_N) - printf("Disposition-Notification-To: %s\r\n", opt_from); - - // make a random string -- it will delimit message parts - srand(monotonic_us()); - boundary = xasprintf("%d-%d-%d", rand(), rand(), rand()); - - // put common headers and body start - printf( - "Message-ID: <%s>\r\n" - "Mime-Version: 1.0\r\n" - "%smultipart/mixed; boundary=\"%s\"\r\n" - , boundary - , "Content-Type: " - , boundary - ); - - // put body + attachment(s) - // N.B. all these weird things just to be tiny - // by reusing string patterns! - fmt = - "\r\n--%s\r\n" - "%stext/plain; charset=%s\r\n" - "%s%s\r\n" - "%s" - ; - p = opt_charset; - q = (char *)""; - l = opt_attachments; - while (l) { - printf( - fmt - , boundary - , "Content-Type: " - , p - , "Content-Disposition: inline" - , q - , "Content-Transfer-Encoding: base64\r\n" - ); - p = ""; - fmt = - "\r\n--%s\r\n" - "%sapplication/octet-stream%s\r\n" - "%s; filename=\"%s\"\r\n" - "%s" - ; - uuencode(l->data, NULL); - l = l->link; - if (l) - q = bb_get_last_path_component_strip(l->data); - } - - // put message terminator - printf("\r\n--%s--\r\n" "\r\n", boundary); - - // leave "put message" mode - smtp_check(".", 250); - // ... and say goodbye - smtp_check("QUIT", 221); - } -#if ENABLE_FETCHMAIL -/*************************************************** - * FETCHMAIL - ***************************************************/ - else { - char *buf; - unsigned nmsg; - char *hostname; - pid_t pid; - - // cache fetch command: - // TOP will return only the headers - // RETR will dump the whole message - const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u"; - - // goto maildir - xchdir(*argv++); - - // cache postprocess program - *fargs = *argv; - - // authenticate - - // password is mandatory - if (!opt_pass) { - bb_error_msg_and_die("no password"); - } - - // get server greeting - pop3_checkr(NULL, NULL, &buf); - - // server supports APOP? - if ('<' == *buf) { - md5_ctx_t md5; - // yes! compose - char *s = strchr(buf, '>'); - if (s) - strcpy(s+1, opt_pass); - s = buf; - // get md5 sum of - md5_begin(&md5); - md5_hash(s, strlen(s), &md5); - md5_end(s, &md5); - // NOTE: md5 struct contains enough space - // so we reuse md5 space instead of xzalloc(16*2+1) -#define md5_hex ((uint8_t *)&md5) -// uint8_t *md5_hex = (uint8_t *)&md5; - *bin2hex((char *)md5_hex, s, 16) = '\0'; - // APOP - s = xasprintf("%s %s", opt_user, md5_hex); -#undef md5_hex - pop3_check("APOP %s", s); - if (ENABLE_FEATURE_CLEAN_UP) { - free(s); - free(buf-4); // buf is "+OK " away from malloc'ed string - } - // server ignores APOP -> use simple text authentication - } else { - // USER - pop3_check("USER %s", opt_user); - // PASS - pop3_check("PASS %s", opt_pass); - } - - // get mailbox statistics - pop3_checkr("STAT", NULL, &buf); - - // prepare message filename suffix - hostname = safe_gethostname(); - pid = getpid(); - - // get messages counter - // NOTE: we don't use xatou(buf) since buf is "nmsg nbytes" - // we only need nmsg and atoi is just exactly what we need - // if atoi fails to convert buf into number it returns 0 - // in this case the following loop simply will not be executed - nmsg = atoi(buf); - if (ENABLE_FEATURE_CLEAN_UP) - free(buf-4); // buf is "+OK " away from malloc'ed string - - // loop through messages - for (; nmsg; nmsg--) { - - // generate unique filename - char *filename = xasprintf("tmp/%llu.%u.%s", - monotonic_us(), (unsigned)pid, hostname); - char *target; - int rc; - - // retrieve message in ./tmp/ - pop3_check(retr, (const char *)(ptrdiff_t)nmsg); - pop3_message(filename); - // delete message from server - if (opts & OPTF_z) - pop3_check("DELE %u", (const char*)(ptrdiff_t)nmsg); - - // run postprocessing program - if (*fargs) { - fargs[1] = filename; - rc = wait4pid(spawn((char **)fargs)); - if (99 == rc) - break; - if (1 == rc) - goto skip; - } - - // atomically move message to ./new/ - target = xstrdup(filename); - strncpy(target, "new", 3); - // ... or just stop receiving on error - if (rename_or_warn(filename, target)) - break; - free(target); - skip: - free(filename); - } - - // Bye - pop3_check("QUIT", NULL); - } -#endif // ENABLE_FETCHMAIL - - return 0; -} diff --git a/release/src/router/busybox/networking/slattach.c b/release/src/router/busybox/networking/slattach.c index 52f7f3cffa..d3212bb40d 100644 --- a/release/src/router/busybox/networking/slattach.c +++ b/release/src/router/busybox/networking/slattach.c @@ -206,6 +206,8 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) state.c_cflag = CS8 | HUPCL | CREAD | ((opt & OPT_L_local) ? CLOCAL : 0) | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); + cfsetispeed(&state, cfgetispeed(&saved_state)); + cfsetospeed(&state, cfgetospeed(&saved_state)); } if (opt & OPT_s_baud) { diff --git a/release/src/router/busybox/networking/tc.c b/release/src/router/busybox/networking/tc.c new file mode 100644 index 0000000000..03f57f637c --- /dev/null +++ b/release/src/router/busybox/networking/tc.c @@ -0,0 +1,543 @@ +/* vi: set sw=4 ts=4: */ +/* + * tc.c "tc" utility frontend. + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * + * Authors: Alexey Kuznetsov, + * + * Bernhard Reutner-Fischer adjusted for busybox + */ + +#include "libbb.h" + +#include "libiproute/utils.h" +#include "libiproute/ip_common.h" +#include "libiproute/rt_names.h" +#include /* for the TC_H_* macros */ + +#define parse_rtattr_nested(tb, max, rta) \ + (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) + +/* nullifies tb on error */ +#define __parse_rtattr_nested_compat(tb, max, rta, len) \ + ({if ((RTA_PAYLOAD(rta) >= len) && \ + (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr))) { \ + rta = RTA_DATA(rta) + RTA_ALIGN(len); \ + parse_rtattr_nested(tb, max, rta); \ + } else \ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \ + }) + +#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ + ({data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ + __parse_rtattr_nested_compat(tb, max, rta, len); }) + +#define show_details (0) /* not implemented. Does anyone need it? */ +#define use_iec (0) /* not currently documented in the upstream manpage */ + + +struct globals { + int filter_ifindex; + __u32 filter_qdisc; + __u32 filter_parent; + __u32 filter_prio; + __u32 filter_proto; +}; + +#define G (*(struct globals*)&bb_common_bufsiz1) +#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) + +/* Allocates a buffer containing the name of a class id. + * The caller must free the returned memory. */ +static char* print_tc_classid(uint32_t cid) +{ +#if 0 /* IMPOSSIBLE */ + if (cid == TC_H_ROOT) + return xasprintf("root"); + else +#endif + if (cid == TC_H_UNSPEC) + return xasprintf("none"); + else if (TC_H_MAJ(cid) == 0) + return xasprintf(":%x", TC_H_MIN(cid)); + else if (TC_H_MIN(cid) == 0) + return xasprintf("%x:", TC_H_MAJ(cid)>>16); + else + return xasprintf("%x:%x", TC_H_MAJ(cid)>>16, TC_H_MIN(cid)); +} + +/* Get a qdisc handle. Return 0 on success, !0 otherwise. */ +static int get_qdisc_handle(__u32 *h, const char *str) { + __u32 maj; + char *p; + + maj = TC_H_UNSPEC; + if (!strcmp(str, "none")) + goto ok; + maj = strtoul(str, &p, 16); + if (p == str) + return 1; + maj <<= 16; + if (*p != ':' && *p!=0) + return 1; + ok: + *h = maj; + return 0; +} + +/* Get class ID. Return 0 on success, !0 otherwise. */ +static int get_tc_classid(__u32 *h, const char *str) { + __u32 maj, min; + char *p; + + maj = TC_H_ROOT; + if (!strcmp(str, "root")) + goto ok; + maj = TC_H_UNSPEC; + if (!strcmp(str, "none")) + goto ok; + maj = strtoul(str, &p, 16); + if (p == str) { + if (*p != ':') + return 1; + maj = 0; + } + if (*p == ':') { + if (maj >= (1<<16)) + return 1; + maj <<= 16; + str = p + 1; + min = strtoul(str, &p, 16); + if (*p != 0 || min >= (1<<16)) + return 1; + maj |= min; + } else if (*p != 0) + return 1; + ok: + *h = maj; + return 0; +} + +static void print_rate(char *buf, int len, uint32_t rate) +{ + double tmp = (double)rate*8; + + if (use_iec) { + if (tmp >= 1000.0*1024.0*1024.0) + snprintf(buf, len, "%.0fMibit", tmp/1024.0*1024.0); + else if (tmp >= 1000.0*1024) + snprintf(buf, len, "%.0fKibit", tmp/1024); + else + snprintf(buf, len, "%.0fbit", tmp); + } else { + if (tmp >= 1000.0*1000000.0) + snprintf(buf, len, "%.0fMbit", tmp/1000000.0); + else if (tmp >= 1000.0 * 1000.0) + snprintf(buf, len, "%.0fKbit", tmp/1000.0); + else + snprintf(buf, len, "%.0fbit", tmp); + } +} + +/* This is "pfifo_fast". */ +static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) +{ + return 0; +} +static int prio_print_opt(struct rtattr *opt) +{ + int i; + struct tc_prio_qopt *qopt; + struct rtattr *tb[TCA_PRIO_MAX+1]; + + if (opt == NULL) + return 0; + parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt)); + if (tb == NULL) + return 0; + printf("bands %u priomap ", qopt->bands); + for (i=0; i<=TC_PRIO_MAX; i++) + printf(" %d", qopt->priomap[i]); + + if (tb[TCA_PRIO_MQ]) + printf(" multiqueue: o%s ", + *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "n" : "ff"); + + return 0; +} + +/* Class Based Queue */ +static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) +{ + return 0; +} +static int cbq_print_opt(struct rtattr *opt) +{ + struct rtattr *tb[TCA_CBQ_MAX+1]; + struct tc_ratespec *r = NULL; + struct tc_cbq_lssopt *lss = NULL; + struct tc_cbq_wrropt *wrr = NULL; + struct tc_cbq_fopt *fopt = NULL; + struct tc_cbq_ovl *ovl = NULL; + const char * const error = "CBQ: too short %s opt"; + RESERVE_CONFIG_BUFFER(buf, 64); + + if (opt == NULL) + goto done; + parse_rtattr_nested(tb, TCA_CBQ_MAX, opt); + + if (tb[TCA_CBQ_RATE]) { + if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r)) + bb_error_msg(error, "rate"); + else + r = RTA_DATA(tb[TCA_CBQ_RATE]); + } + if (tb[TCA_CBQ_LSSOPT]) { + if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss)) + bb_error_msg(error, "lss"); + else + lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]); + } + if (tb[TCA_CBQ_WRROPT]) { + if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr)) + bb_error_msg(error, "wrr"); + else + wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]); + } + if (tb[TCA_CBQ_FOPT]) { + if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt)) + bb_error_msg(error, "fopt"); + else + fopt = RTA_DATA(tb[TCA_CBQ_FOPT]); + } + if (tb[TCA_CBQ_OVL_STRATEGY]) { + if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl)) + bb_error_msg("CBQ: too short overlimit strategy %u/%u", + (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), + (unsigned) sizeof(*ovl)); + else + ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]); + } + + if (r) { + print_rate(buf, sizeof(buf), r->rate); + printf("rate %s ", buf); + if (show_details) { + printf("cell %ub ", 1<cell_log); + if (r->mpu) + printf("mpu %ub ", r->mpu); + if (r->overhead) + printf("overhead %ub ", r->overhead); + } + } + if (lss && lss->flags) { + bool comma = false; + bb_putchar('('); + if (lss->flags&TCF_CBQ_LSS_BOUNDED) { + printf("bounded"); + comma = true; + } + if (lss->flags&TCF_CBQ_LSS_ISOLATED) { + if (comma) + bb_putchar(','); + printf("isolated"); + } + printf(") "); + } + if (wrr) { + if (wrr->priority != TC_CBQ_MAXPRIO) + printf("prio %u", wrr->priority); + else + printf("prio no-transmit"); + if (show_details) { + printf("/%u ", wrr->cpriority); + if (wrr->weight != 1) { + print_rate(buf, sizeof(buf), wrr->weight); + printf("weight %s ", buf); + } + if (wrr->allot) + printf("allot %ub ", wrr->allot); + } + } + done: + RELEASE_CONFIG_BUFFER(buf); + return 0; +} + +static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM, + struct nlmsghdr *hdr, void *arg UNUSED_PARAM) +{ + struct tcmsg *msg = NLMSG_DATA(hdr); + int len = hdr->nlmsg_len; + struct rtattr * tb[TCA_MAX+1]; + char *name; + + if (hdr->nlmsg_type != RTM_NEWQDISC && hdr->nlmsg_type != RTM_DELQDISC) { + /* bb_error_msg("Not a qdisc"); */ + return 0; /* ??? mimic upstream; should perhaps return -1 */ + } + len -= NLMSG_LENGTH(sizeof(*msg)); + if (len < 0) { + /* bb_error_msg("Wrong len %d", len); */ + return -1; + } + /* not the desired interface? */ + if (filter_ifindex && filter_ifindex != msg->tcm_ifindex) + return 0; + memset (tb, 0, sizeof(tb)); + parse_rtattr(tb, TCA_MAX, TCA_RTA(msg), len); + if (tb[TCA_KIND] == NULL) { + /* bb_error_msg("%s: NULL kind", "qdisc"); */ + return -1; + } + if (hdr->nlmsg_type == RTM_DELQDISC) + printf("deleted "); + name = (char*)RTA_DATA(tb[TCA_KIND]); + printf("qdisc %s %x: ", name, msg->tcm_handle>>16); + if (filter_ifindex == 0) + printf("dev %s ", ll_index_to_name(msg->tcm_ifindex)); + if (msg->tcm_parent == TC_H_ROOT) + printf("root "); + else if (msg->tcm_parent) { + char *classid = print_tc_classid(msg->tcm_parent); + printf("parent %s ", classid); + if (ENABLE_FEATURE_CLEAN_UP) + free(classid); + } + if (msg->tcm_info != 1) + printf("refcnt %d ", msg->tcm_info); + if (tb[TCA_OPTIONS]) { + static const char _q_[] ALIGN1 = "pfifo_fast\0""cbq\0"; + int qqq = index_in_strings(_q_, name); + if (qqq == 0) { /* pfifo_fast aka prio */ + prio_print_opt(tb[TCA_OPTIONS]); + } else if (qqq == 1) { /* class based queueing */ + cbq_print_opt(tb[TCA_OPTIONS]); + } else + bb_error_msg("unknown %s", name); + } + bb_putchar('\n'); + return 0; +} + +static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, + struct nlmsghdr *hdr, void *arg UNUSED_PARAM) +{ + struct tcmsg *msg = NLMSG_DATA(hdr); + int len = hdr->nlmsg_len; + struct rtattr * tb[TCA_MAX+1]; + char *name, *classid; + + /*XXX Eventually factor out common code */ + + if (hdr->nlmsg_type != RTM_NEWTCLASS && hdr->nlmsg_type != RTM_DELTCLASS) { + /* bb_error_msg("Not a class"); */ + return 0; /* ??? mimic upstream; should perhaps return -1 */ + } + len -= NLMSG_LENGTH(sizeof(*msg)); + if (len < 0) { + /* bb_error_msg("Wrong len %d", len); */ + return -1; + } + /* not the desired interface? */ + if (filter_qdisc && TC_H_MAJ(msg->tcm_handle^filter_qdisc)) + return 0; + memset (tb, 0, sizeof(tb)); + parse_rtattr(tb, TCA_MAX, TCA_RTA(msg), len); + if (tb[TCA_KIND] == NULL) { + /* bb_error_msg("%s: NULL kind", "class"); */ + return -1; + } + if (hdr->nlmsg_type == RTM_DELTCLASS) + printf("deleted "); + + name = (char*)RTA_DATA(tb[TCA_KIND]); + classid = !msg->tcm_handle ? NULL : print_tc_classid( + filter_qdisc ? TC_H_MIN(msg->tcm_parent) : msg->tcm_parent); + printf ("class %s %s", name, classid); + if (ENABLE_FEATURE_CLEAN_UP) + free(classid); + + if (filter_ifindex == 0) + printf("dev %s ", ll_index_to_name(msg->tcm_ifindex)); + if (msg->tcm_parent == TC_H_ROOT) + printf("root "); + else if (msg->tcm_parent) { + classid = print_tc_classid(filter_qdisc ? + TC_H_MIN(msg->tcm_parent) : msg->tcm_parent); + printf("parent %s ", classid); + if (ENABLE_FEATURE_CLEAN_UP) + free(classid); + } + if (msg->tcm_info) + printf("leaf %x ", msg->tcm_info >> 16); + /* Do that get_qdisc_kind(RTA_DATA(tb[TCA_KIND])). */ + if (tb[TCA_OPTIONS]) { + static const char _q_[] ALIGN1 = "pfifo_fast\0""cbq\0"; + int qqq = index_in_strings(_q_, name); + if (qqq == 0) { /* pfifo_fast aka prio */ + /* nothing. */ /*prio_print_opt(tb[TCA_OPTIONS]);*/ + } else if (qqq == 1) { /* class based queueing */ + /* cbq_print_copt() is identical to cbq_print_opt(). */ + cbq_print_opt(tb[TCA_OPTIONS]); + } else + bb_error_msg("unknown %s", name); + } + bb_putchar('\n'); + + return 0; +} + +static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, + struct nlmsghdr *hdr, void *arg UNUSED_PARAM) +{ + struct tcmsg *msg = NLMSG_DATA(hdr); + int len = hdr->nlmsg_len; + struct rtattr * tb[TCA_MAX+1]; + return 0; +} + +int tc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tc_main(int argc UNUSED_PARAM, char **argv) +{ + static const char objects[] ALIGN1 = + "qdisc\0""class\0""filter\0" + ; + enum { OBJ_qdisc = 0, OBJ_class, OBJ_filter }; + static const char commands[] ALIGN1 = + "add\0""delete\0""change\0" + "link\0" /* only qdisc */ + "replace\0" + "show\0""list\0" + ; + static const char args[] ALIGN1 = + "dev\0" /* qdisc, class, filter */ + "root\0" /* class, filter */ + "parent\0" /* class, filter */ + "qdisc\0" /* class */ + "handle\0" /* change: qdisc, class(classid) list: filter */ + "classid\0" /* change: for class use "handle" */ + "preference\0""priority\0""protocol\0" /* filter */ + ; + enum { CMD_add = 0, CMD_del, CMD_change, CMD_link, CMD_replace, CMD_show }; + enum { ARG_dev = 0, ARG_root, ARG_parent, ARG_qdisc, + ARG_handle, ARG_classid, ARG_pref, ARG_prio, ARG_proto}; + struct rtnl_handle rth; + struct tcmsg msg; + int ret, obj, cmd, arg; + char *dev = NULL; + + INIT_G(); + + if (!*++argv) + bb_show_usage(); + xrtnl_open(&rth); + ret = EXIT_SUCCESS; + + obj = index_in_substrings(objects, *argv++); + + if (obj < OBJ_qdisc) + bb_show_usage(); + if (!*argv) + cmd = CMD_show; /* list is the default */ + else { + cmd = index_in_substrings(commands, *argv); + if (cmd < 0) + bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + argv++; + } + memset(&msg, 0, sizeof(msg)); + msg.tcm_family = AF_UNSPEC; + ll_init_map(&rth); + while (*argv) { + arg = index_in_substrings(args, *argv); + if (arg == ARG_dev) { + NEXT_ARG(); + if (dev) + duparg2("dev", *argv); + dev = *argv++; + msg.tcm_ifindex = xll_name_to_index(dev); + if (cmd >= CMD_show) + filter_ifindex = msg.tcm_ifindex; + } else if ((arg == ARG_qdisc && obj == OBJ_class && cmd >= CMD_show) + || (arg == ARG_handle && obj == OBJ_qdisc + && cmd == CMD_change)) { + NEXT_ARG(); + /* We don't care about duparg2("qdisc handle",*argv) for now */ + if (get_qdisc_handle(&filter_qdisc, *argv)) + invarg(*argv, "qdisc"); + } else if (obj != OBJ_qdisc && + (arg == ARG_root + || arg == ARG_parent + || (obj == OBJ_filter && arg >= ARG_pref))) { + } else { + invarg(*argv, "command"); + } + NEXT_ARG(); + if (arg == ARG_root) { + if (msg.tcm_parent) + duparg("parent", *argv); + msg.tcm_parent = TC_H_ROOT; + if (obj == OBJ_filter) + filter_parent = TC_H_ROOT; + } else if (arg == ARG_parent) { + __u32 handle; + if (msg.tcm_parent) + duparg(*argv, "parent"); + if (get_tc_classid(&handle, *argv)) + invarg(*argv, "parent"); + msg.tcm_parent = handle; + if (obj == OBJ_filter) + filter_parent = handle; + } else if (arg == ARG_handle) { /* filter::list */ + if (msg.tcm_handle) + duparg(*argv, "handle"); + /* reject LONG_MIN || LONG_MAX */ + /* TODO: for fw + if ((slash = strchr(handle, '/')) != NULL) + *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); */ + } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){ + } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */ + if (filter_prio) + duparg(*argv, "priority"); + filter_prio = get_u32(*argv, "priority"); + } else if (arg == ARG_proto) { /* filter::list */ + __u16 tmp; + if (filter_proto) + duparg(*argv, "protocol"); + if (ll_proto_a2n(&tmp, *argv)) + invarg(*argv, "protocol"); + filter_proto = tmp; + } + } + if (cmd >= CMD_show) { /* show or list */ + if (obj == OBJ_filter) + msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto); + if (rtnl_dump_request(&rth, obj == OBJ_qdisc ? RTM_GETQDISC : + obj == OBJ_class ? RTM_GETTCLASS : RTM_GETTFILTER, + &msg, sizeof(msg)) < 0) + bb_simple_perror_msg_and_die("cannot send dump request"); + + xrtnl_dump_filter(&rth, obj == OBJ_qdisc ? print_qdisc : + obj == OBJ_class ? print_class : print_filter, + NULL); + } + if (ENABLE_FEATURE_CLEAN_UP) { + rtnl_close(&rth); + } + return ret; +} diff --git a/release/src/router/busybox/networking/tcpudp.c b/release/src/router/busybox/networking/tcpudp.c index d6731198c9..55a3e0899c 100644 --- a/release/src/router/busybox/networking/tcpudp.c +++ b/release/src/router/busybox/networking/tcpudp.c @@ -85,8 +85,7 @@ static void undo_xsetenv(void) char **pp = env_cur = &env_var[0]; while (*pp) { char *var = *pp; - *strchrnul(var, '=') = '\0'; - unsetenv(var); + bb_unsetenv(var); free(var); *pp++ = NULL; } @@ -147,7 +146,7 @@ static void connection_status(void) static void sig_child_handler(int sig UNUSED_PARAM) { int wstat; - int pid; + pid_t pid; while ((pid = wait_any_nohang(&wstat)) > 0) { if (max_per_host) @@ -497,9 +496,9 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) xdup2(0, 1); - signal(SIGTERM, SIG_DFL); - signal(SIGPIPE, SIG_DFL); - signal(SIGCHLD, SIG_DFL); + signal(SIGPIPE, SIG_DFL); /* this one was SIG_IGNed */ + /* Non-ignored signals revert to SIG_DFL on exec anyway */ + /*signal(SIGCHLD, SIG_DFL);*/ sig_unblock(SIGCHLD); #ifdef SSLSVD diff --git a/release/src/router/busybox/networking/tcpudp_perhost.h b/release/src/router/busybox/networking/tcpudp_perhost.h index 2e093c1c42..d370036a7a 100644 --- a/release/src/router/busybox/networking/tcpudp_perhost.h +++ b/release/src/router/busybox/networking/tcpudp_perhost.h @@ -7,9 +7,7 @@ * Licensed under GPLv2, see file LICENSE in this tarball for details. */ -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct hcc { char *ip; @@ -32,6 +30,4 @@ void ipsvd_perhost_remove(int pid); //unsigned ipsvd_perhost_setpid(int pid); //void ipsvd_perhost_free(void); -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY diff --git a/release/src/router/busybox/networking/telnet.c b/release/src/router/busybox/networking/telnet.c index 63ee380885..cc994250c8 100644 --- a/release/src/router/busybox/networking/telnet.c +++ b/release/src/router/busybox/networking/telnet.c @@ -21,7 +21,6 @@ * */ -#include #include #include #include "libbb.h" @@ -60,7 +59,6 @@ struct globals { byte telwish; /* DO, DONT, WILL, WONT */ byte charmode; byte telflags; - byte gotsig; byte do_termios; #if ENABLE_FEATURE_TELNET_TTYPE char *ttype; @@ -94,7 +92,7 @@ static void will_charmode(void); static void telopt(byte c); static int subneg(byte c); -static void iacflush(void) +static void iac_flush(void) { write(netfd, G.iacbuf, G.iaclen); G.iaclen = 0; @@ -109,11 +107,11 @@ static void doexit(int ev) exit(ev); } -static void conescape(void) +static void con_escape(void) { char b; - if (G.gotsig) /* came from line mode... go raw */ + if (bb_got_signal) /* came from line mode... go raw */ rawmode(); write_str(1, "\r\nConsole escape. Commands are:\r\n\n" @@ -127,15 +125,15 @@ static void conescape(void) switch (b) { case 'l': - if (!G.gotsig) { + if (!bb_got_signal) { do_linemode(); - goto rrturn; + goto ret; } break; case 'c': - if (G.gotsig) { + if (bb_got_signal) { will_charmode(); - goto rrturn; + goto ret; } break; case 'z': @@ -149,15 +147,14 @@ static void conescape(void) write_str(1, "continuing...\r\n"); - if (G.gotsig) + if (bb_got_signal) cookmode(); - - rrturn: - G.gotsig = 0; + ret: + bb_got_signal = 0; } -static void handlenetoutput(int len) +static void handle_net_output(int len) { /* here we could do smart tricks how to handle 0xFF:s in output * stream like writing twice every sequence of FF:s (thus doing @@ -170,19 +167,19 @@ static void handlenetoutput(int len) * first - I cannot use programs like sz/rz * second - the 0x0D is sent as one character and if the next * char is 0x0A then it's eaten by a server side. - * third - whay doy you have to make 'many write()s'? + * third - why do you have to make 'many write()s'? * I don't understand. - * So I implemented it. It's realy useful for me. I hope that - * others people will find it interesting too. + * So I implemented it. It's really useful for me. I hope that + * other people will find it interesting too. */ int i, j; - byte * p = (byte*)G.buf; + byte *p = (byte*)G.buf; byte outbuf[4*DATABUFSIZE]; for (i = len, j = 0; i > 0; i--, p++) { if (*p == 0x1d) { - conescape(); + con_escape(); return; } outbuf[j++] = *p; @@ -195,7 +192,7 @@ static void handlenetoutput(int len) write(netfd, outbuf, j); } -static void handlenetinput(int len) +static void handle_net_input(int len) { int i; int cstart = 0; @@ -208,51 +205,54 @@ static void handlenetinput(int len) cstart = i; G.telstate = TS_IAC; } - } else - switch (G.telstate) { - case TS_0: - if (c == IAC) - G.telstate = TS_IAC; - else - G.buf[cstart++] = c; - break; + continue; + } + switch (G.telstate) { + case TS_0: + if (c == IAC) + G.telstate = TS_IAC; + else + G.buf[cstart++] = c; + break; - case TS_IAC: - if (c == IAC) { /* IAC IAC -> 0xFF */ - G.buf[cstart++] = c; - G.telstate = TS_0; - break; - } - /* else */ - switch (c) { - case SB: - G.telstate = TS_SUB1; - break; - case DO: - case DONT: - case WILL: - case WONT: - G.telwish = c; - G.telstate = TS_OPT; - break; - default: - G.telstate = TS_0; /* DATA MARK must be added later */ - } - break; - case TS_OPT: /* WILL, WONT, DO, DONT */ - telopt(c); + case TS_IAC: + if (c == IAC) { /* IAC IAC -> 0xFF */ + G.buf[cstart++] = c; G.telstate = TS_0; break; - case TS_SUB1: /* Subnegotiation */ - case TS_SUB2: /* Subnegotiation */ - if (subneg(c)) - G.telstate = TS_0; + } + /* else */ + switch (c) { + case SB: + G.telstate = TS_SUB1; + break; + case DO: + case DONT: + case WILL: + case WONT: + G.telwish = c; + G.telstate = TS_OPT; break; + default: + G.telstate = TS_0; /* DATA MARK must be added later */ } + break; + case TS_OPT: /* WILL, WONT, DO, DONT */ + telopt(c); + G.telstate = TS_0; + break; + case TS_SUB1: /* Subnegotiation */ + case TS_SUB2: /* Subnegotiation */ + if (subneg(c)) + G.telstate = TS_0; + break; + } } if (G.telstate) { - if (G.iaclen) iacflush(); - if (G.telstate == TS_0) G.telstate = 0; + if (G.iaclen) + iac_flush(); + if (G.telstate == TS_0) + G.telstate = 0; len = cstart; } @@ -260,87 +260,87 @@ static void handlenetinput(int len) write(STDOUT_FILENO, G.buf, len); } -static void putiac(int c) +static void put_iac(int c) { G.iacbuf[G.iaclen++] = c; } -static void putiac2(byte wwdd, byte c) +static void put_iac2(byte wwdd, byte c) { if (G.iaclen + 3 > IACBUFSIZE) - iacflush(); + iac_flush(); - putiac(IAC); - putiac(wwdd); - putiac(c); + put_iac(IAC); + put_iac(wwdd); + put_iac(c); } #if ENABLE_FEATURE_TELNET_TTYPE -static void putiac_subopt(byte c, char *str) +static void put_iac_subopt(byte c, char *str) { - int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) + int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) if (G.iaclen + len > IACBUFSIZE) - iacflush(); + iac_flush(); - putiac(IAC); - putiac(SB); - putiac(c); - putiac(0); + put_iac(IAC); + put_iac(SB); + put_iac(c); + put_iac(0); while (*str) - putiac(*str++); + put_iac(*str++); - putiac(IAC); - putiac(SE); + put_iac(IAC); + put_iac(SE); } #endif #if ENABLE_FEATURE_TELNET_AUTOLOGIN -static void putiac_subopt_autologin(void) +static void put_iac_subopt_autologin(void) { int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) const char *user = "USER"; if (G.iaclen + len > IACBUFSIZE) - iacflush(); + iac_flush(); - putiac(IAC); - putiac(SB); - putiac(TELOPT_NEW_ENVIRON); - putiac(TELQUAL_IS); - putiac(NEW_ENV_VAR); + put_iac(IAC); + put_iac(SB); + put_iac(TELOPT_NEW_ENVIRON); + put_iac(TELQUAL_IS); + put_iac(NEW_ENV_VAR); while (*user) - putiac(*user++); + put_iac(*user++); - putiac(NEW_ENV_VALUE); + put_iac(NEW_ENV_VALUE); while (*G.autologin) - putiac(*G.autologin++); + put_iac(*G.autologin++); - putiac(IAC); - putiac(SE); + put_iac(IAC); + put_iac(SE); } #endif #if ENABLE_FEATURE_AUTOWIDTH -static void putiac_naws(byte c, int x, int y) +static void put_iac_naws(byte c, int x, int y) { if (G.iaclen + 9 > IACBUFSIZE) - iacflush(); + iac_flush(); - putiac(IAC); - putiac(SB); - putiac(c); + put_iac(IAC); + put_iac(SB); + put_iac(c); - putiac((x >> 8) & 0xff); - putiac(x & 0xff); - putiac((y >> 8) & 0xff); - putiac(y & 0xff); + put_iac((x >> 8) & 0xff); + put_iac(x & 0xff); + put_iac((y >> 8) & 0xff); + put_iac(y & 0xff); - putiac(IAC); - putiac(SE); + put_iac(IAC); + put_iac(SE); } #endif @@ -369,9 +369,9 @@ static void will_charmode(void) G.telflags |= (UF_ECHO | UF_SGA); setConMode(); - putiac2(DO, TELOPT_ECHO); - putiac2(DO, TELOPT_SGA); - iacflush(); + put_iac2(DO, TELOPT_ECHO); + put_iac2(DO, TELOPT_SGA); + iac_flush(); } static void do_linemode(void) @@ -380,24 +380,24 @@ static void do_linemode(void) G.telflags &= ~(UF_ECHO | UF_SGA); setConMode(); - putiac2(DONT, TELOPT_ECHO); - putiac2(DONT, TELOPT_SGA); - iacflush(); + put_iac2(DONT, TELOPT_ECHO); + put_iac2(DONT, TELOPT_SGA); + iac_flush(); } static void to_notsup(char c) { if (G.telwish == WILL) - putiac2(DONT, c); + put_iac2(DONT, c); else if (G.telwish == DO) - putiac2(WONT, c); + put_iac2(WONT, c); } static void to_echo(void) { /* if server requests ECHO, don't agree */ if (G.telwish == DO) { - putiac2(WONT, TELOPT_ECHO); + put_iac2(WONT, TELOPT_ECHO); return; } if (G.telwish == DONT) @@ -413,9 +413,9 @@ static void to_echo(void) G.telflags ^= UF_ECHO; if (G.telflags & UF_ECHO) - putiac2(DO, TELOPT_ECHO); + put_iac2(DO, TELOPT_ECHO); else - putiac2(DONT, TELOPT_ECHO); + put_iac2(DONT, TELOPT_ECHO); setConMode(); write_str(1, "\r\n"); /* sudden modec */ @@ -433,9 +433,9 @@ static void to_sga(void) G.telflags ^= UF_SGA; /* toggle */ if (G.telflags & UF_SGA) - putiac2(DO, TELOPT_SGA); + put_iac2(DO, TELOPT_SGA); else - putiac2(DONT, TELOPT_SGA); + put_iac2(DONT, TELOPT_SGA); } #if ENABLE_FEATURE_TELNET_TTYPE @@ -444,9 +444,9 @@ static void to_ttype(void) /* Tell server we will (or won't) do TTYPE */ if (G.ttype) - putiac2(WILL, TELOPT_TTYPE); + put_iac2(WILL, TELOPT_TTYPE); else - putiac2(WONT, TELOPT_TTYPE); + put_iac2(WONT, TELOPT_TTYPE); } #endif @@ -456,9 +456,9 @@ static void to_new_environ(void) /* Tell server we will (or will not) do AUTOLOGIN */ if (G.autologin) - putiac2(WILL, TELOPT_NEW_ENVIRON); + put_iac2(WILL, TELOPT_NEW_ENVIRON); else - putiac2(WONT, TELOPT_NEW_ENVIRON); + put_iac2(WONT, TELOPT_NEW_ENVIRON); } #endif @@ -466,7 +466,7 @@ static void to_new_environ(void) static void to_naws(void) { /* Tell server we will do NAWS */ - putiac2(WILL, TELOPT_NAWS); + put_iac2(WILL, TELOPT_NAWS); } #endif @@ -488,7 +488,7 @@ static void telopt(byte c) #if ENABLE_FEATURE_AUTOWIDTH case TELOPT_NAWS: to_naws(); - putiac_naws(c, G.win_width, G.win_height); + put_iac_naws(c, G.win_width, G.win_height); break; #endif default: @@ -507,12 +507,12 @@ static int subneg(byte c) #if ENABLE_FEATURE_TELNET_TTYPE else if (c == TELOPT_TTYPE) - putiac_subopt(TELOPT_TTYPE, G.ttype); + put_iac_subopt(TELOPT_TTYPE, G.ttype); #endif #if ENABLE_FEATURE_TELNET_AUTOLOGIN else if (c == TELOPT_NEW_ENVIRON) - putiac_subopt_autologin(); + put_iac_subopt_autologin(); #endif break; case TS_SUB2: @@ -524,12 +524,6 @@ static int subneg(byte c) return FALSE; } -static void fgotsig(int sig) -{ - G.gotsig = sig; -} - - static void rawmode(void) { if (G.do_termios) @@ -592,7 +586,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); - signal(SIGINT, fgotsig); + signal(SIGINT, record_signo); #ifdef USE_POLL ufds[0].fd = 0; ufds[1].fd = netfd; @@ -617,8 +611,8 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) /* timeout */ case -1: /* error, ignore and/or log something, bay go to loop */ - if (G.gotsig) - conescape(); + if (bb_got_signal) + con_escape(); else sleep(1); break; @@ -634,7 +628,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) if (len <= 0) doexit(EXIT_SUCCESS); TRACE(0, ("Read con: %d\n", len)); - handlenetoutput(len); + handle_net_output(len); } #ifdef USE_POLL @@ -649,7 +643,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) doexit(EXIT_FAILURE); } TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); - handlenetinput(len); + handle_net_input(len); } } } /* while (1) */ diff --git a/release/src/router/busybox/networking/telnetd.c b/release/src/router/busybox/networking/telnetd.c index 7f748641b7..ccf3289250 100644 --- a/release/src/router/busybox/networking/telnetd.c +++ b/release/src/router/busybox/networking/telnetd.c @@ -35,8 +35,8 @@ /* Structure that describes a session */ struct tsession { struct tsession *next; + pid_t shell_pid; int sockfd_read, sockfd_write, ptyfd; - int shell_pid; /* two circular buffers */ /*char *buf1, *buf2;*/ @@ -74,9 +74,6 @@ static const char *issuefile = "/etc/issue.net"; past (bf + len) then that IAC will be left unprocessed and *processed will be less than len. - FIXME - if we mean to send 0xFF to the terminal then it will be escaped, - what is the escape character? We aren't handling that situation here. - CR-LF ->'s CR mapping is also done here, for convenience. NB: may fail to remove iacs which wrap around buffer! @@ -96,44 +93,55 @@ remove_iacs(struct tsession *ts, int *pnum_totty) *totty++ = c; ptr++; - /* We now map \r\n ==> \r for pragmatic reasons. + /* We map \r\n ==> \r for pragmatic reasons. * Many client implementations send \r\n when * the user hits the CarriageReturn key. */ if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0')) ptr++; - } else { - /* - * TELOPT_NAWS support! - */ - if ((ptr+2) >= end) { - /* only the beginning of the IAC is in the - buffer we were asked to process, we can't - process this char. */ - break; - } + continue; + } - /* - * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE - */ - else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { - struct winsize ws; - - if ((ptr+8) >= end) - break; /* incomplete, can't process */ - ws.ws_col = (ptr[3] << 8) | ptr[4]; - ws.ws_row = (ptr[5] << 8) | ptr[6]; - ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); - ptr += 9; - } else { - /* skip 3-byte IAC non-SB cmd */ + if ((ptr+1) >= end) + break; + if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */ + ptr += 2; + continue; + } + if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */ + *totty++ = ptr[1]; + ptr += 2; + continue; + } + + /* + * TELOPT_NAWS support! + */ + if ((ptr+2) >= end) { + /* only the beginning of the IAC is in the + buffer we were asked to process, we can't + process this char. */ + break; + } + /* + * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE + */ + if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { + struct winsize ws; + if ((ptr+8) >= end) + break; /* incomplete, can't process */ + ws.ws_col = (ptr[3] << 8) | ptr[4]; + ws.ws_row = (ptr[5] << 8) | ptr[6]; + ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); + ptr += 9; + continue; + } + /* skip 3-byte IAC non-SB cmd */ #if DEBUG - fprintf(stderr, "Ignoring IAC %s,%s\n", - TELCMD(ptr[1]), TELOPT(ptr[2])); + fprintf(stderr, "Ignoring IAC %s,%s\n", + TELCMD(ptr[1]), TELOPT(ptr[2])); #endif - ptr += 3; - } - } + ptr += 3; } num_totty = totty - ptr0; @@ -148,6 +156,48 @@ remove_iacs(struct tsession *ts, int *pnum_totty) return memmove(ptr - num_totty, ptr0, num_totty); } +/* + * Converting single IAC into double on output + */ +static size_t iac_safe_write(int fd, const char *buf, size_t count) +{ + const char *IACptr; + size_t wr, rc, total; + + total = 0; + while (1) { + if (count == 0) + return total; + if (*buf == (char)IAC) { + static const char IACIAC[] ALIGN1 = { IAC, IAC }; + rc = safe_write(fd, IACIAC, 2); + if (rc != 2) + break; + buf++; + total++; + count--; + continue; + } + /* count != 0, *buf != IAC */ + IACptr = memchr(buf, IAC, count); + wr = count; + if (IACptr) + wr = IACptr - buf; + rc = safe_write(fd, buf, wr); + if (rc != wr) + break; + buf += rc; + total += rc; + count -= rc; + } + /* here: rc - result of last short write */ + if ((ssize_t)rc < 0) { /* error? */ + if (total == 0) + return rc; + rc = 0; + } + return total + rc; +} static struct tsession * make_new_session( @@ -171,6 +221,8 @@ make_new_session( ndelay_on(fd); #if ENABLE_FEATURE_TELNETD_STANDALONE ts->sockfd_read = sock; + /* SO_KEEPALIVE by popular demand */ + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); ndelay_on(sock); if (!sock) { /* We are called with fd 0 - we are in inetd mode */ sock++; /* so use fd 1 for output */ @@ -180,6 +232,8 @@ make_new_session( if (sock > maxfd) maxfd = sock; #else + /* SO_KEEPALIVE by popular demand */ + setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); /* ts->sockfd_read = 0; - done by xzalloc */ ts->sockfd_write = 1; ndelay_on(0); @@ -193,13 +247,24 @@ make_new_session( static const char iacs_to_send[] ALIGN1 = { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, - IAC, DO, TELOPT_LFLOW, + /* This requires telnetd.ctrlSQ.patch (incomplete) */ + /* IAC, DO, TELOPT_LFLOW, */ IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; - memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send)); - ts->rdidx2 = sizeof(iacs_to_send); - ts->size2 = sizeof(iacs_to_send); + /* This confuses iac_safe_write(), it will try to duplicate + * each IAC... */ + //memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send)); + //ts->rdidx2 = sizeof(iacs_to_send); + //ts->size2 = sizeof(iacs_to_send); + /* So just stuff it into TCP stream! (no error check...) */ +#if ENABLE_FEATURE_TELNETD_STANDALONE + safe_write(sock, iacs_to_send, sizeof(iacs_to_send)); +#else + safe_write(1, iacs_to_send, sizeof(iacs_to_send)); +#endif + /*ts->rdidx2 = 0; - xzalloc did it */ + /*ts->size2 = 0;*/ } fflush(NULL); /* flush all streams */ @@ -220,13 +285,13 @@ make_new_session( /* Child */ /* Careful - we are after vfork! */ - /* make new session and process group */ - setsid(); - - /* Restore default signal handling */ + /* Restore default signal handling ASAP */ bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); - /* open the child's side of the tty. */ + /* Make new session and process group */ + setsid(); + + /* Open the child's side of the tty. */ /* NB: setsid() disconnects from any previous ctty's. Therefore * we must open child's side of the tty AFTER setsid! */ close(0); @@ -243,7 +308,7 @@ make_new_session( termbuf.c_iflag |= ICRNL; termbuf.c_iflag &= ~IXOFF; /*termbuf.c_lflag &= ~ICANON;*/ - tcsetattr(0, TCSANOW, &termbuf); + tcsetattr_stdin_TCSANOW(&termbuf); /* Uses FILE-based I/O to stdout, but does fflush(stdout), * so should be safe with vfork. @@ -296,7 +361,7 @@ free_session(struct tsession *ts) * doesn't send SIGKILL. When we close ptyfd, * kernel sends SIGHUP to processes having slave side opened. */ kill(ts->shell_pid, SIGKILL); - wait4(ts->shell_pid, NULL, 0, NULL); + waitpid(ts->shell_pid, NULL, 0); #endif close(ts->ptyfd); close(ts->sockfd_read); @@ -387,7 +452,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) } /* Redirect log to syslog early, if needed */ if (IS_INETD || !(opt & OPT_FOREGROUND)) { - openlog(applet_name, 0, LOG_USER); + openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } USE_FEATURE_TELNETD_STANDALONE( @@ -523,7 +588,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { /* Write to socket from buffer 2. */ count = MIN(BUFSIZE - ts->wridx2, ts->size2); - count = safe_write(ts->sockfd_write, TS_BUF2 + ts->wridx2, count); + count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2 + ts->wridx2), count); if (count < 0) { if (errno == EAGAIN) goto skip2; diff --git a/release/src/router/busybox/networking/telnetd.ctrlSQ.patch b/release/src/router/busybox/networking/telnetd.ctrlSQ.patch new file mode 100644 index 0000000000..885e105230 --- /dev/null +++ b/release/src/router/busybox/networking/telnetd.ctrlSQ.patch @@ -0,0 +1,175 @@ +From: "Doug Graham" +Date: 2009-01-22 07:20 + +Hello, + +Busybox's telnetd does not disable local (client-side) flow control +properly. It does not put the pty into packet mode and then notify the +client whenever flow control is disabled by an application running under +its control. The result is that ^S/^Q are not passed through to the +application, which is painful when the application is an emacs variant. + +I suppose that support for this might be considered bloat, but the +included patch only adds about 200 bytes of text to x86 busybox and 300 +bytes to mipsel busybox. Please consider applying. + +============================= + +NB: the patch doesn't work as-is because we now have iac_safe_write() +which quotes IACs on output. + +============================= +Docs: + +The following ioctl(2) calls apply only to pseudo terminals: + +TIOCSTOP Stops output to a terminal (e.g. like typing ^S). Takes no parameter. + +TIOCSTART Restarts output (stopped by TIOCSTOP or by typing ^S). Takes no parameter. + +TIOCPKT Enable/disable packet mode. When applied to the master side of a pseudo terminal, each +subsequent read(2) from the terminal will return data written on the slave part of the pseudo terminal preceded by a +zero byte (symbolically defined as TIOCPKT_DATA), or a single byte reflecting control status information. +In the latter case, the byte is an inclusive-or of zero or more of the bits: + +TIOCPKT_FLUSHREAD whenever the read queue for the terminal is flushed. +TIOCPKT_FLUSHWRITE whenever the write queue for the terminal is flushed. +TIOCPKT_STOP whenever output to the terminal is stopped a la ^S. +TIOCPKT_START whenever output to the terminal is restarted. +TIOCPKT_DOSTOP whenever t_stopc is ^S and t_startc is ^Q. +TIOCPKT_NOSTOP whenever the start and stop characters are not ^S/^Q. + +While this mode is in use, the presence of control status information to be read from the master side may be detected +by a select(2) for exceptional conditions. + +This mode is used by rlogin(1) and rlogind(8) to implement a remote-echoed, locally ^S/^Q flow-controlled remote login +with proper back-flushing of output; it can be used by other similar programs. + +TIOCUCNTL Enable/disable a mode that allows a small number of simple user ioctl(2) commands to be passed through +the pseudo-terminal, using a protocol similar to that of TIOCPKT. The TIOCUCNTL and TIOCPKT modes are mutually +exclusive. This mode is enabled from the master side of a pseudo terminal. Each subsequent read(2) from the master side +will return data written on the slave part of the pseudo terminal preceded by a zero byte, or a single byte reflecting a +user control operation on the slave side. A user control command consists of a special ioctl(2) operation with no data; +the command is given as UIOCCMD (n), where n is a number in the range 1-255. The operation value n will be received as +a single byte on the next read(2) from the master side. The ioctl(2) UIOCCMD (0) is a no-op that may be used to probe +for the existence of this facility. As with TIOCPKT mode, command operations may be detected with a select(2) for +exceptional conditions. + +--- busybox-1.13.2/networking/telnetd.c 2009/01/21 20:02:39 1.1 ++++ busybox-1.13.2/networking/telnetd.c 2009/01/22 00:35:28 +@@ -38,6 +38,9 @@ + int sockfd_read, sockfd_write, ptyfd; + int shell_pid; + ++#ifdef TIOCPKT ++ int flowstate; ++#endif + /* two circular buffers */ + /*char *buf1, *buf2;*/ + /*#define TS_BUF1 ts->buf1*/ +@@ -170,6 +173,9 @@ + int fd, pid; + char tty_name[GETPTY_BUFSIZE]; + struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); ++#ifdef TIOCPKT ++ int on = 1; ++#endif + + /*ts->buf1 = (char *)(ts + 1);*/ + /*ts->buf2 = ts->buf1 + BUFSIZE;*/ +@@ -180,6 +186,10 @@ + maxfd = fd; + ts->ptyfd = fd; + ndelay_on(fd); ++#ifdef TIOCPKT ++ ioctl(fd, TIOCPKT, &on); ++ ts->flowstate = TIOCPKT_DOSTOP; ++#endif + #if ENABLE_FEATURE_TELNETD_STANDALONE + ts->sockfd_read = sock; + /* SO_KEEPALIVE by popular demand */ +@@ -385,6 +395,16 @@ + portnbr = 23, + }; + #endif ++#ifdef TIOCPKT ++ int control; ++ static const char lflow_on[] = ++ {IAC, SB, TELOPT_LFLOW, LFLOW_ON, IAC, SE}; ++ static const char lflow_off[] = ++ {IAC, SB, TELOPT_LFLOW, LFLOW_OFF, IAC, SE}; ++# define RESERVED sizeof(lflow_on) ++#else ++# define RESERVED 0 ++#endif + /* Even if !STANDALONE, we accept (and ignore) -i, thus people + * don't need to guess whether it's ok to pass -i to us */ + opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"), +@@ -475,7 +495,7 @@ + FD_SET(ts->sockfd_read, &rdfdset); + if (ts->size2 > 0) /* can write to socket */ + FD_SET(ts->sockfd_write, &wrfdset); +- if (ts->size2 < BUFSIZE) /* can read from pty */ ++ if (ts->size2 < (BUFSIZE - RESERVED)) /* can read from pty */ + FD_SET(ts->ptyfd, &rdfdset); + } + ts = next; +@@ -593,6 +613,52 @@ + goto skip4; + goto kill_session; + } ++#ifdef TIOCPKT ++ control = TS_BUF2[ts->rdidx2]; ++ if (--count > 0 && control == TIOCPKT_DATA) { ++ /* ++ * If we are in packet mode, and we have ++ * just read a chunk of actual data from ++ * the pty, then there is the TIOCPKT_DATA ++ * byte (zero) that we have got to remove ++ * somehow. If there were no chars in ++ * TS_BUF2 before we did this read, then ++ * we can optimize by just advancing wridx2. ++ * Otherwise we have to copy the new data down ++ * to close the gap (Could use readv() instead). ++ */ ++ if (ts->size2 == 0) ++ ts->wridx2++; ++ else { ++ memmove(TS_BUF2 + ts->rdidx2, ++ TS_BUF2 + ts->rdidx2 + 1, count); ++ } ++ } ++ ++ /* ++ * If the flow control state changed, notify ++ * the client. If "control" is not TIOCPKT_DATA, ++ * then there are no data bytes to worry about. ++ */ ++ if ((control & (TIOCPKT_DOSTOP|TIOCPKT_NOSTOP)) != 0 ++ && ts->flowstate != (control & TIOCPKT_DOSTOP)) { ++ const char *p = ts->flowstate ? lflow_off : lflow_on; ++ ++ /* ++ * We know we have enough free slots available ++ * (see RESERVED) but they are not necessarily ++ * contiguous; we may have to wrap. ++ */ ++ for (count = sizeof(lflow_on); count > 0; count--) { ++ TS_BUF2[ts->rdidx2++] = *p++; ++ if (ts->rdidx2 >= BUFSIZE) ++ ts->rdidx2 = 0; ++ ts->size2++; ++ } ++ ++ ts->flowstate = control & TIOCPKT_DOSTOP; ++ } ++#endif /* TIOCPKT */ + ts->size2 += count; + ts->rdidx2 += count; + if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */ + +--Doug +_______________________________________________ +busybox mailing list +busybox@busybox.net +http://lists.busybox.net/mailman/listinfo/busybox diff --git a/release/src/router/busybox/networking/tftp.c b/release/src/router/busybox/networking/tftp.c index 07d672dcbc..9c78b6e144 100644 --- a/release/src/router/busybox/networking/tftp.c +++ b/release/src/router/busybox/networking/tftp.c @@ -113,7 +113,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize) bb_error_msg("bad blocksize '%s'", blksize_str); return -1; } -#if ENABLE_DEBUG_TFTP +#if ENABLE_TFTP_DEBUG bb_error_msg("using blksize %u", blksize); #endif return blksize; @@ -223,9 +223,7 @@ static int tftp_protocol( } if (user_opt) { - struct passwd *pw = getpwnam(user_opt); - if (!pw) - bb_error_msg_and_die("unknown user %s", user_opt); + struct passwd *pw = xgetpwnam(user_opt); change_identity(pw); /* initgroups, setgid, setuid */ } } @@ -369,7 +367,7 @@ static int tftp_protocol( waittime_ms = TFTP_TIMEOUT_MS; send_again: -#if ENABLE_DEBUG_TFTP +#if ENABLE_TFTP_DEBUG fprintf(stderr, "sending %u bytes\n", send_len); for (cp = xbuf; cp < &xbuf[send_len]; cp++) fprintf(stderr, "%02x ", (unsigned char) *cp); @@ -431,7 +429,7 @@ static int tftp_protocol( /* Process recv'ed packet */ opcode = ntohs( ((uint16_t*)rbuf)[0] ); recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); -#if ENABLE_DEBUG_TFTP +#if ENABLE_TFTP_DEBUG fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); #endif if (opcode == TFTP_ERROR) { @@ -591,10 +589,15 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) } #endif - if (!local_file) - local_file = remote_file; - if (!remote_file) + if (remote_file) { + if (!local_file) { + const char *slash = strrchr(remote_file, '/'); + local_file = slash ? slash + 1 : remote_file; + } + } else { remote_file = local_file; + } + /* Error if filename or host is not known */ if (!remote_file || !argv[0]) bb_show_usage(); @@ -602,7 +605,7 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) port = bb_lookup_port(argv[1], "udp", 69); peer_lsa = xhost2sockaddr(argv[0], port); -#if ENABLE_DEBUG_TFTP +#if ENABLE_TFTP_DEBUG fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n", xmalloc_sockaddr2dotted(&peer_lsa->u.sa), remote_file, local_file); @@ -624,21 +627,6 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) #endif /* ENABLE_TFTP */ #if ENABLE_TFTPD - -/* TODO: libbb candidate? */ -static len_and_sockaddr *get_sock_lsa(int s) -{ - len_and_sockaddr *lsa; - socklen_t len = 0; - - if (getsockname(s, NULL, &len) != 0) - return NULL; - lsa = xzalloc(LSA_LEN_SIZE + len); - lsa->len = len; - getsockname(s, &lsa->u.sa, &lsa->len); - return lsa; -} - int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tftpd_main(int argc UNUSED_PARAM, char **argv) { @@ -653,8 +641,15 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) INIT_G(); our_lsa = get_sock_lsa(STDIN_FILENO); - if (!our_lsa) - bb_perror_msg_and_die("stdin is not a socket"); + if (!our_lsa) { + /* This is confusing: + *bb_error_msg_and_die("stdin is not a socket"); + * Better: */ + bb_show_usage(); + /* Help text says that tftpd must be used as inetd service, + * which is by far the most usual cause of get_sock_lsa + * failure */ + } peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len); peer_lsa->len = our_lsa->len; diff --git a/release/src/router/busybox/networking/traceroute.c b/release/src/router/busybox/networking/traceroute.c index 29cebfa61f..7284f0022d 100644 --- a/release/src/router/busybox/networking/traceroute.c +++ b/release/src/router/busybox/networking/traceroute.c @@ -215,137 +215,64 @@ #include "libbb.h" #include "inet_common.h" - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - #ifndef IPPROTO_ICMP -/* Grrrr.... */ -#define IPPROTO_ICMP 1 +# define IPPROTO_ICMP 1 #endif #ifndef IPPROTO_IP -#define IPPROTO_IP 0 +# define IPPROTO_IP 0 #endif -/* - * Overlay for ip header used by other protocols (tcp, udp). - */ -struct ipovly { - unsigned char ih_x1[9]; /* (unused) */ - unsigned char ih_pr; /* protocol */ - short ih_len; /* protocol length */ - struct in_addr ih_src; /* source internet address */ - struct in_addr ih_dst; /* destination internet address */ +/* Keep in sync with getopt32 call! */ +enum { + OPT_DONT_FRAGMNT = (1 << 0), /* F */ + OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ + OPT_TTL_FLAG = (1 << 2), /* l */ + OPT_ADDR_NUM = (1 << 3), /* n */ + OPT_BYPASS_ROUTE = (1 << 4), /* r */ + OPT_DEBUG = (1 << 5), /* d */ + OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */ + OPT_IP_CHKSUM = (1 << 7), /* x */ + OPT_TOS = (1 << 8), /* t */ + OPT_DEVICE = (1 << 9), /* i */ + OPT_MAX_TTL = (1 << 10), /* m */ + OPT_PORT = (1 << 11), /* p */ + OPT_NPROBES = (1 << 12), /* q */ + OPT_SOURCE = (1 << 13), /* s */ + OPT_WAITTIME = (1 << 14), /* w */ + OPT_PAUSE_MS = (1 << 15), /* z */ + OPT_FIRST_TTL = (1 << 16), /* f */ }; +#define verbose (option_mask32 & OPT_VERBOSE) -/* - * UDP kernel structures and variables. - */ -struct udpiphdr { - struct ipovly ui_i; /* overlaid ip structure */ - struct udphdr ui_u; /* udp header */ -}; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev -#define ui_x1 ui_i.ih_x1 -#define ui_pr ui_i.ih_pr -#define ui_len ui_i.ih_len -#define ui_src ui_i.ih_src -#define ui_dst ui_i.ih_dst -#define ui_sport ui_u.uh_sport -#define ui_dport ui_u.uh_dport -#define ui_ulen ui_u.uh_ulen -#define ui_sum ui_u.uh_sum - - -/* Host name and address list */ -struct hostinfo { - char *name; - int n; - uint32_t *addrs; +enum { + SIZEOF_ICMP_HDR = 8, + rcvsock = 3, /* receive (icmp) socket file descriptor */ + sndsock = 4, /* send (udp/icmp) socket file descriptor */ }; /* Data section of the probe packet */ -typedef struct outdata { +struct outdata_t { unsigned char seq; /* sequence number of this packet */ unsigned char ttl; /* ttl packet left with */ // UNUSED. Retaining to have the same packet size. struct timeval tv_UNUSED PACKED; /* time packet left */ -} outdata_t; - -struct IFADDRLIST { - uint32_t addr; - char device[sizeof(struct ifreq)]; }; - -/* Keep in sync with getopt32 call! */ -#define OPT_DONT_FRAGMNT (1<<0) /* F */ -#define OPT_USE_ICMP (1<<1) /* I */ -#define OPT_TTL_FLAG (1<<2) /* l */ -#define OPT_ADDR_NUM (1<<3) /* n */ -#define OPT_BYPASS_ROUTE (1<<4) /* r */ -#define OPT_DEBUG (1<<5) /* d */ -#define OPT_VERBOSE (1<<6) /* v */ -#define OPT_IP_CHKSUM (1<<7) /* x */ -#define OPT_TOS (1<<8) /* t */ -#define OPT_DEVICE (1<<9) /* i */ -#define OPT_MAX_TTL (1<<10) /* m */ -#define OPT_PORT (1<<11) /* p */ -#define OPT_NPROBES (1<<12) /* q */ -#define OPT_SOURCE (1<<13) /* s */ -#define OPT_WAITTIME (1<<14) /* w */ -#define OPT_PAUSE_MS (1<<15) /* z */ -#define OPT_FIRST_TTL (1<<16) /* f */ - -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP -/* use icmp echo instead of udp packets */ -#define useicmp (option_mask32 & OPT_USE_ICMP) -#endif -#if ENABLE_FEATURE_TRACEROUTE_VERBOSE -#define verbose (option_mask32 & OPT_VERBOSE) -#endif -#define nflag (option_mask32 & OPT_ADDR_NUM) - - struct globals { - struct ip *outip; /* last output (udp) packet */ - struct udphdr *outudp; /* last output (udp) packet */ - struct outdata *outdata; /* last output (udp) packet */ - -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - struct icmp *outicmp; /* last output (icmp) packet */ -#endif - - int rcvsock; /* receive (icmp) socket file descriptor */ - int sndsock; /* send (udp/icmp) socket file descriptor */ - + struct ip *outip; + struct outdata_t *outdata; + len_and_sockaddr *dest_lsa; int packlen; /* total length of packet */ - int minpacket; /* min ip packet size */ - int maxpacket; // 32 * 1024; /* max ip packet size */ int pmtu; /* Path MTU Discovery (RFC1191) */ - - char *hostname; - uint16_t ident; uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ - int waittime; // 5; /* time to wait for response (in seconds) */ - int doipcksum; // 1; /* calculate ip checksums by default */ - #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE int optlen; /* length of ip options */ #else #define optlen 0 #endif - - struct sockaddr_storage whereto; /* Who to try to reach */ - struct sockaddr_storage wherefrom; /* Who we are */ - /* last inbound (icmp) packet */ - unsigned char packet[512]; + unsigned char recv_pkt[512]; /* last inbound (icmp) packet */ #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE /* Maximum number of gateways (include room for one noop) */ #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t))) @@ -356,215 +283,39 @@ struct globals { #define G (*ptr_to_globals) #define outip (G.outip ) -#define outudp (G.outudp ) #define outdata (G.outdata ) -#define outicmp (G.outicmp ) -#define rcvsock (G.rcvsock ) -#define sndsock (G.sndsock ) +#define dest_lsa (G.dest_lsa ) #define packlen (G.packlen ) -#define minpacket (G.minpacket) -#define maxpacket (G.maxpacket) #define pmtu (G.pmtu ) -#define hostname (G.hostname ) #define ident (G.ident ) #define port (G.port ) #define waittime (G.waittime ) -#define doipcksum (G.doipcksum) #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE -#define optlen (G.optlen ) +# define optlen (G.optlen ) #endif -#define packet (G.packet ) -#define whereto (G.whereto ) -#define wherefrom (G.wherefrom) +#define recv_pkt (G.recv_pkt ) #define gwlist (G.gwlist ) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ - maxpacket = 32 * 1024; \ port = 32768 + 666; \ waittime = 5; \ - doipcksum = 1; \ } while (0) +#define outicmp ((struct icmp *)(outip + 1)) +#define outudp ((struct udphdr *)(outip + 1)) -/* - * Return the interface list - */ -static int -ifaddrlist(struct IFADDRLIST **ipaddrp) -{ - enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) }; - - int fd, nipaddr; -#ifdef HAVE_SOCKADDR_SA_LEN - int n; -#endif - struct ifreq *ifrp, *ifend, *ifnext; - struct sockaddr_in *addr_sin; - struct IFADDRLIST *al; - struct ifconf ifc; - struct ifreq ifr; - /* Was on stack, but 32k is a bit too much: */ - struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0])); - struct IFADDRLIST *st_ifaddrlist; - - fd = xsocket(AF_INET, SOCK_DGRAM, 0); - - ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]); - ifc.ifc_buf = (caddr_t)ibuf; - - if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 - || ifc.ifc_len < (int)sizeof(struct ifreq) - ) { - if (errno == EINVAL) - bb_error_msg_and_die( - "SIOCGIFCONF: ifreq struct too small (%u bytes)", - (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0]))); - bb_perror_msg_and_die("SIOCGIFCONF"); - } - ifrp = ibuf; - ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); - - nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq)); - st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST)); - al = st_ifaddrlist; - nipaddr = 0; - - for (; ifrp < ifend; ifrp = ifnext) { -#ifdef HAVE_SOCKADDR_SA_LEN - n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); - if (n < sizeof(*ifrp)) - ifnext = ifrp + 1; - else - ifnext = (struct ifreq *)((char *)ifrp + n); - if (ifrp->ifr_addr.sa_family != AF_INET) - continue; -#else - ifnext = ifrp + 1; -#endif - /* - * Need a template to preserve address info that is - * used below to locate the next entry. (Otherwise, - * SIOCGIFFLAGS stomps over it because the requests - * are returned in a union.) - */ - strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { - if (errno == ENXIO) - continue; - bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s", - (int)sizeof(ifr.ifr_name), ifr.ifr_name); - } - - /* Must be up */ - if ((ifr.ifr_flags & IFF_UP) == 0) - continue; - - safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1); -#ifdef sun - /* Ignore sun virtual interfaces */ - if (strchr(al->device, ':') != NULL) - continue; -#endif - ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr, - "SIOCGIFADDR: %s", al->device); - - addr_sin = (struct sockaddr_in *)&ifr.ifr_addr; - al->addr = addr_sin->sin_addr.s_addr; - ++al; - ++nipaddr; - } - if (nipaddr == 0) - bb_error_msg_and_die("can't find any network interfaces"); - - free(ibuf); - close(fd); - *ipaddrp = st_ifaddrlist; - return nipaddr; -} - - -static void -setsin(struct sockaddr_in *addr_sin, uint32_t addr) -{ - memset(addr_sin, 0, sizeof(*addr_sin)); -#ifdef HAVE_SOCKADDR_SA_LEN - addr_sin->sin_len = sizeof(*addr_sin); -#endif - addr_sin->sin_family = AF_INET; - addr_sin->sin_addr.s_addr = addr; -} - - -/* - * Return the source address for the given destination address - */ -static void -findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from) -{ - int i, n; - FILE *f; - uint32_t mask; - uint32_t dest, tmask; - struct IFADDRLIST *al; - char buf[256], tdevice[256], device[256]; - - f = xfopen_for_read("/proc/net/route"); - - /* Find the appropriate interface */ - n = 0; - mask = 0; - device[0] = '\0'; - while (fgets(buf, sizeof(buf), f) != NULL) { - ++n; - if (n == 1 && strncmp(buf, "Iface", 5) == 0) - continue; - i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x", - tdevice, &dest, &tmask); - if (i != 3) - bb_error_msg_and_die("junk in buffer"); - if ((to->sin_addr.s_addr & tmask) == dest - && (tmask > mask || mask == 0) - ) { - mask = tmask; - strcpy(device, tdevice); - } - } - fclose(f); - - if (device[0] == '\0') - bb_error_msg_and_die("can't find interface"); - - /* Get the interface address list */ - n = ifaddrlist(&al); - - /* Find our appropriate source address */ - for (i = n; i > 0; --i, ++al) - if (strcmp(device, al->device) == 0) - break; - if (i <= 0) - bb_error_msg_and_die("can't find interface %s", device); - - setsin(from, al->addr); -} - -/* -"Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n" -"\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n" -"\t[-w waittime] [-z pausemsecs] host [packetlen]" - -*/ static int -wait_for_reply(int sock, struct sockaddr_in *fromp) +wait_for_reply(struct sockaddr_in *fromp) { struct pollfd pfd[1]; int cc = 0; socklen_t fromlen = sizeof(*fromp); - pfd[0].fd = sock; + pfd[0].fd = rcvsock; pfd[0].events = POLLIN; if (safe_poll(pfd, 1, waittime * 1000) > 0) - cc = recvfrom(sock, packet, sizeof(packet), 0, + cc = recvfrom(rcvsock, recv_pkt, sizeof(recv_pkt), 0, (struct sockaddr *)fromp, &fromlen); return cc; } @@ -581,12 +332,12 @@ in_cksum(uint16_t *addr, int len) 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. + * 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) { + while (nleft > 1) { sum += *w++; nleft -= 2; } @@ -595,37 +346,18 @@ in_cksum(uint16_t *addr, int len) if (nleft == 1) sum += *(unsigned char *)w; - /* - * add back carry outs from top 16 bits to low 16 bits - */ + /* 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) { - int cc; - struct udpiphdr *ui, *oui; - struct ip tip; - - outip->ip_ttl = ttl; - outip->ip_id = htons(ident + seq); - - /* - * In most cases, the kernel will recalculate the ip checksum. - * But we must do it anyway so that the udp checksum comes out - * right. - */ - if (doipcksum) { - outip->ip_sum = - in_cksum((uint16_t *)outip, sizeof(*outip) + optlen); - if (outip->ip_sum == 0) - outip->ip_sum = 0xffff; - } + int len, res; + void *out; /* Payload */ outdata->seq = seq; @@ -633,42 +365,19 @@ send_probe(int seq, int ttl) // UNUSED: was storing gettimeofday's result there, but never ever checked it /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - if (useicmp) + if (option_mask32 & OPT_USE_ICMP) { outicmp->icmp_seq = htons(seq); - else -#endif - outudp->dest = htons(port + seq); -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - if (useicmp) { /* Always calculate checksum for icmp packets */ outicmp->icmp_cksum = 0; outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, - packlen - (sizeof(*outip) + optlen)); + packlen - (sizeof(*outip) + optlen)); if (outicmp->icmp_cksum == 0) outicmp->icmp_cksum = 0xffff; - } else -#endif - if (doipcksum) { - /* Checksum (we must save and restore ip header) */ - tip = *outip; - ui = (struct udpiphdr *)outip; - oui = (struct udpiphdr *)&tip; - /* Easier to zero and put back things that are ok */ - memset((char *)ui, 0, sizeof(ui->ui_i)); - ui->ui_src = oui->ui_src; - ui->ui_dst = oui->ui_dst; - ui->ui_pr = oui->ui_pr; - ui->ui_len = outudp->len; - outudp->check = 0; - outudp->check = in_cksum((uint16_t *)ui, packlen); - if (outudp->check == 0) - outudp->check = 0xffff; - *outip = tip; } -#if ENABLE_FEATURE_TRACEROUTE_VERBOSE +//BUG! verbose is (x & OPT_VERBOSE), not a counter! +#if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE /* XXX undocumented debugging hack */ if (verbose > 1) { const uint16_t *sp; @@ -693,17 +402,25 @@ send_probe(int seq, int ttl) } #endif -#if !defined(IP_HDRINCL) && defined(IP_TTL) +#if defined(IP_TTL) if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, - (char *)&ttl, sizeof(ttl)) < 0) { + (char *)&ttl, sizeof(ttl)) < 0) { bb_perror_msg_and_die("setsockopt ttl %d", ttl); } #endif - cc = xsendto(sndsock, (char *)outip, - packlen, (struct sockaddr *)&whereto, sizeof(whereto)); - if (cc != packlen) { - bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc); + len = packlen - sizeof(*outip); + if (option_mask32 & OPT_USE_ICMP) + out = outicmp; + else { + out = outdata; + len -= sizeof(*outudp); + set_nport(dest_lsa, htons(port + seq)); + } + res = xsendto(sndsock, out, len, + (struct sockaddr *)&dest_lsa->u.sa, dest_lsa->len); + if (res != len) { + bb_info_msg("sent %d octets, ret=%d", len, res); } } @@ -722,7 +439,7 @@ pr_type(unsigned char t) "Info Reply", "Mask Request", "Mask Reply" }; - if (t > 18) + if (t >= ARRAY_SIZE(ttab)) return "OUT-OF-RANGE"; return ttab[t]; @@ -730,18 +447,18 @@ pr_type(unsigned char t) #endif #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE -#define packet_ok(buf, cc, from, seq) \ - packet_ok(buf, cc, seq) +#define packet_ok(cc, from, seq) \ + packet_ok(cc, seq) #endif static int -packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq) +packet_ok(int cc, const struct sockaddr_in *from, int seq) { - struct icmp *icp; + const struct icmp *icp; unsigned char type, code; int hlen; - struct ip *ip; + const struct ip *ip; - ip = (struct ip *) buf; + ip = (struct ip *) recv_pkt; hlen = ip->ip_hl << 2; if (cc < hlen + ICMP_MINLEN) { #if ENABLE_FEATURE_TRACEROUTE_VERBOSE @@ -752,49 +469,54 @@ packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq) return 0; } cc -= hlen; - icp = (struct icmp *)(buf + hlen); + icp = (struct icmp *)(recv_pkt + hlen); type = icp->icmp_type; code = icp->icmp_code; /* Path MTU Discovery (RFC1191) */ - if (code != ICMP_UNREACH_NEEDFRAG) - pmtu = 0; - else { + pmtu = 0; + if (code == ICMP_UNREACH_NEEDFRAG) pmtu = ntohs(icp->icmp_nextmtu); - } - if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || - type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { - struct ip *hip; - struct udphdr *up; + + if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) + || type == ICMP_UNREACH + || type == ICMP_ECHOREPLY + ) { + const struct ip *hip; + const struct udphdr *up; hip = &icp->icmp_ip; hlen = hip->ip_hl << 2; -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - if (useicmp) { + if (option_mask32 & OPT_USE_ICMP) { struct icmp *hicmp; /* XXX */ - if (type == ICMP_ECHOREPLY && - icp->icmp_id == htons(ident) && - icp->icmp_seq == htons(seq)) + if (type == ICMP_ECHOREPLY + && icp->icmp_id == htons(ident) + && icp->icmp_seq == htons(seq) + ) { return -2; + } hicmp = (struct icmp *)((unsigned char *)hip + hlen); - /* XXX 8 is a magic number */ - if (hlen + 8 <= cc && - hip->ip_p == IPPROTO_ICMP && - hicmp->icmp_id == htons(ident) && - hicmp->icmp_seq == htons(seq)) + if (hlen + SIZEOF_ICMP_HDR <= cc + && hip->ip_p == IPPROTO_ICMP + && hicmp->icmp_id == htons(ident) + && hicmp->icmp_seq == htons(seq) + ) { return (type == ICMP_TIMXCEED ? -1 : code + 1); - } else -#endif - { - up = (struct udphdr *)((unsigned char *)hip + hlen); - /* XXX 8 is a magic number */ - if (hlen + 12 <= cc && - hip->ip_p == IPPROTO_UDP && - up->source == htons(ident) && - up->dest == htons(port + seq)) + } + } else { + up = (struct udphdr *)((char *)hip + hlen); + if (hlen + 12 <= cc + && hip->ip_p == IPPROTO_UDP +// Off: since we do not form the entire IP packet, +// but defer it to kernel, we can't set source port, +// and thus can't check it here in the reply + /* && up->source == htons(ident) */ + && up->dest == htons(port + seq) + ) { return (type == ICMP_TIMXCEED ? -1 : code + 1); + } } } #if ENABLE_FEATURE_TRACEROUTE_VERBOSE @@ -804,8 +526,9 @@ packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq) printf("\n%d bytes from %s to " "%s: icmp type %d (%s) code %d\n", - cc, inet_ntoa(from->sin_addr), - inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); + cc, inet_ntoa(from->sin_addr), + inet_ntoa(ip->ip_dst), + type, pr_type(type), icp->icmp_code); for (i = 4; i < cc; i += sizeof(*lp)) printf("%2d: x%8.8x\n", i, *lp++); } @@ -813,146 +536,84 @@ packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq) return 0; } - /* * Construct an Internet address representation. - * If the nflag has been supplied, give + * If the -n flag has been supplied, give * numeric value, otherwise try for symbolic name. */ static void -print_inetname(struct sockaddr_in *from) +print_inetname(const struct sockaddr_in *from) { const char *ina; ina = inet_ntoa(from->sin_addr); - if (nflag) - printf(" %s", ina); + if (option_mask32 & OPT_ADDR_NUM) + printf(" %s", ina); else { char *n = NULL; if (from->sin_addr.s_addr != INADDR_ANY) n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); - printf(" %s (%s)", (n ? n : ina), ina); + printf(" %s (%s)", (n ? n : ina), ina); free(n); } } static void -print(unsigned char *buf, int cc, struct sockaddr_in *from) +print(int cc, const struct sockaddr_in *from) { - struct ip *ip; - int hlen; - - ip = (struct ip *) buf; - hlen = ip->ip_hl << 2; - cc -= hlen; - print_inetname(from); -#if ENABLE_FEATURE_TRACEROUTE_VERBOSE - if (verbose) - printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); -#endif -} - + if (verbose) { + const struct ip *ip; + int hlen; -static struct hostinfo * -gethostinfo(const char *host) -{ - int n; - struct hostent *hp; - struct hostinfo *hi; - char **p; - uint32_t addr, *ap; - - hi = xzalloc(sizeof(*hi)); - addr = inet_addr(host); - if (addr != 0xffffffff) { - hi->name = xstrdup(host); - hi->n = 1; - hi->addrs = xzalloc(sizeof(hi->addrs[0])); - hi->addrs[0] = addr; - return hi; + ip = (struct ip *) recv_pkt; + hlen = ip->ip_hl << 2; + cc -= hlen; + printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); } - - hp = xgethostbyname(host); - if (hp->h_addrtype != AF_INET || hp->h_length != 4) - bb_perror_msg_and_die("bad host %s", host); - hi->name = xstrdup(hp->h_name); - for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) - continue; - hi->n = n; - hi->addrs = xzalloc(n * sizeof(hi->addrs[0])); - for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) - memcpy(ap, *p, sizeof(*ap)); - return hi; } static void -freehostinfo(struct hostinfo *hi) -{ - free(hi->name); - free(hi->addrs); - free(hi); -} - -#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE -static void -getaddr(uint32_t *ap, const char *host) -{ - struct hostinfo *hi; - - hi = gethostinfo(host); - *ap = hi->addrs[0]; - freehostinfo(hi); -} -#endif - -static void print_delta_ms(unsigned t1p, unsigned t2p) { unsigned tt = t2p - t1p; - printf(" %u.%03u ms", tt/1000, tt%1000); + printf(" %u.%03u ms", tt / 1000, tt % 1000); } +/* +Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl] +[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] +[-w waittime] [-z pausemsecs] host [packetlen]" +*/ + int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int traceroute_main(int argc, char **argv) { - int code, n; - unsigned char *outp; - uint32_t *ap; - struct sockaddr_in *from; - struct sockaddr_in *to; - struct hostinfo *hi; - int ttl, probe, i; + int minpacket; + int ttl, i; int seq = 0; int tos = 0; - char *tos_str; - char *source; + int max_ttl = 30; + int nprobes = 3; + int first_ttl = 1; + unsigned pausemsecs = 0; unsigned op; -#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE - int lsrr = 0; -#endif - uint16_t off = 0; - struct IFADDRLIST *al; + char *source; char *device; - int max_ttl = 30; + char *tos_str; char *max_ttl_str; char *port_str; - int nprobes = 3; char *nprobes_str; char *waittime_str; - unsigned pausemsecs = 0; char *pausemsecs_str; - int first_ttl = 1; char *first_ttl_str; #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE llist_t *source_route_list = NULL; + int lsrr = 0; #endif INIT_G(); - from = (struct sockaddr_in *)&wherefrom; - to = (struct sockaddr_in *)&whereto; - //opterr = 0; #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE opt_complementary = "x-x:g::"; #else @@ -970,12 +631,10 @@ int traceroute_main(int argc, char **argv) #endif ); - if (op & OPT_DONT_FRAGMNT) - off = IP_DF; - if (op & OPT_IP_CHKSUM) { - doipcksum = 0; +#if 0 /* IGNORED */ + if (op & OPT_IP_CHKSUM) bb_error_msg("warning: ip checksums disabled"); - } +#endif if (op & OPT_TOS) tos = xatou_range(tos_str, 0, 255); if (op & OPT_MAX_TTL) @@ -989,63 +648,47 @@ int traceroute_main(int argc, char **argv) * set the ip source address of the outbound * probe (e.g., on a multi-homed host). */ - if (getuid()) - bb_error_msg_and_die("-s %s: permission denied", source); + if (getuid() != 0) + bb_error_msg_and_die("you must be root to use -s"); } if (op & OPT_WAITTIME) - waittime = xatou_range(waittime_str, 2, 24 * 60 * 60); + waittime = xatou_range(waittime_str, 1, 24 * 60 * 60); if (op & OPT_PAUSE_MS) pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000); if (op & OPT_FIRST_TTL) - first_ttl = xatou_range(first_ttl_str, 1, 255); + first_ttl = xatou_range(first_ttl_str, 1, max_ttl); #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE if (source_route_list) { while (source_route_list) { + len_and_sockaddr *lsa; + if (lsrr >= NGATEWAYS) bb_error_msg_and_die("no more than %d gateways", NGATEWAYS); - getaddr(gwlist + lsrr, llist_pop(&source_route_list)); + lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET); + gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr; + free(lsa); ++lsrr; } optlen = (lsrr + 1) * sizeof(gwlist[0]); } #endif - if (first_ttl > max_ttl) { - bb_error_msg_and_die( - "first ttl (%d) may not be greater than max ttl (%d)", - first_ttl, max_ttl); - } - - minpacket = sizeof(*outip) + sizeof(*outdata) + optlen; - -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - if (useicmp) - minpacket += 8; /* XXX magic number */ - else -#endif - minpacket += sizeof(*outudp); - packlen = minpacket; /* minimum sized packet */ + minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; + if (!(op & OPT_USE_ICMP)) + minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; + packlen = minpacket; /* Process destination and optional packet size */ - switch (argc - optind) { - + argv += optind; + argc -= optind; + switch (argc) { case 2: - packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket); + packlen = xatoul_range(argv[1], minpacket, 32 * 1024); /* Fall through */ - case 1: - hostname = argv[optind]; - hi = gethostinfo(hostname); - setsin(to, hi->addrs[0]); - if (hi->n > 1) - bb_error_msg("warning: %s has multiple addresses; using %s", - hostname, inet_ntoa(to->sin_addr)); - hostname = hi->name; - hi->name = NULL; - freehostinfo(hi); + dest_lsa = xhost2sockaddr(argv[0], port); break; - default: bb_show_usage(); } @@ -1053,8 +696,7 @@ int traceroute_main(int argc, char **argv) /* Ensure the socket fds won't be 0, 1 or 2 */ bb_sanitize_stdio(); - rcvsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - + xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); #if TRACEROUTE_SO_DEBUG if (op & OPT_DEBUG) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, @@ -1064,15 +706,17 @@ int traceroute_main(int argc, char **argv) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)); - sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); - + if (op & OPT_USE_ICMP) + xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); + else + xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE #if defined(IP_OPTIONS) if (lsrr > 0) { unsigned char optlist[MAX_IPOPTLEN]; /* final hop */ - gwlist[lsrr] = to->sin_addr.s_addr; + gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; ++lsrr; /* force 4 byte alignment */ @@ -1081,35 +725,31 @@ int traceroute_main(int argc, char **argv) optlist[1] = IPOPT_LSRR; i = lsrr * sizeof(gwlist[0]); optlist[2] = i + 3; - /* Pointer to LSRR addresses */ + /* pointer to LSRR addresses */ optlist[3] = IPOPT_MINOFF; memcpy(optlist + 4, gwlist, i); - if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, - (char *)optlist, i + sizeof(gwlist[0]))) < 0) { + if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, + (char *)optlist, i + sizeof(gwlist[0])) < 0) { bb_perror_msg_and_die("IP_OPTIONS"); } } #endif /* IP_OPTIONS */ #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */ - #ifdef SO_SNDBUF if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { bb_perror_msg_and_die("SO_SNDBUF"); } #endif -#ifdef IP_HDRINCL - if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0 - && errno != ENOPROTOOPT - ) { - bb_perror_msg_and_die("IP_HDRINCL"); - } -#else #ifdef IP_TOS - if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { + if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { bb_perror_msg_and_die("setsockopt tos %d", tos); } #endif +#ifdef IP_DONTFRAG + if (op & OPT_DONT_FRAGMNT) + setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG, + &const_int_1, sizeof(const_int_1)); #endif #if TRACEROUTE_SO_DEBUG if (op & OPT_DEBUG) @@ -1120,230 +760,167 @@ int traceroute_main(int argc, char **argv) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)); - /* Revert to non-privileged user after opening sockets */ - xsetgid(getgid()); - xsetuid(getuid()); - outip = xzalloc(packlen); - outip->ip_v = IPVERSION; - if (tos_str) - outip->ip_tos = tos; - outip->ip_len = htons(packlen); - outip->ip_off = htons(off); - outp = (unsigned char *)(outip + 1); - outip->ip_dst = to->sin_addr; - - outip->ip_hl = (outp - (unsigned char *)outip) >> 2; - ident = (getpid() & 0xffff) | 0x8000; -#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP - if (useicmp) { - outip->ip_p = IPPROTO_ICMP; - outicmp = (struct icmp *)outp; + if (op & OPT_USE_ICMP) { + ident = getpid() | 0x8000; outicmp->icmp_type = ICMP_ECHO; outicmp->icmp_id = htons(ident); - outdata = (outdata_t *)(outp + 8); /* XXX magic number */ - } else -#endif - { - outip->ip_p = IPPROTO_UDP; - outudp = (struct udphdr *)outp; - outudp->source = htons(ident); - outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen))); - outdata = (outdata_t *)(outudp + 1); + outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); + } else { + outdata = (struct outdata_t *)(outudp + 1); } - /* Get the interface address list */ - n = ifaddrlist(&al); - - /* Look for a specific device */ - if (op & OPT_DEVICE) { - for (i = n; i > 0; --i, ++al) - if (strcmp(device, al->device) == 0) - goto found_dev; - bb_error_msg_and_die("can't find interface %s", device); - } - found_dev: + if (op & OPT_DEVICE) /* hmm, do we need error check? */ + setsockopt_bindtodevice(sndsock, device); - /* Determine our source address */ - if (!(op & OPT_SOURCE)) { - /* - * If a device was specified, use the interface address. - * Otherwise, try to determine our source address. - */ - if (op & OPT_DEVICE) - setsin(from, al->addr); - findsaddr(to, from); - } else { - hi = gethostinfo(source); - source = hi->name; - hi->name = NULL; - /* - * If the device was specified make sure it - * corresponds to the source address specified. - * Otherwise, use the first address (and warn if - * there are more than one). - */ - if (op & OPT_DEVICE) { - for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) - if (*ap == al->addr) - goto found_dev2; - bb_error_msg_and_die("%s is not on interface %s", - source, device); - found_dev2: - setsin(from, *ap); - } else { - setsin(from, hi->addrs[0]); - if (hi->n > 1) - bb_error_msg( - "warning: %s has multiple addresses; using %s", - source, inet_ntoa(from->sin_addr)); - } - freehostinfo(hi); + if (op & OPT_SOURCE) { + len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); + /* Ping does this (why?) */ + if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, + &source_lsa->u.sa, source_lsa->len)) + bb_error_msg_and_die("can't set multicast source interface"); +//TODO: we can query source port we bound to, +// and check it in replies... if we care enough + xbind(sndsock, &source_lsa->u.sa, source_lsa->len); + free(source_lsa); } - outip->ip_src = from->sin_addr; -#ifndef IP_HDRINCL - xbind(sndsock, (struct sockaddr *)from, sizeof(*from)); -#endif + /* Revert to non-privileged user after opening sockets */ + xsetgid(getgid()); + xsetuid(getuid()); - printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); + printf("traceroute to %s (%s)", argv[0], + xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); if (op & OPT_SOURCE) printf(" from %s", source); printf(", %d hops max, %d byte packets\n", max_ttl, packlen); - fflush(stdout); for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { +//TODO: make it protocol agnostic (get rid of sockaddr_in) + struct sockaddr_in from; uint32_t lastaddr = 0; - int gotlastaddr = 0; + int probe; + int unreachable = 0; /* counter */ + int gotlastaddr = 0; /* flags */ int got_there = 0; - int unreachable = 0; - int sentfirst = 0; + int first = 1; - printf("%2d ", ttl); + printf("%2d", ttl); for (probe = 0; probe < nprobes; ++probe) { int cc; unsigned t1; unsigned t2; struct ip *ip; - if (sentfirst && pausemsecs > 0) + if (!first && pausemsecs > 0) usleep(pausemsecs * 1000); + fflush(stdout); + t1 = monotonic_us(); send_probe(++seq, ttl); - ++sentfirst; - while ((cc = wait_for_reply(rcvsock, from)) != 0) { + first = 0; + + while ((cc = wait_for_reply(&from)) != 0) { t2 = monotonic_us(); - i = packet_ok(packet, cc, from, seq); + i = packet_ok(cc, &from, seq); /* Skip short packet */ if (i == 0) continue; - if (!gotlastaddr || - from->sin_addr.s_addr != lastaddr) { - print(packet, cc, from); - lastaddr = from->sin_addr.s_addr; - ++gotlastaddr; + if (!gotlastaddr + || from.sin_addr.s_addr != lastaddr + ) { + print(cc, &from); + lastaddr = from.sin_addr.s_addr; + gotlastaddr = 1; } print_delta_ms(t1, t2); - ip = (struct ip *)packet; + ip = (struct ip *)recv_pkt; if (op & OPT_TTL_FLAG) printf(" (%d)", ip->ip_ttl); if (i == -2) { if (ip->ip_ttl <= 1) printf(" !"); - ++got_there; + got_there = 1; break; } /* time exceeded in transit */ if (i == -1) break; - code = i - 1; - switch (code) { - + i--; + switch (i) { case ICMP_UNREACH_PORT: if (ip->ip_ttl <= 1) printf(" !"); - ++got_there; + got_there = 1; break; - case ICMP_UNREACH_NET: - ++unreachable; printf(" !N"); + ++unreachable; break; - case ICMP_UNREACH_HOST: - ++unreachable; printf(" !H"); + ++unreachable; break; - case ICMP_UNREACH_PROTOCOL: - ++got_there; printf(" !P"); + got_there = 1; break; - case ICMP_UNREACH_NEEDFRAG: - ++unreachable; printf(" !F-%d", pmtu); + ++unreachable; break; - case ICMP_UNREACH_SRCFAIL: - ++unreachable; printf(" !S"); + ++unreachable; break; - case ICMP_UNREACH_FILTER_PROHIB: case ICMP_UNREACH_NET_PROHIB: /* misuse */ - ++unreachable; printf(" !A"); + ++unreachable; break; - case ICMP_UNREACH_HOST_PROHIB: - ++unreachable; printf(" !C"); + ++unreachable; break; - case ICMP_UNREACH_HOST_PRECEDENCE: - ++unreachable; printf(" !V"); + ++unreachable; break; - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - ++unreachable; printf(" !C"); + ++unreachable; break; - case ICMP_UNREACH_NET_UNKNOWN: case ICMP_UNREACH_HOST_UNKNOWN: - ++unreachable; printf(" !U"); + ++unreachable; break; - case ICMP_UNREACH_ISOLATED: - ++unreachable; printf(" !I"); + ++unreachable; break; - case ICMP_UNREACH_TOSNET: case ICMP_UNREACH_TOSHOST: - ++unreachable; printf(" !T"); + ++unreachable; break; - default: + printf(" !<%d>", i); ++unreachable; - printf(" !<%d>", code); break; } break; } if (cc == 0) - printf(" *"); - (void)fflush(stdout); + printf(" *"); } bb_putchar('\n'); - if (got_there || - (unreachable > 0 && unreachable >= nprobes - 1)) + if (got_there + || (unreachable > 0 && unreachable >= nprobes - 1) + ) { break; + } } return 0; } diff --git a/release/src/router/busybox/networking/tunctl.c b/release/src/router/busybox/networking/tunctl.c new file mode 100644 index 0000000000..a8e5270ad5 --- /dev/null +++ b/release/src/router/busybox/networking/tunctl.c @@ -0,0 +1,139 @@ +/* vi: set sw=4 ts=4: */ +/* + * tun devices controller + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Original code: + * Jeff Dike + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include +#include +#include +#include "libbb.h" + +/* TUNSETGROUP appeared in 2.6.23 */ +#ifndef TUNSETGROUP +#define TUNSETGROUP _IOW('T', 206, int) +#endif + +#define IOCTL(a, b, c) ioctl_or_perror_and_die(a, b, c, NULL) + +#if 1 + +int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tunctl_main(int argc UNUSED_PARAM, char **argv) +{ + struct ifreq ifr; + int fd; + const char *opt_name = "tap%d"; + const char *opt_device = "/dev/net/tun"; +#if ENABLE_FEATURE_TUNCTL_UG + const char *opt_user, *opt_group; + long user = -1, group = -1; +#endif + unsigned opts; + + enum { + OPT_f = 1 << 0, // control device name (/dev/net/tun) + OPT_t = 1 << 1, // create named interface + OPT_d = 1 << 2, // delete named interface +#if ENABLE_FEATURE_TUNCTL_UG + OPT_u = 1 << 3, // set new interface owner + OPT_g = 1 << 4, // set new interface group + OPT_b = 1 << 5, // brief output +#endif + }; + + opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d + opts = getopt32(argv, "f:t:d:" USE_FEATURE_TUNCTL_UG("u:g:b"), + &opt_device, &opt_name, &opt_name + USE_FEATURE_TUNCTL_UG(, &opt_user, &opt_group)); + + // select device + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy_IFNAMSIZ(ifr.ifr_name, opt_name); + + // open device + fd = xopen(opt_device, O_RDWR); + IOCTL(fd, TUNSETIFF, (void *)&ifr); + + // delete? + if (opts & OPT_d) { + IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)0); + bb_info_msg("Set '%s' %spersistent", ifr.ifr_name, "non"); + return EXIT_SUCCESS; + } + + // create +#if ENABLE_FEATURE_TUNCTL_UG + if (opts & OPT_g) { + group = xgroup2gid(opt_group); + IOCTL(fd, TUNSETGROUP, (void *)(uintptr_t)group); + } else + user = geteuid(); + if (opts & OPT_u) + user = xuname2uid(opt_user); + IOCTL(fd, TUNSETOWNER, (void *)(uintptr_t)user); +#endif + IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)1); + + // show info +#if ENABLE_FEATURE_TUNCTL_UG + if (opts & OPT_b) { + puts(ifr.ifr_name); + } else { + printf("Set '%s' %spersistent", ifr.ifr_name, ""); + printf(" and owned by uid %ld", user); + if (group != -1) + printf(" gid %ld", group); + bb_putchar('\n'); + } +#else + puts(ifr.ifr_name); +#endif + return EXIT_SUCCESS; +} + +#else + +/* -210 bytes: */ + +int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tunctl_main(int argc UNUSED_PARAM, char **argv) +{ + struct ifreq ifr; + int fd; + const char *opt_name = "tap%d"; + const char *opt_device = "/dev/net/tun"; + unsigned opts; + + enum { + OPT_f = 1 << 0, // control device name (/dev/net/tun) + OPT_t = 1 << 1, // create named interface + OPT_d = 1 << 2, // delete named interface + }; + + opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d + opts = getopt32(argv, "f:t:d:u:g:b", // u, g, b accepted and ignored + &opt_device, &opt_name, &opt_name, NULL, NULL); + + // set interface name + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy_IFNAMSIZ(ifr.ifr_name, opt_name); + + // open device + fd = xopen(opt_device, O_RDWR); + IOCTL(fd, TUNSETIFF, (void *)&ifr); + + // create or delete interface + IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)(0 == (opts & OPT_d))); + + return EXIT_SUCCESS; +} + +#endif diff --git a/release/src/router/busybox/networking/udhcp/Config.in b/release/src/router/busybox/networking/udhcp/Config.in index 55cefb6730..d4b76e188a 100644 --- a/release/src/router/busybox/networking/udhcp/Config.in +++ b/release/src/router/busybox/networking/udhcp/Config.in @@ -74,14 +74,14 @@ config FEATURE_UDHCP_PORT At the cost of ~300 bytes, enables -P port option. This feature is typically not needed. -config FEATURE_UDHCP_DEBUG +config UDHCP_DEBUG bool "Compile udhcp with noisy debugging messages" default n depends on APP_UDHCPD || APP_UDHCPC help If selected, udhcpd will output extra debugging output. -config FEATURE_RFC3397 +config FEATURE_UDHCP_RFC3397 bool "Support for RFC3397 domain search (experimental)" default n depends on APP_UDHCPD || APP_UDHCPC @@ -89,7 +89,7 @@ config FEATURE_RFC3397 If selected, both client and server will support passing of domain search lists via option 119, specified in RFC3397. -config DHCPC_DEFAULT_SCRIPT +config UDHCPC_DEFAULT_SCRIPT string "Absolute path to config script" default "/usr/share/udhcpc/default.script" depends on APP_UDHCPC diff --git a/release/src/router/busybox/networking/udhcp/Kbuild b/release/src/router/busybox/networking/udhcp/Kbuild index f4be6dfc1b..e938076f76 100644 --- a/release/src/router/busybox/networking/udhcp/Kbuild +++ b/release/src/router/busybox/networking/udhcp/Kbuild @@ -22,4 +22,4 @@ lib-$(CONFIG_APP_UDHCPD) += dhcpd.o arpping.o files.o leases.o \ lib-$(CONFIG_APP_DUMPLEASES) += dumpleases.o lib-$(CONFIG_APP_DHCPRELAY) += dhcprelay.o -lib-$(CONFIG_FEATURE_RFC3397) += domain_codec.o +lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o diff --git a/release/src/router/busybox/networking/udhcp/arpping.c b/release/src/router/busybox/networking/udhcp/arpping.c index 44815ad74e..b10bff6514 100644 --- a/release/src/router/busybox/networking/udhcp/arpping.c +++ b/release/src/router/busybox/networking/udhcp/arpping.c @@ -4,6 +4,8 @@ * * Mostly stolen from: dhcpcd - DHCP client daemon * by Yoichi Hariguchi + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include @@ -39,7 +41,7 @@ enum { /* Returns 1 if no reply received */ -int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) +int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) { int timeout_ms; struct pollfd pfd[1]; diff --git a/release/src/router/busybox/networking/udhcp/clientpacket.c b/release/src/router/busybox/networking/udhcp/clientpacket.c index 3e45619466..3f9522ff8b 100644 --- a/release/src/router/busybox/networking/udhcp/clientpacket.c +++ b/release/src/router/busybox/networking/udhcp/clientpacket.c @@ -25,7 +25,7 @@ /* Create a random xid */ -uint32_t random_xid(void) +uint32_t FAST_FUNC random_xid(void) { static smallint initialized; @@ -78,10 +78,36 @@ static void add_param_req_option(struct dhcpMessage *packet) } } +/* RFC 2131 + * 4.4.4 Use of broadcast and unicast + * + * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM + * messages, unless the client knows the address of a DHCP server. + * The client unicasts DHCPRELEASE messages to the server. Because + * the client is declining the use of the IP address supplied by the server, + * the client broadcasts DHCPDECLINE messages. + * + * When the DHCP client knows the address of a DHCP server, in either + * INIT or REBOOTING state, the client may use that address + * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address. + * The client may also use unicast to send DHCPINFORM messages + * to a known DHCP server. If the client receives no response to DHCP + * messages sent to the IP address of a known DHCP server, the DHCP + * client reverts to using the IP broadcast address. + */ + +static int raw_bcast_from_client_config_ifindex(struct dhcpMessage *packet) +{ + return udhcp_send_raw_packet(packet, + /*src*/ INADDR_ANY, CLIENT_PORT, + /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, + client_config.ifindex); +} + #if ENABLE_FEATURE_UDHCPC_ARPING -/* Unicast a DHCP decline message */ -int send_decline(uint32_t xid, uint32_t server, uint32_t requested) +/* Broadcast a DHCP decline message */ +int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) { struct dhcpMessage packet; @@ -92,13 +118,12 @@ int send_decline(uint32_t xid, uint32_t server, uint32_t requested) bb_info_msg("Sending decline..."); - return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + return raw_bcast_from_client_config_ifindex(&packet); } #endif /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ -int send_discover(uint32_t xid, uint32_t requested) +int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) { struct dhcpMessage packet; @@ -114,13 +139,15 @@ int send_discover(uint32_t xid, uint32_t requested) add_param_req_option(&packet); bb_info_msg("Sending discover..."); - return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + return raw_bcast_from_client_config_ifindex(&packet); } /* Broadcasts a DHCP request message */ -int send_selecting(uint32_t xid, uint32_t server, uint32_t requested) +/* RFC 2131 3.1 paragraph 3: + * "The client _broadcasts_ a DHCPREQUEST message..." + */ +int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested) { struct dhcpMessage packet; struct in_addr addr; @@ -134,13 +161,12 @@ int send_selecting(uint32_t xid, uint32_t server, uint32_t requested) addr.s_addr = requested; bb_info_msg("Sending select for %s...", inet_ntoa(addr)); - return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + return raw_bcast_from_client_config_ifindex(&packet); } /* Unicasts or broadcasts a DHCP renew message */ -int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) +int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) { struct dhcpMessage packet; @@ -151,15 +177,16 @@ int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) add_param_req_option(&packet); bb_info_msg("Sending renew..."); if (server) - return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); + return udhcp_send_kernel_packet(&packet, + ciaddr, CLIENT_PORT, + server, SERVER_PORT); - return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + return raw_bcast_from_client_config_ifindex(&packet); } /* Unicasts a DHCP release message */ -int send_release(uint32_t server, uint32_t ciaddr) +int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr) { struct dhcpMessage packet; @@ -175,7 +202,7 @@ int send_release(uint32_t server, uint32_t ciaddr) /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ -int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd) +int FAST_FUNC udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd) { int bytes; struct udp_dhcp_packet packet; diff --git a/release/src/router/busybox/networking/udhcp/clientsocket.c b/release/src/router/busybox/networking/udhcp/clientsocket.c index 0e13824b65..1dcc10570a 100644 --- a/release/src/router/busybox/networking/udhcp/clientsocket.c +++ b/release/src/router/busybox/networking/udhcp/clientsocket.c @@ -36,7 +36,7 @@ #include "dhcpd.h" #include "dhcpc.h" -int raw_socket(int ifindex) +int FAST_FUNC udhcp_raw_socket(int ifindex) { int fd; struct sockaddr_ll sock; diff --git a/release/src/router/busybox/networking/udhcp/common.h b/release/src/router/busybox/networking/udhcp/common.h index ef233c4bcb..0cea7aff55 100644 --- a/release/src/router/busybox/networking/udhcp/common.h +++ b/release/src/router/busybox/networking/udhcp/common.h @@ -6,19 +6,16 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - -#ifndef _COMMON_H -#define _COMMON_H +#ifndef UDHCP_COMMON_H +#define UDHCP_COMMON_H 1 #include "libbb.h" #include #include -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -#define DEFAULT_SCRIPT CONFIG_DHCPC_DEFAULT_SCRIPT +#define DEFAULT_SCRIPT CONFIG_UDHCPC_DEFAULT_SCRIPT extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ @@ -27,21 +24,23 @@ extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ #define DHCP_OPTIONS_BUFSIZE 308 struct dhcpMessage { - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - uint32_t xid; - uint16_t secs; - uint16_t flags; - uint32_t ciaddr; - uint32_t yiaddr; - uint32_t siaddr; - uint32_t giaddr; - uint8_t chaddr[16]; - uint8_t sname[64]; - uint8_t file[128]; - uint32_t cookie; + uint8_t op; /* 1 = BOOTREQUEST, 2 = 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; /* unique id */ + uint16_t secs; /* elapsed since client began acquisition/renewal */ + uint16_t flags; /* only one flag so far: */ +#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */ + uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */ + uint32_t yiaddr; /* 'your' (client) IP address */ + uint32_t siaddr; /* IP address of next server to use in bootstrap, + * returned in DHCPOFFER, DHCPACK by server */ + uint32_t giaddr; /* relay agent IP address */ + uint8_t chaddr[16];/* link-layer client hardware address (MAC) */ + uint8_t sname[64]; /* server host name (ASCIZ) */ + uint8_t file[128]; /* boot file name (ASCIZ) */ + uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */ uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; } PACKED; @@ -57,26 +56,27 @@ struct BUG_bad_sizeof_struct_udp_dhcp_packet { [(sizeof(struct udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; }; -uint16_t udhcp_checksum(void *addr, int count); +uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; -void udhcp_init_header(struct dhcpMessage *packet, char type); +void udhcp_init_header(struct dhcpMessage *packet, char type) FAST_FUNC; /*int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd); - in dhcpc.h */ -int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd); +int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) FAST_FUNC; int udhcp_send_raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port, - const uint8_t *dest_arp, int ifindex); + uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, + int ifindex) FAST_FUNC; + int udhcp_send_kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port); + uint32_t dest_ip, int dest_port) FAST_FUNC; extern int minpkt; // zzz /**/ -void udhcp_run_script(struct dhcpMessage *packet, const char *name); +void udhcp_run_script(struct dhcpMessage *packet, const char *name) FAST_FUNC; // Still need to clean these up... @@ -85,27 +85,22 @@ void udhcp_run_script(struct dhcpMessage *packet, const char *name); #define end_option udhcp_end_option #define add_option_string udhcp_add_option_string #define add_simple_option udhcp_add_simple_option -/* from socket.h */ -#define listen_socket udhcp_listen_socket -#define read_interface udhcp_read_interface - -void udhcp_sp_setup(void); -int udhcp_sp_fd_set(fd_set *rfds, int extra_fd); -int udhcp_sp_read(const fd_set *rfds); -int raw_socket(int ifindex); -int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp); -int listen_socket(/*uint32_t ip,*/ int port, const char *inf); + +void udhcp_sp_setup(void) FAST_FUNC; +int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC; +int udhcp_sp_read(const fd_set *rfds) FAST_FUNC; +int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) FAST_FUNC; +int udhcp_raw_socket(int ifindex) FAST_FUNC; +int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; /* Returns 1 if no reply received */ -int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface); +int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) FAST_FUNC; -#if ENABLE_FEATURE_UDHCP_DEBUG +#if ENABLE_UDHCP_DEBUG # define DEBUG(str, args...) bb_info_msg("### " str, ## args) #else # define DEBUG(str, args...) do {;} while (0) #endif -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.c b/release/src/router/busybox/networking/udhcp/dhcpc.c index 06c522031c..e9e37460f4 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpc.c +++ b/release/src/router/busybox/networking/udhcp/dhcpc.c @@ -43,11 +43,17 @@ static void change_listen_mode(int new_mode) { DEBUG("entering %s listen mode", new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); + + listen_mode = new_mode; if (sockfd >= 0) { close(sockfd); sockfd = -1; } - listen_mode = new_mode; + if (new_mode == LISTEN_KERNEL) + sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); + else if (new_mode != LISTEN_NONE) + sockfd = udhcp_raw_socket(client_config.ifindex); + /* else LISTEN_NONE: sockfd stay closed */ } @@ -270,18 +276,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } if (opt & OPT_m) minpkt = 1; // zzz - if (read_interface(client_config.interface, &client_config.ifindex, + if (udhcp_read_interface(client_config.interface, &client_config.ifindex, NULL, client_config.arp)) return 1; #if !BB_MMU /* on NOMMU reexec (i.e., background) early */ if (!(opt & OPT_f)) { bb_daemonize_or_rexec(0 /* flags */, argv); - logmode = 0; + logmode = LOGMODE_NONE; } #endif if (opt & OPT_S) { - openlog(applet_name, LOG_PID, LOG_LOCAL0); + openlog(applet_name, LOG_PID, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } @@ -320,15 +326,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * on sockfd. * "continue" statements in code below jump to the top of the loop. */ - unsigned timestamp_before_wait = 0; - for (;;) { + for (;;) { + /* 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:"). */ - if (listen_mode != LISTEN_NONE && sockfd < 0) { - if (listen_mode == LISTEN_KERNEL) - sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); - else - sockfd = raw_socket(client_config.ifindex); - } max_fd = udhcp_sp_fd_set(&rfds, sockfd); tv.tv_sec = timeout - already_waited_sec; @@ -351,7 +361,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * resend discover/renew/whatever */ if (retval == 0) { - /* We will restart wait afresh in any case */ + /* We will restart the wait in any case */ already_waited_sec = 0; switch (state) { @@ -366,6 +376,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) packet_num++; continue; } + leasefail: udhcp_run_script(NULL, "leasefail"); #if BB_MMU /* -b is not supported on NOMMU */ if (opt & OPT_b) { /* background if no lease */ @@ -391,7 +402,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (state == RENEW_REQUESTED) /* unicast */ send_renew(xid, server_addr, requested_ip); else /* broadcast */ - send_selecting(xid, server_addr, requested_ip); + send_select(xid, server_addr, requested_ip); timeout = discover_timeout; packet_num++; @@ -401,13 +412,20 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (state == RENEW_REQUESTED) udhcp_run_script(NULL, "deconfig"); change_listen_mode(LISTEN_RAW); + /* "discover...select...discover..." loops + * were seen in the wild. Treat them similarly + * to "no response to discover" case */ + if (state == REQUESTING) { + state = INIT_SELECTING; + goto leasefail; + } state = INIT_SELECTING; timeout = 0; packet_num = 0; continue; case BOUND: /* Half of the lease passed, time to enter renewing state */ - change_listen_mode(LISTEN_RAW); // was: LISTEN_KERNEL -- zzz + change_listen_mode(LISTEN_KERNEL); DEBUG("Entering renew state"); state = RENEWING; /* fall right through */ @@ -427,7 +445,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * try to find DHCP server using broadcast */ if (timeout > 0) { /* send a request packet */ - send_renew(xid, 0, requested_ip); /* broadcast */ + send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); /* broadcast */ timeout >>= 1; continue; } @@ -447,7 +465,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } /* select() didn't timeout, something did happen. */ - /* Is is a packet? */ + /* Is it a packet? */ if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) { int len; /* A packet is ready, read it */ @@ -469,7 +487,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) continue; if (packet.xid != xid) { - DEBUG("Ignoring XID %x (our xid is %x)", + DEBUG("Ignoring xid %x (our xid is %x)", (unsigned)packet.xid, (unsigned)xid); continue; } @@ -498,7 +516,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* still selecting - this server looks bad */ } /* it IS unaligned sometimes, don't "optimize" */ - server_addr = get_unaligned_u32p((uint32_t*)temp); + move_from_unaligned32(server_addr, temp); xid = packet.xid; requested_ip = packet.yiaddr; @@ -519,8 +537,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("no lease time with ACK, using 1 hour lease"); lease_seconds = 60 * 60; } else { - /* can be misaligned, thus memcpy */ - memcpy(&lease_seconds, temp, 4); + /* 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 */ @@ -528,6 +546,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { +/* RFC 2131 3.1 paragraph 5: + * "The client receives the DHCPACK message with configuration + * parameters. The client SHOULD perform a final check on the + * parameters (e.g., ARP for allocated network address), and notes + * the duration of the lease specified in the DHCPACK message. At this + * point, the client is configured. If the client detects that the + * address is already in use (e.g., through the use of ARP), + * the client MUST send a DHCPDECLINE message to the server and restarts + * the configuration process..." */ if (!arpping(packet.yiaddr, (uint32_t) 0, client_config.arp, @@ -559,7 +586,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } requested_ip = packet.yiaddr; udhcp_run_script(&packet, - ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); + ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); state = BOUND; change_listen_mode(LISTEN_NONE); diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.h b/release/src/router/busybox/networking/udhcp/dhcpc.h index 04e320cf0d..7b77942668 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpc.h +++ b/release/src/router/busybox/networking/udhcp/dhcpc.h @@ -1,12 +1,9 @@ /* vi: set sw=4 ts=4: */ /* dhcpc.h */ +#ifndef UDHCP_DHCPC_H +#define UDHCP_DHCPC_H 1 -#ifndef _DHCPC_H -#define _DHCPC_H - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct client_config_t { uint8_t arp[6]; /* Our arp address */ @@ -37,20 +34,18 @@ struct client_config_t { /*** clientpacket.h ***/ -uint32_t random_xid(void); -int send_discover(uint32_t xid, uint32_t requested); -int send_selecting(uint32_t xid, uint32_t server, uint32_t requested); +uint32_t random_xid(void) FAST_FUNC; +int send_discover(uint32_t xid, uint32_t requested) FAST_FUNC; +int send_select(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; #if ENABLE_FEATURE_UDHCPC_ARPING -int send_decline(uint32_t xid, uint32_t server, uint32_t requested); +int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; #endif -int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr); -int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr); -int send_release(uint32_t server, uint32_t ciaddr); +int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; +int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; +int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC; -int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd); +int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/udhcp/dhcpd.c b/release/src/router/busybox/networking/udhcp/dhcpd.c index 0cd6b9d505..a82fd8c478 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpd.c +++ b/release/src/router/busybox/networking/udhcp/dhcpd.c @@ -26,11 +26,12 @@ int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpd_main(int argc UNUSED_PARAM, char **argv) { fd_set rfds; - struct timeval tv; - int server_socket = -1, bytes, retval, max_sock; + int server_socket = -1, retval, max_sock; struct dhcpMessage packet; uint8_t *state, *server_id, *requested; - uint32_t server_id_align, requested_align, static_lease_ip; + uint32_t server_id_aligned = server_id_aligned; /* for compiler */ + uint32_t requested_aligned = requested_aligned; + uint32_t static_lease_ip; unsigned timeout_end; unsigned num_ips; unsigned opt; @@ -45,14 +46,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "fS" USE_FEATURE_UDHCP_PORT("P:", &str_P)); argv += optind; - if (!(opt & 1)) { /* no -f */ bb_daemonize_or_rexec(0, argv); - logmode &= ~LOGMODE_STDIO; + logmode = LOGMODE_NONE; } - if (opt & 2) { /* -S */ - openlog(applet_name, LOG_PID, LOG_LOCAL0); + openlog(applet_name, LOG_PID, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } #if ENABLE_FEATURE_UDHCP_PORT @@ -79,7 +78,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) option = find_option(server_config.options, DHCP_LEASE_TIME); server_config.lease = LEASE_TIME; if (option) { - memcpy(&server_config.lease, option->data + 2, 4); + move_from_unaligned32(server_config.lease, option->data + 2); server_config.lease = ntohl(server_config.lease); } @@ -94,7 +93,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) leases = xzalloc(server_config.max_leases * sizeof(*leases)); read_leases(server_config.lease_file); - if (read_interface(server_config.interface, &server_config.ifindex, + if (udhcp_read_interface(server_config.interface, &server_config.ifindex, &server_config.server, server_config.arp)) { retval = 1; goto ret; @@ -105,9 +104,11 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) timeout_end = monotonic_sec() + server_config.auto_time; while (1) { /* loop until universe collapses */ + int bytes; + struct timeval tv; if (server_socket < 0) { - server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT, + server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_config.interface); } @@ -141,12 +142,15 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) case SIGTERM: bb_info_msg("Received a SIGTERM"); goto ret0; - case 0: break; /* no signal */ - default: continue; /* signal or error (probably EINTR) */ + case 0: /* no signal: read a packet */ + break; + default: /* signal or error (probably EINTR): back to select */ + continue; } - bytes = udhcp_recv_kernel_packet(&packet, server_socket); /* this waits for a packet - idle */ + bytes = udhcp_recv_kernel_packet(&packet, server_socket); if (bytes < 0) { + /* bytes can also be -2 ("bad packet data") */ if (bytes == -1 && errno != EINTR) { DEBUG("error on read, %s, reopening socket", strerror(errno)); close(server_socket); @@ -163,7 +167,6 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) /* Look for a static lease */ static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); - if (static_lease_ip) { bb_info_msg("Found static lease: %x", static_lease_ip); @@ -190,21 +193,24 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) requested = get_option(&packet, DHCP_REQUESTED_IP); server_id = get_option(&packet, DHCP_SERVER_ID); - if (requested) memcpy(&requested_align, requested, 4); - if (server_id) memcpy(&server_id_align, server_id, 4); + if (requested) + move_from_unaligned32(requested_aligned, requested); + if (server_id) + move_from_unaligned32(server_id_aligned, server_id); if (lease) { if (server_id) { /* SELECTING State */ - DEBUG("server_id = %08x", ntohl(server_id_align)); - if (server_id_align == server_config.server && requested - && requested_align == lease->yiaddr + DEBUG("server_id = %08x", ntohl(server_id_aligned)); + if (server_id_aligned == server_config.server + && requested + && requested_aligned == lease->yiaddr ) { send_ACK(&packet, lease->yiaddr); } } else if (requested) { /* INIT-REBOOT State */ - if (lease->yiaddr == requested_align) + if (lease->yiaddr == requested_aligned) send_ACK(&packet, lease->yiaddr); else send_NAK(&packet); @@ -221,7 +227,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) } else if (requested) { /* INIT-REBOOT State */ - lease = find_lease_by_yiaddr(requested_align); + lease = find_lease_by_yiaddr(requested_aligned); if (lease) { if (lease_expired(lease)) { /* probably best if we drop this lease */ @@ -230,7 +236,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) } else send_NAK(&packet); } else { - uint32_t r = ntohl(requested_align); + uint32_t r = ntohl(requested_aligned); if (r < server_config.start_ip || r > server_config.end_ip ) { @@ -247,13 +253,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) DEBUG("Received DECLINE"); if (lease) { memset(lease->chaddr, 0, 16); - lease->expires = time(0) + server_config.decline_time; + lease->expires = time(NULL) + server_config.decline_time; } break; case DHCPRELEASE: DEBUG("Received RELEASE"); if (lease) - lease->expires = time(0); + lease->expires = time(NULL); break; case DHCPINFORM: DEBUG("Received INFORM"); diff --git a/release/src/router/busybox/networking/udhcp/dhcpd.h b/release/src/router/busybox/networking/udhcp/dhcpd.h index 87e1afc1fe..9667c61e81 100644 --- a/release/src/router/busybox/networking/udhcp/dhcpd.h +++ b/release/src/router/busybox/networking/udhcp/dhcpd.h @@ -1,12 +1,9 @@ /* vi: set sw=4 ts=4: */ /* dhcpd.h */ +#ifndef UDHCP_DHCPD_H +#define UDHCP_DHCPD_H 1 -#ifndef _DHCPD_H -#define _DHCPD_H - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /************************************/ /* Defaults _you_ may want to tweak */ @@ -26,8 +23,8 @@ struct option_set { struct static_lease { struct static_lease *next; - uint8_t *mac; - uint32_t *ip; + uint32_t ip; + uint8_t mac[6]; }; struct server_config_t { @@ -42,8 +39,11 @@ struct server_config_t { char *interface; /* The name of the interface to use */ int ifindex; /* Index number of the interface to use */ uint8_t arp[6]; /* Our arp address */ - char remaining; /* should the lease file be interpreted as lease time remaining, or - * as the time the lease expires */ +// disabled: dumpleases has no way of knowing this value, +// and will break if it's off. Now it's on always. +// char remaining; /* Should the lease time in lease file +// * be written as lease time remaining, or +// * as the absolute time the lease expires */ uint32_t lease; /* lease time in seconds (host order) */ uint32_t max_leases; /* maximum number of leases (including reserved address) */ uint32_t auto_time; /* how long should udhcpd wait before writing a config file. @@ -52,11 +52,11 @@ struct server_config_t { * decline message */ uint32_t conflict_time; /* how long an arp conflict offender is leased for */ uint32_t offer_time; /* how long an offered address is reserved */ - uint32_t min_lease; /* minimum lease a client can request */ + uint32_t min_lease; /* minimum lease time a client can request */ + uint32_t siaddr; /* next server bootp option */ char *lease_file; char *pidfile; char *notify_file; /* What to run whenever leases are written */ - uint32_t siaddr; /* next server bootp option */ char *sname; /* bootp server name */ char *boot_file; /* bootp boot file option */ struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ @@ -71,55 +71,66 @@ struct server_config_t { #define SERVER_PORT 67 #endif -extern struct dhcpOfferedAddr *leases; - /*** leases.h ***/ +typedef uint32_t leasetime_t; +typedef int32_t signed_leasetime_t; + struct dhcpOfferedAddr { uint8_t chaddr[16]; - uint32_t yiaddr; /* network order */ - uint32_t expires; /* host order */ + /* In network order */ + uint32_t yiaddr; + /* Unix time when lease expires, regardless of value of + * server_config.remaining. Kept in memory in host order. + * When written to file, converted to network order + * and optionally adjusted (current time subtracted) + * if server_config.remaining = 1 */ + leasetime_t expires; + uint8_t hostname[20]; /* (size is a multiply of 4) */ }; -struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease); -int lease_expired(struct dhcpOfferedAddr *lease); -struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr); -struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr); -uint32_t find_address(int check_expired); +extern struct dhcpOfferedAddr *leases; + +struct dhcpOfferedAddr *add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname + ) FAST_FUNC; +int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; +struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; +struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; +uint32_t find_free_or_expired_address(void) FAST_FUNC; /*** static_leases.h ***/ /* Config file will pass static lease info to this function which will add it * to a data structure that can be searched later */ -int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip); +void addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip) FAST_FUNC; /* Check to see if a mac has an associated static lease */ -uint32_t getIpByMac(struct static_lease *lease_struct, void *arg); +uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) FAST_FUNC; /* Check to see if an ip is reserved as a static ip */ -uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip); +int reservedIp(struct static_lease *lease_struct, uint32_t ip) FAST_FUNC; /* Print out static leases just to check what's going on (debug code) */ -void printStaticLeases(struct static_lease **lease_struct); +void printStaticLeases(struct static_lease **lease_struct) FAST_FUNC; /*** serverpacket.h ***/ -int send_offer(struct dhcpMessage *oldpacket); -int send_NAK(struct dhcpMessage *oldpacket); -int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr); -int send_inform(struct dhcpMessage *oldpacket); +int send_offer(struct dhcpMessage *oldpacket) FAST_FUNC; +int send_NAK(struct dhcpMessage *oldpacket) FAST_FUNC; +int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) FAST_FUNC; +int send_inform(struct dhcpMessage *oldpacket) FAST_FUNC; /*** files.h ***/ -void read_config(const char *file); -void write_leases(void); -void read_leases(const char *file); -struct option_set *find_option(struct option_set *opt_list, uint8_t code); +void read_config(const char *file) FAST_FUNC; +void write_leases(void) FAST_FUNC; +void read_leases(const char *file) FAST_FUNC; +struct option_set *find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif +POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/release/src/router/busybox/networking/udhcp/dhcprelay.c b/release/src/router/busybox/networking/udhcp/dhcprelay.c index 90ecf48319..53540d1ab9 100644 --- a/release/src/router/busybox/networking/udhcp/dhcprelay.c +++ b/release/src/router/busybox/networking/udhcp/dhcprelay.c @@ -13,7 +13,6 @@ #include "common.h" #include "options.h" -/* constants */ #define SERVER_PORT 67 #define SELECT_TIMEOUT 5 /* select timeout in sec. */ #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ @@ -149,19 +148,21 @@ static char **get_client_devices(char *dev_list, int *client_number) } -/* Creates listen sockets (in fds) and returns numerically max fd. */ -static int init_sockets(char **client, int num_clients, - char *server, int *fds) +/* Creates listen sockets (in fds) bound to client and server ifaces, + * and returns numerically max fd. + */ +static int init_sockets(char **client_ifaces, int num_clients, + char *server_iface, int *fds) { int i, n; /* talk to real server on bootps */ - fds[0] = listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server); + fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_iface); n = fds[0]; for (i = 1; i < num_clients; i++) { /* listen for clients on bootps */ - fds[i] = listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client[i-1]); + fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]); if (fds[i] > n) n = fds[i]; } @@ -170,11 +171,11 @@ static int init_sockets(char **client, int num_clients, /** - * pass_on() - forwards dhcp packets from client to server + * pass_to_server() - forwards dhcp packets from client to server * p - packet to send * client - number of the client */ -static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds, +static void pass_to_server(struct dhcpMessage *p, int packet_len, int client, int *fds, struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) { int res, type; @@ -193,19 +194,19 @@ static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds, item = xid_add(p->xid, client_addr, client); /* forward request to LAN (server) */ + errno = 0; res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr, sizeof(struct sockaddr_in)); if (res != packet_len) { - bb_perror_msg("pass_on"); - return; + bb_perror_msg("sendto"); } } /** - * pass_back() - forwards dhcp packets from server to client + * pass_to_client() - forwards dhcp packets from server to client * p - packet to send */ -static void pass_back(struct dhcpMessage *p, int packet_len, int *fds) +static void pass_to_client(struct dhcpMessage *p, int packet_len, int *fds) { int res, type; struct xid_item *item; @@ -224,10 +225,11 @@ static void pass_back(struct dhcpMessage *p, int packet_len, int *fds) if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); - res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip), - sizeof(item->ip)); + errno = 0; + res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*) &(item->ip), + sizeof(item->ip)); if (res != packet_len) { - bb_perror_msg("pass_back"); + bb_perror_msg("sendto"); return; } @@ -235,20 +237,53 @@ static void pass_back(struct dhcpMessage *p, int packet_len, int *fds) xid_del(p->xid); } -static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients, - struct sockaddr_in *server_addr, uint32_t gw_ip) NORETURN; -static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients, - struct sockaddr_in *server_addr, uint32_t gw_ip) +int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dhcprelay_main(int argc, char **argv) { struct dhcpMessage dhcp_msg; - fd_set rfds; - size_t packlen; - socklen_t addr_size; + struct sockaddr_in server_addr; struct sockaddr_in client_addr; - struct timeval tv; - int i; + fd_set rfds; + char **client_ifaces; + int *fds; + int num_sockets, max_socket; + uint32_t our_ip; + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(SERVER_PORT); + + /* dhcprelay client_iface1,client_iface2,... server_iface [server_IP] */ + if (argc == 4) { + if (!inet_aton(argv[3], &server_addr.sin_addr)) + bb_perror_msg_and_die("bad server IP"); + } else if (argc == 3) { + server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + } else { + bb_show_usage(); + } + + /* Produce list of client ifaces */ + client_ifaces = get_client_devices(argv[1], &num_sockets); + + num_sockets++; /* for server socket at fds[0] */ + fds = xmalloc(num_sockets * sizeof(fds[0])); + + /* Create sockets and bind one to every iface */ + max_socket = init_sockets(client_ifaces, num_sockets, argv[2], fds); + + /* Get our IP on server_iface */ + if (udhcp_read_interface(argv[2], NULL, &our_ip, NULL)) + return 1; + /* Main loop */ while (1) { +//reinit stuff from time to time? go back to get_client_devices +//every N minutes? + struct timeval tv; + size_t packlen; + socklen_t addr_size; + int i; + FD_ZERO(&rfds); for (i = 0; i < num_sockets; i++) FD_SET(fds[i], &rfds); @@ -259,56 +294,32 @@ static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **cli if (FD_ISSET(fds[0], &rfds)) { packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); if (packlen > 0) { - pass_back(&dhcp_msg, packlen, fds); + pass_to_client(&dhcp_msg, packlen, fds); } } + /* clients */ for (i = 1; i < num_sockets; i++) { - /* clients */ if (!FD_ISSET(fds[i], &rfds)) continue; addr_size = sizeof(struct sockaddr_in); packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, - (struct sockaddr *)(&client_addr), &addr_size); + (struct sockaddr *)(&client_addr), &addr_size); if (packlen <= 0) continue; - if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL)) - dhcp_msg.giaddr = gw_ip; - pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr); + + /* Get our IP on corresponding client_iface */ +//why? what if server can't route such IP? + if (udhcp_read_interface(client_ifaces[i-1], NULL, &dhcp_msg.giaddr, NULL)) { + /* Fall back to our server_iface's IP */ +//this makes more sense! + dhcp_msg.giaddr = our_ip; + } +//maybe set dhcp_msg.flags |= BROADCAST_FLAG too? + pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); } } xid_expire(); - } -} - -int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int dhcprelay_main(int argc, char **argv) -{ - int num_sockets, max_socket; - int *fds; - uint32_t gw_ip; - char **clients; - struct sockaddr_in server_addr; - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(SERVER_PORT); - if (argc == 4) { - if (!inet_aton(argv[3], &server_addr.sin_addr)) - bb_perror_msg_and_die("didn't grok server"); - } else if (argc == 3) { - server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); - } else { - bb_show_usage(); - } - - clients = get_client_devices(argv[1], &num_sockets); - num_sockets++; /* for server socket at fds[0] */ - fds = xmalloc(num_sockets * sizeof(fds[0])); - max_socket = init_sockets(clients, num_sockets, argv[2], fds); - - if (read_interface(argv[2], NULL, &gw_ip, NULL)) - return 1; + } /* while (1) */ - /* doesn't return */ - dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip); /* return 0; - not reached */ } diff --git a/release/src/router/busybox/networking/udhcp/domain_codec.c b/release/src/router/busybox/networking/udhcp/domain_codec.c index 239ae5b5c4..6f051c4b05 100644 --- a/release/src/router/busybox/networking/udhcp/domain_codec.c +++ b/release/src/router/busybox/networking/udhcp/domain_codec.c @@ -7,7 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 #include "common.h" #include "options.h" @@ -23,7 +23,7 @@ * returns a newly allocated string containing the space-separated domains, * prefixed with the contents of string pre, or NULL if an error occurs. */ -char *dname_dec(const uint8_t *cstr, int clen, const char *pre) +char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) { const uint8_t *c; int crtpos, retpos, depth, plen = 0, len = 0; @@ -178,7 +178,7 @@ static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname) * The computed string is returned directly; its length is returned via retlen; * NULL and 0, respectively, are returned if an error occurs. */ -uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) +uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) { uint8_t *d, *dname; int off; @@ -202,4 +202,4 @@ uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) return dname; } -#endif /* ENABLE_FEATURE_RFC3397 */ +#endif /* ENABLE_FEATURE_UDHCP_RFC3397 */ diff --git a/release/src/router/busybox/networking/udhcp/dumpleases.c b/release/src/router/busybox/networking/udhcp/dumpleases.c index 3e193903d0..1558f8848c 100644 --- a/release/src/router/busybox/networking/udhcp/dumpleases.c +++ b/release/src/router/busybox/networking/udhcp/dumpleases.c @@ -6,13 +6,24 @@ #include "common.h" #include "dhcpd.h" +#if BB_LITTLE_ENDIAN +static inline uint64_t hton64(uint64_t v) +{ + return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); +} +#else +#define hton64(v) (v) +#endif +#define ntoh64(v) hton64(v) + + int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dumpleases_main(int argc UNUSED_PARAM, char **argv) { int fd; int i; unsigned opt; - time_t expires; + int64_t written_at, curr, expires_abs; const char *file = LEASES_FILE; struct dhcpOfferedAddr lease; struct in_addr addr; @@ -36,29 +47,45 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) fd = xopen(file, O_RDONLY); - printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); - /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ + printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in"); + /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */ + /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */ + + if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) + return 0; + written_at = ntoh64(written_at); + curr = time(NULL); + if (curr < written_at) + written_at = curr; /* lease file from future! :) */ + while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { - printf(":%02x"+1, lease.chaddr[0]); - for (i = 1; i < 6; i++) { - printf(":%02x", lease.chaddr[i]); + const char *fmt = ":%02x" + 1; + for (i = 0; i < 6; i++) { + printf(fmt, lease.chaddr[i]); + fmt = ":%02x"; } addr.s_addr = lease.yiaddr; - printf(" %-15s ", inet_ntoa(addr)); - expires = ntohl(lease.expires); + /* actually, 15+1 and 19+1, +1 is a space between columns */ + /* lease.hostname is char[20] and is always NUL terminated */ + printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname); + expires_abs = ntohl(lease.expires) + written_at; + if (expires_abs <= curr) { + puts("expired"); + continue; + } if (!(opt & OPT_a)) { /* no -a */ - if (!expires) - puts("expired"); - else { - unsigned d, h, m; - d = expires / (24*60*60); expires %= (24*60*60); - h = expires / (60*60); expires %= (60*60); - m = expires / 60; expires %= 60; - if (d) printf("%u days ", d); - printf("%02u:%02u:%02u\n", h, m, (unsigned)expires); - } - } else /* -a */ - fputs(ctime(&expires), stdout); + unsigned d, h, m; + unsigned expires = expires_abs - curr; + d = expires / (24*60*60); expires %= (24*60*60); + h = expires / (60*60); expires %= (60*60); + m = expires / 60; expires %= 60; + if (d) + printf("%u days ", d); + printf("%02u:%02u:%02u\n", h, m, (unsigned)expires); + } else { /* -a */ + time_t t = expires_abs; + fputs(ctime(&t), stdout); + } } /* close(fd); */ diff --git a/release/src/router/busybox/networking/udhcp/files.c b/release/src/router/busybox/networking/udhcp/files.c index ff5847d25b..a061a9c9bb 100644 --- a/release/src/router/busybox/networking/udhcp/files.c +++ b/release/src/router/busybox/networking/udhcp/files.c @@ -2,6 +2,8 @@ /* * files.c -- DHCP server file manipulation * * Rewrite by Russ Dill July 2001 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include @@ -10,6 +12,16 @@ #include "dhcpd.h" #include "options.h" +#if BB_LITTLE_ENDIAN +static inline uint64_t hton64(uint64_t v) +{ + return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); +} +#else +#define hton64(v) (v) +#endif +#define ntoh64(v) hton64(v) + /* on these functions, make sure your datatype matches */ static int read_ip(const char *line, void *arg) @@ -24,14 +36,10 @@ static int read_ip(const char *line, void *arg) return 1; } + static int read_mac(const char *line, void *arg) { - struct ether_addr *temp_ether_addr; - - temp_ether_addr = ether_aton_r(line, (struct ether_addr *)arg); - if (temp_ether_addr == NULL) - return 0; - return 1; + return NULL == ether_aton_r(line, (struct ether_addr *)arg); } @@ -69,7 +77,7 @@ static int read_yn(const char *line, void *arg) /* find option 'code' in opt_list */ -struct option_set *find_option(struct option_set *opt_list, uint8_t code) +struct option_set* FAST_FUNC find_option(struct option_set *opt_list, uint8_t code) { while (opt_list && opt_list->data[OPT_CODE] < code) opt_list = opt_list->next; @@ -90,7 +98,7 @@ static void attach_option(struct option_set **opt_list, if (!existing) { DEBUG("Attaching option %02x to list", option->code); -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 if ((option->flags & TYPE_MASK) == OPTION_STR1035) /* reuse buffer and length for RFC1035-formatted string */ buffer = (char *)dname_enc(NULL, 0, buffer, &length); @@ -109,7 +117,7 @@ static void attach_option(struct option_set **opt_list, new->next = *curr; *curr = new; -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) free(buffer); #endif @@ -119,7 +127,7 @@ static void attach_option(struct option_set **opt_list, /* add it to an existing option */ DEBUG("Attaching option %02x to existing member of list", option->code); if (option->flags & OPTION_LIST) { -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 if ((option->flags & TYPE_MASK) == OPTION_STR1035) /* reuse buffer and length for RFC1035-formatted string */ buffer = (char *)dname_enc(existing->data + 2, @@ -139,7 +147,7 @@ static void attach_option(struct option_set **opt_list, memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); existing->data[OPT_LEN] += length; } /* else, ignore the data, we could put this in a second option in the future */ -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) free(buffer); #endif @@ -190,7 +198,7 @@ static int read_opt(const char *const_line, void *arg) retval = read_ip(val, buffer + 4); break; case OPTION_STRING: -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_STR1035: #endif length = strlen(val); @@ -248,25 +256,21 @@ static int read_staticlease(const char *const_line, void *arg) char *line; char *mac_string; char *ip_string; - uint8_t *mac_bytes; - uint32_t *ip; - - /* Allocate memory for addresses */ - mac_bytes = xmalloc(sizeof(unsigned char) * 8); - ip = xmalloc(sizeof(uint32_t)); + struct ether_addr mac_bytes; + uint32_t ip; /* Read mac */ line = (char *) const_line; - mac_string = strtok(line, " \t"); - read_mac(mac_string, mac_bytes); + mac_string = strtok_r(line, " \t", &line); + read_mac(mac_string, &mac_bytes); /* Read ip */ - ip_string = strtok(NULL, " \t"); - read_ip(ip_string, ip); + ip_string = strtok_r(NULL, " \t", &line); + read_ip(ip_string, &ip); - addStaticLease(arg, mac_bytes, ip); + addStaticLease(arg, (uint8_t*) &mac_bytes, ip); - if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg); + if (ENABLE_UDHCP_DEBUG) printStaticLeases(arg); return 1; } @@ -287,7 +291,7 @@ static const struct config_keyword keywords[] = { /* Avoid "max_leases value not sane" warning by setting default * to default_end_ip - default_start_ip + 1: */ {"max_leases", read_u32, &(server_config.max_leases), "235"}, - {"remaining", read_yn, &(server_config.remaining), "yes"}, +// {"remaining", read_yn, &(server_config.remaining), "yes"}, {"auto_time", read_u32, &(server_config.auto_time), "7200"}, {"decline_time", read_u32, &(server_config.decline_time), "3600"}, {"conflict_time",read_u32, &(server_config.conflict_time),"3600"}, @@ -303,11 +307,10 @@ static const struct config_keyword keywords[] = { {"sname", read_str, &(server_config.sname), ""}, {"boot_file", read_str, &(server_config.boot_file), ""}, {"static_lease", read_staticlease, &(server_config.static_leases), ""}, - /* ADDME: static lease */ }; enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; -void read_config(const char *file) +void FAST_FUNC read_config(const char *file) { parser_t *parser; const struct config_keyword *k; @@ -338,38 +341,44 @@ void read_config(const char *file) } -void write_leases(void) +void FAST_FUNC write_leases(void) { - int fp; + int fd; unsigned i; - time_t curr = time(0); - unsigned long tmp_time; + leasetime_t curr; + int64_t written_at; - fp = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC); - if (fp < 0) { + fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC); + if (fd < 0) return; - } + + curr = written_at = time(NULL); + + written_at = hton64(written_at); + full_write(fd, &written_at, sizeof(written_at)); for (i = 0; i < server_config.max_leases; i++) { - if (leases[i].yiaddr != 0) { - - /* screw with the time in the struct, for easier writing */ - tmp_time = leases[i].expires; - - if (server_config.remaining) { - if (lease_expired(&(leases[i]))) - leases[i].expires = 0; - else leases[i].expires -= curr; - } /* else stick with the time we got */ - leases[i].expires = htonl(leases[i].expires); - // FIXME: error check?? - full_write(fp, &leases[i], sizeof(leases[i])); - - /* then restore it when done */ - leases[i].expires = tmp_time; - } + leasetime_t tmp_time; + + if (leases[i].yiaddr == 0) + continue; + + /* Screw with the time in the struct, for easier writing */ + tmp_time = leases[i].expires; + + leases[i].expires -= curr; + if ((signed_leasetime_t) leases[i].expires < 0) + leases[i].expires = 0; + leases[i].expires = htonl(leases[i].expires); + + /* No error check. If the file gets truncated, + * we lose some leases on restart. Oh well. */ + full_write(fd, &leases[i], sizeof(leases[i])); + + /* Then restore it when done */ + leases[i].expires = tmp_time; } - close(fp); + close(fd); if (server_config.notify_file) { // TODO: vfork-based child creation @@ -380,34 +389,45 @@ void write_leases(void) } -void read_leases(const char *file) +void FAST_FUNC read_leases(const char *file) { - int fp; - unsigned i; struct dhcpOfferedAddr lease; + int64_t written_at, time_passed; + int fd; + USE_UDHCP_DEBUG(unsigned i;) - fp = open_or_warn(file, O_RDONLY); - if (fp < 0) { + fd = open_or_warn(file, O_RDONLY); + if (fd < 0) return; - } - i = 0; - while (i < server_config.max_leases - && full_read(fp, &lease, sizeof(lease)) == sizeof(lease) - ) { - /* ADDME: is it a static lease */ + if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) + goto ret; + written_at = ntoh64(written_at); + + time_passed = time(NULL) - written_at; + /* Strange written_at, or lease file from old version of udhcpd + * which had no "written_at" field? */ + if ((uint64_t)time_passed > 12 * 60 * 60) + goto ret; + + USE_UDHCP_DEBUG(i = 0;) + while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { + /* ADDME: what if it matches some static lease? */ uint32_t y = ntohl(lease.yiaddr); if (y >= server_config.start_ip && y <= server_config.end_ip) { - lease.expires = ntohl(lease.expires); - if (!server_config.remaining) - lease.expires -= time(NULL); - if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { + signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; + if (expires <= 0) + continue; + /* NB: add_lease takes "relative time", IOW, + * lease duration, not lease deadline. */ + if (!(add_lease(lease.chaddr, lease.yiaddr, expires, lease.hostname))) { bb_error_msg("too many leases while loading %s", file); break; } - i++; + USE_UDHCP_DEBUG(i++;) } } DEBUG("Read %d leases", i); - close(fp); + ret: + close(fd); } diff --git a/release/src/router/busybox/networking/udhcp/leases.c b/release/src/router/busybox/networking/udhcp/leases.c index 1745fee033..6e1398d2f6 100644 --- a/release/src/router/busybox/networking/udhcp/leases.c +++ b/release/src/router/busybox/networking/udhcp/leases.c @@ -2,6 +2,8 @@ /* * leases.c -- tools to manage DHCP leases * Russ Dill July 2001 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "common.h" @@ -11,21 +13,23 @@ /* Find the oldest expired lease, NULL if there are no expired leases */ static struct dhcpOfferedAddr *oldest_expired_lease(void) { - struct dhcpOfferedAddr *oldest = NULL; -// TODO: use monotonic_sec() - unsigned long oldest_lease = time(0); + struct dhcpOfferedAddr *oldest_lease = NULL; + leasetime_t oldest_time = time(NULL); unsigned i; - for (i = 0; i < server_config.max_leases; i++) - if (oldest_lease > leases[i].expires) { - oldest_lease = leases[i].expires; - oldest = &(leases[i]); + /* Unexpired leases have leases[i].expires >= current time + * and therefore can't ever match */ + for (i = 0; i < server_config.max_leases; i++) { + if (leases[i].expires < oldest_time) { + oldest_time = leases[i].expires; + oldest_lease = &(leases[i]); } - return oldest; + } + return oldest_lease; } -/* clear every lease out that chaddr OR yiaddr matches and is nonzero */ +/* Clear every lease out that chaddr OR yiaddr matches and is nonzero */ static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) { unsigned i, j; @@ -33,19 +37,23 @@ static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) for (j = 0; j < 16 && !chaddr[j]; j++) continue; - for (i = 0; i < server_config.max_leases; i++) + for (i = 0; i < server_config.max_leases; i++) { if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0) || (yiaddr && leases[i].yiaddr == yiaddr) ) { memset(&(leases[i]), 0, sizeof(leases[i])); } + } } -/* add a lease into the table, clearing out any old ones */ -struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) +/* Add a lease into the table, clearing out any old ones */ +struct dhcpOfferedAddr* FAST_FUNC add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname) { struct dhcpOfferedAddr *oldest; + uint8_t hostname_length; /* clean out any old ones */ clear_lease(chaddr, yiaddr); @@ -53,24 +61,37 @@ struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsign oldest = oldest_expired_lease(); if (oldest) { + oldest->hostname[0] = '\0'; + if (hostname) { + hostname_length = hostname[-1]; /* look at option size byte */ + if (hostname_length > sizeof(oldest->hostname)) + hostname_length = sizeof(oldest->hostname); + hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length); + /* sanitization (s/non-ASCII/^/g) */ + while (*hostname) { + if (*hostname < ' ' || *hostname > 126) + *hostname = '^'; + hostname++; + } + } memcpy(oldest->chaddr, chaddr, 16); oldest->yiaddr = yiaddr; - oldest->expires = time(0) + lease; + oldest->expires = time(NULL) + leasetime; } return oldest; } -/* true if a lease has expired */ -int lease_expired(struct dhcpOfferedAddr *lease) +/* True if a lease has expired */ +int FAST_FUNC lease_expired(struct dhcpOfferedAddr *lease) { - return (lease->expires < (unsigned long) time(0)); + return (lease->expires < (leasetime_t) time(NULL)); } /* Find the first lease that matches chaddr, NULL if no match */ -struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) +struct dhcpOfferedAddr* FAST_FUNC find_lease_by_chaddr(const uint8_t *chaddr) { unsigned i; @@ -83,7 +104,7 @@ struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) /* Find the first lease that matches yiaddr, NULL is no match */ -struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) +struct dhcpOfferedAddr* FAST_FUNC find_lease_by_yiaddr(uint32_t yiaddr) { unsigned i; @@ -112,38 +133,48 @@ static int nobody_responds_to_arp(uint32_t addr) temp.s_addr = addr; bb_info_msg("%s belongs to someone, reserving it for %u seconds", inet_ntoa(temp), (unsigned)server_config.conflict_time); - add_lease(blank_chaddr, addr, server_config.conflict_time); + add_lease(blank_chaddr, addr, server_config.conflict_time, NULL); return 0; } -/* find an assignable address, if check_expired is true, we check all the expired leases as well. - * Maybe this should try expired leases by age... */ -uint32_t find_address(int check_expired) +/* Find a new usable (we think) address. */ +uint32_t FAST_FUNC find_free_or_expired_address(void) { - uint32_t addr, ret; - struct dhcpOfferedAddr *lease = NULL; + uint32_t addr; + struct dhcpOfferedAddr *oldest_lease = NULL; addr = server_config.start_ip; /* addr is in host order here */ for (; addr <= server_config.end_ip; addr++) { + uint32_t net_addr; + struct dhcpOfferedAddr *lease; + /* ie, 192.168.55.0 */ - if (!(addr & 0xFF)) + if ((addr & 0xff) == 0) continue; /* ie, 192.168.55.255 */ - if ((addr & 0xFF) == 0xFF) + if ((addr & 0xff) == 0xff) continue; - /* Only do if it isn't assigned as a static lease */ - ret = htonl(addr); - if (!reservedIp(server_config.static_leases, ret)) { - /* lease is not taken */ - lease = find_lease_by_yiaddr(ret); - /* no lease or it expired and we are checking for expired leases */ - if ((!lease || (check_expired && lease_expired(lease))) - && nobody_responds_to_arp(ret) /* it isn't used on the network */ - ) { - return ret; - } + net_addr = htonl(addr); + /* addr has a static lease? */ + if (reservedIp(server_config.static_leases, net_addr)) + continue; + + lease = find_lease_by_yiaddr(net_addr); + if (!lease) { + if (nobody_responds_to_arp(net_addr)) + return net_addr; + } else { + if (!oldest_lease || lease->expires < oldest_lease->expires) + oldest_lease = lease; } } + + if (oldest_lease && lease_expired(oldest_lease) + && nobody_responds_to_arp(oldest_lease->yiaddr) + ) { + return oldest_lease->yiaddr; + } + return 0; } diff --git a/release/src/router/busybox/networking/udhcp/options.c b/release/src/router/busybox/networking/udhcp/options.c index 12e5662108..143a1fd1ca 100644 --- a/release/src/router/busybox/networking/udhcp/options.c +++ b/release/src/router/busybox/networking/udhcp/options.c @@ -2,6 +2,8 @@ /* * options.c -- DHCP server option packet tools * Rewrite by Russ Dill July 2001 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "common.h" @@ -43,7 +45,7 @@ const struct dhcp_option dhcp_options[] = { { OPTION_STRING , 0x42 }, /* tftp */ { OPTION_STRING , 0x43 }, /* bootfile */ { OPTION_STRING , 0x4D }, /* userclass */ -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 { OPTION_STR1035 | OPTION_LIST , 0x77 }, /* search */ #endif /* MSIE's "Web Proxy Autodiscovery Protocol" support */ @@ -92,7 +94,7 @@ const char dhcp_option_strings[] ALIGN1 = "tftp" "\0" "bootfile" "\0" "userclass" "\0" -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 "search" "\0" #endif /* MSIE's "Web Proxy Autodiscovery Protocol" support */ @@ -106,7 +108,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_IP_PAIR] = 8, [OPTION_BOOLEAN] = 1, [OPTION_STRING] = 1, -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_STR1035] = 1, #endif [OPTION_U8] = 1, @@ -117,81 +119,83 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { }; -/* get an option with bounds checking (warning, not aligned). */ -uint8_t *get_option(struct dhcpMessage *packet, int code) +/* get an option with bounds checking (warning, result is not aligned). */ +uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) { - int i, length; uint8_t *optionptr; - int over = 0; - int curr = OPTION_FIELD; - + int len; + int rem; + int overload = 0; + enum { + FILE_FIELD101 = FILE_FIELD * 0x101, + SNAME_FIELD101 = SNAME_FIELD * 0x101, + }; + + /* option bytes: [code][len][data1][data2]..[dataLEN] */ optionptr = packet->options; - i = 0; - length = sizeof(packet->options); + rem = sizeof(packet->options); while (1) { - if (i >= length) { - bb_error_msg("bogus packet, option fields too long"); + if (rem <= 0) { + bb_error_msg("bogus packet, malformed option field"); return NULL; } - if (optionptr[i + OPT_CODE] == code) { - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - return optionptr + i + 2; + if (optionptr[OPT_CODE] == DHCP_PADDING) { + rem--; + optionptr++; + continue; } - switch (optionptr[i + OPT_CODE]) { - case DHCP_PADDING: - i++; - break; - case DHCP_OPTION_OVER: - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - over = optionptr[i + 3]; - i += optionptr[OPT_LEN] + 2; - break; - case DHCP_END: - if (curr == OPTION_FIELD && (over & FILE_FIELD)) { + if (optionptr[OPT_CODE] == DHCP_END) { + if ((overload & FILE_FIELD101) == FILE_FIELD) { + /* can use packet->file, and didn't look at it yet */ + overload |= FILE_FIELD101; /* "we looked at it" */ optionptr = packet->file; - i = 0; - length = sizeof(packet->file); - curr = FILE_FIELD; - } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { + rem = sizeof(packet->file); + continue; + } + if ((overload & SNAME_FIELD101) == SNAME_FIELD) { + /* can use packet->sname, and didn't look at it yet */ + overload |= SNAME_FIELD101; /* "we looked at it" */ optionptr = packet->sname; - i = 0; - length = sizeof(packet->sname); - curr = SNAME_FIELD; - } else - return NULL; - break; - default: - i += optionptr[OPT_LEN + i] + 2; + rem = sizeof(packet->sname); + continue; + } + return NULL; + } + len = 2 + optionptr[OPT_LEN]; + rem -= len; + if (rem < 0) + continue; /* complain and return NULL */ + + if (optionptr[OPT_CODE] == code) + return optionptr + OPT_DATA; + + if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { + overload |= optionptr[OPT_DATA]; + /* fall through */ } + optionptr += len; } return NULL; } /* return the position of the 'end' option (no bounds checking) */ -int end_option(uint8_t *optionptr) +int FAST_FUNC end_option(uint8_t *optionptr) { int i = 0; while (optionptr[i] != DHCP_END) { - if (optionptr[i] == DHCP_PADDING) - i++; - else - i += optionptr[i + OPT_LEN] + 2; + if (optionptr[i] != DHCP_PADDING) + i += optionptr[i + OPT_LEN] + 1; + i++; } return i; } -/* add an option string to the options (an option string contains an option code, - * length, then data) */ -int add_option_string(uint8_t *optionptr, uint8_t *string) +/* add an option string to the options */ +/* option bytes: [code][len][data1][data2]..[dataLEN] */ +int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) { int end = end_option(optionptr); @@ -209,7 +213,7 @@ int add_option_string(uint8_t *optionptr, uint8_t *string) /* add a one to four byte option to a packet */ -int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) +int FAST_FUNC add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) { const struct dhcp_option *dh; @@ -222,9 +226,8 @@ int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) option[OPT_LEN] = len; if (BB_BIG_ENDIAN) data <<= 8 * (4 - len); - /* This memcpy is for processors which can't - * handle a simple unaligned 32-bit assignment */ - memcpy(&option[OPT_DATA], &data, 4); + /* Assignment is unaligned! */ + move_to_unaligned32(&option[OPT_DATA], data); return add_option_string(optionptr, option); } } diff --git a/release/src/router/busybox/networking/udhcp/options.h b/release/src/router/busybox/networking/udhcp/options.h dissimilarity index 69% index cf3fe3b183..23370da6e4 100644 --- a/release/src/router/busybox/networking/udhcp/options.h +++ b/release/src/router/busybox/networking/udhcp/options.h @@ -1,123 +1,114 @@ -/* vi: set sw=4 ts=4: */ -/* options.h */ -#ifndef _OPTIONS_H -#define _OPTIONS_H - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility push(hidden) -#endif - -#define TYPE_MASK 0x0F - -enum { - OPTION_IP = 1, - OPTION_IP_PAIR, - OPTION_STRING, -#if ENABLE_FEATURE_RFC3397 - OPTION_STR1035, /* RFC1035 compressed domain name list */ -#endif - OPTION_BOOLEAN, - OPTION_U8, - OPTION_U16, - OPTION_S16, - OPTION_U32, - OPTION_S32 -}; - -#define OPTION_REQ 0x10 /* have the client request this option */ -#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ - -/*****************************************************************/ -/* Do not modify below here unless you know what you are doing!! */ -/*****************************************************************/ - -/* DHCP protocol -- see RFC 2131 */ -#define DHCP_MAGIC 0x63825363 - - -/* DHCP option codes (partial list) */ -#define DHCP_PADDING 0x00 -#define DHCP_SUBNET 0x01 -#define DHCP_TIME_OFFSET 0x02 -#define DHCP_ROUTER 0x03 -#define DHCP_TIME_SERVER 0x04 -#define DHCP_NAME_SERVER 0x05 -#define DHCP_DNS_SERVER 0x06 -#define DHCP_LOG_SERVER 0x07 -#define DHCP_COOKIE_SERVER 0x08 -#define DHCP_LPR_SERVER 0x09 -#define DHCP_HOST_NAME 0x0c -#define DHCP_BOOT_SIZE 0x0d -#define DHCP_DOMAIN_NAME 0x0f -#define DHCP_SWAP_SERVER 0x10 -#define DHCP_ROOT_PATH 0x11 -#define DHCP_IP_TTL 0x17 -#define DHCP_MTU 0x1a -#define DHCP_BROADCAST 0x1c -#define DHCP_NTP_SERVER 0x2a -#define DHCP_WINS_SERVER 0x2c -#define DHCP_REQUESTED_IP 0x32 -#define DHCP_LEASE_TIME 0x33 -#define DHCP_OPTION_OVER 0x34 -#define DHCP_MESSAGE_TYPE 0x35 -#define DHCP_SERVER_ID 0x36 -#define DHCP_PARAM_REQ 0x37 -#define DHCP_MESSAGE 0x38 -#define DHCP_MAX_SIZE 0x39 -#define DHCP_T1 0x3a -#define DHCP_T2 0x3b -#define DHCP_VENDOR 0x3c -#define DHCP_CLIENT_ID 0x3d -#define DHCP_FQDN 0x51 -#define DHCP_END 0xFF - - -#define BOOTREQUEST 1 -#define BOOTREPLY 2 - -#define ETH_10MB 1 -#define ETH_10MB_LEN 6 - -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 -#define DHCPINFORM 8 - -#define BROADCAST_FLAG 0x8000 - -#define OPTION_FIELD 0 -#define FILE_FIELD 1 -#define SNAME_FIELD 2 - -/* miscellaneous defines */ -#define OPT_CODE 0 -#define OPT_LEN 1 -#define OPT_DATA 2 - -struct dhcp_option { - uint8_t flags; - uint8_t code; -}; - -extern const struct dhcp_option dhcp_options[]; -extern const char dhcp_option_strings[]; -extern const uint8_t dhcp_option_lengths[]; - -uint8_t *get_option(struct dhcpMessage *packet, int code); -int end_option(uint8_t *optionptr); -int add_option_string(uint8_t *optionptr, uint8_t *string); -int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data); -#if ENABLE_FEATURE_RFC3397 -char *dname_dec(const uint8_t *cstr, int clen, const char *pre); -uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen); -#endif - -#if __GNUC_PREREQ(4,1) -# pragma GCC visibility pop -#endif - -#endif +/* vi: set sw=4 ts=4: */ +/* options.h */ +#ifndef UDHCP_OPTIONS_H +#define UDHCP_OPTIONS_H 1 + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +#define TYPE_MASK 0x0F + +enum { + OPTION_IP = 1, + OPTION_IP_PAIR, + OPTION_STRING, +#if ENABLE_FEATURE_UDHCP_RFC3397 + OPTION_STR1035, /* RFC1035 compressed domain name list */ +#endif + OPTION_BOOLEAN, + OPTION_U8, + OPTION_U16, + OPTION_S16, + OPTION_U32, + OPTION_S32 +}; + +#define OPTION_REQ 0x10 /* have the client request this option */ +#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ + +/*****************************************************************/ +/* Do not modify below here unless you know what you are doing!! */ +/*****************************************************************/ + +/* DHCP protocol -- see RFC 2131 */ +#define DHCP_MAGIC 0x63825363 + +/* DHCP option codes (partial list) */ +#define DHCP_PADDING 0x00 +#define DHCP_SUBNET 0x01 +#define DHCP_TIME_OFFSET 0x02 +#define DHCP_ROUTER 0x03 +#define DHCP_TIME_SERVER 0x04 +#define DHCP_NAME_SERVER 0x05 +#define DHCP_DNS_SERVER 0x06 +#define DHCP_LOG_SERVER 0x07 +#define DHCP_COOKIE_SERVER 0x08 +#define DHCP_LPR_SERVER 0x09 +#define DHCP_HOST_NAME 0x0c +#define DHCP_BOOT_SIZE 0x0d +#define DHCP_DOMAIN_NAME 0x0f +#define DHCP_SWAP_SERVER 0x10 +#define DHCP_ROOT_PATH 0x11 +#define DHCP_IP_TTL 0x17 +#define DHCP_MTU 0x1a +#define DHCP_BROADCAST 0x1c +#define DHCP_NTP_SERVER 0x2a +#define DHCP_WINS_SERVER 0x2c +#define DHCP_REQUESTED_IP 0x32 +#define DHCP_LEASE_TIME 0x33 +#define DHCP_OPTION_OVERLOAD 0x34 +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCP_SERVER_ID 0x36 +#define DHCP_PARAM_REQ 0x37 +#define DHCP_MESSAGE 0x38 +#define DHCP_MAX_SIZE 0x39 +#define DHCP_T1 0x3a +#define DHCP_T2 0x3b +#define DHCP_VENDOR 0x3c +#define DHCP_CLIENT_ID 0x3d +#define DHCP_FQDN 0x51 +#define DHCP_END 0xFF +/* Offsets in option byte sequence */ +#define OPT_CODE 0 +#define OPT_LEN 1 +#define OPT_DATA 2 +/* Bits in "overload" option */ +#define OPTION_FIELD 0 +#define FILE_FIELD 1 +#define SNAME_FIELD 2 + +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + +#define ETH_10MB 1 +#define ETH_10MB_LEN 6 + +#define DHCPDISCOVER 1 /* client -> server */ +#define DHCPOFFER 2 /* client <- server */ +#define DHCPREQUEST 3 /* client -> server */ +#define DHCPDECLINE 4 /* client -> server */ +#define DHCPACK 5 /* client <- server */ +#define DHCPNAK 6 /* client <- server */ +#define DHCPRELEASE 7 /* client -> server */ +#define DHCPINFORM 8 /* client -> server */ + +struct dhcp_option { + uint8_t flags; + uint8_t code; +}; + +extern const struct dhcp_option dhcp_options[]; +extern const char dhcp_option_strings[]; +extern const uint8_t dhcp_option_lengths[]; + +uint8_t *get_option(struct dhcpMessage *packet, int code) FAST_FUNC; +int end_option(uint8_t *optionptr) FAST_FUNC; +int add_option_string(uint8_t *optionptr, uint8_t *string) FAST_FUNC; +int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) FAST_FUNC; +#if ENABLE_FEATURE_UDHCP_RFC3397 +char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; +uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; +#endif + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/release/src/router/busybox/networking/udhcp/packet.c b/release/src/router/busybox/networking/udhcp/packet.c index fbb32cda2a..333202384d 100644 --- a/release/src/router/busybox/networking/udhcp/packet.c +++ b/release/src/router/busybox/networking/udhcp/packet.c @@ -1,4 +1,10 @@ /* vi: set sw=4 ts=4: */ +/* + * packet.c -- packet ops + * Rewrite by Russ Dill July 2001 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ #include #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION @@ -16,15 +22,15 @@ int minpkt = 0; // zzz -void udhcp_init_header(struct dhcpMessage *packet, char type) +void FAST_FUNC udhcp_init_header(struct dhcpMessage *packet, char type) { memset(packet, 0, sizeof(struct dhcpMessage)); - packet->op = BOOTREQUEST; + packet->op = BOOTREQUEST; /* if client to a server */ switch (type) { case DHCPOFFER: case DHCPACK: case DHCPNAK: - packet->op = BOOTREPLY; + packet->op = BOOTREPLY; /* if server to client */ } packet->htype = ETH_10MB; packet->hlen = ETH_10MB_LEN; @@ -35,7 +41,7 @@ void udhcp_init_header(struct dhcpMessage *packet, char type) /* read a packet from socket fd, return -1 on read error, -2 on packet error */ -int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) +int FAST_FUNC udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) { int bytes; unsigned char *vendor; @@ -66,7 +72,7 @@ int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i]) && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2]) ) { - DEBUG("broken client (%s), forcing broadcast", + DEBUG("broken client (%s), forcing broadcast replies", broken_vendors[i]); packet->flags |= htons(BROADCAST_FLAG); } @@ -75,7 +81,7 @@ int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1) && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 ) { - DEBUG("broken client (%s), forcing broadcast", "MSFT 98"); + DEBUG("broken client (%s), forcing broadcast replies", "MSFT 98"); packet->flags |= htons(BROADCAST_FLAG); } #endif @@ -86,7 +92,7 @@ int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) } -uint16_t udhcp_checksum(void *addr, int count) +uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) { /* Compute Internet Checksum for "count" bytes * beginning at location "addr". @@ -117,9 +123,10 @@ uint16_t udhcp_checksum(void *addr, int count) /* Construct a ip/udp header for a packet, send packet */ -int udhcp_send_raw_packet(struct dhcpMessage *payload, +int FAST_FUNC udhcp_send_raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, int ifindex) + uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, + int ifindex) { struct sockaddr_ll dest; struct udp_dhcp_packet packet; @@ -224,7 +231,7 @@ int udhcp_send_raw_packet(struct dhcpMessage *payload, /* Let the kernel do all the work for packet generation */ -int udhcp_send_kernel_packet(struct dhcpMessage *payload, +int FAST_FUNC udhcp_send_kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, uint32_t dest_ip, int dest_port) { diff --git a/release/src/router/busybox/networking/udhcp/script.c b/release/src/router/busybox/networking/udhcp/script.c index 4f4bc253a6..3029b13670 100644 --- a/release/src/router/busybox/networking/udhcp/script.c +++ b/release/src/router/busybox/networking/udhcp/script.c @@ -18,7 +18,7 @@ static const uint8_t max_option_length[] = { [OPTION_IP] = sizeof("255.255.255.255 "), [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, [OPTION_STRING] = 1, -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_STR1035] = 1, #endif [OPTION_BOOLEAN] = sizeof("yes "), @@ -90,26 +90,26 @@ static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, dest += sprintf(dest, "%u", *option); break; case OPTION_U16: - memcpy(&val_u16, option, 2); + move_from_unaligned16(val_u16, option); dest += sprintf(dest, "%u", ntohs(val_u16)); break; case OPTION_S16: - memcpy(&val_s16, option, 2); + move_from_unaligned16(val_s16, option); dest += sprintf(dest, "%d", ntohs(val_s16)); break; case OPTION_U32: - memcpy(&val_u32, option, 4); + move_from_unaligned32(val_u32, option); dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32)); break; case OPTION_S32: - memcpy(&val_s32, option, 4); + move_from_unaligned32(val_s32, option); dest += sprintf(dest, "%ld", (long) ntohl(val_s32)); break; case OPTION_STRING: memcpy(dest, option, len); dest[len] = '\0'; return ret; /* Short circuit this case */ -#if ENABLE_FEATURE_RFC3397 +#if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_STR1035: /* unpack option into dest; use ret for prefix (i.e., "optname=") */ dest = dname_dec(option, len, ret); @@ -119,7 +119,8 @@ static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, } option += optlen; len -= optlen; - if (len <= 0) break; + if (len <= 0) + break; dest += sprintf(dest, " "); } return ret; @@ -130,12 +131,11 @@ static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, static char **fill_envp(struct dhcpMessage *packet) { int num_options = 0; - int i, j; - char **envp; - char *var; + int i; + char **envp, **curr; const char *opt_name; uint8_t *temp; - char over = 0; + uint8_t over = 0; if (packet) { for (i = 0; dhcp_options[i].code; i++) { @@ -147,7 +147,7 @@ static char **fill_envp(struct dhcpMessage *packet) } if (packet->siaddr) num_options++; - temp = get_option(packet, DHCP_OPTION_OVER); + temp = get_option(packet, DHCP_OPTION_OVERLOAD); if (temp) over = *temp; if (!(over & FILE_FIELD) && packet->file[0]) @@ -156,21 +156,16 @@ static char **fill_envp(struct dhcpMessage *packet) num_options++; } - envp = xzalloc(sizeof(char *) * (num_options + 5)); - j = 0; - envp[j++] = xasprintf("interface=%s", client_config.interface); - var = getenv("PATH"); - if (var) - envp[j++] = xasprintf("PATH=%s", var); - var = getenv("HOME"); - if (var) - envp[j++] = xasprintf("HOME=%s", var); + curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); + *curr = xasprintf("interface=%s", client_config.interface); + putenv(*curr++); if (packet == NULL) return envp; - envp[j] = xmalloc(sizeof("ip=255.255.255.255")); - sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr); + *curr = xmalloc(sizeof("ip=255.255.255.255")); + sprintip(*curr, "ip=", (uint8_t *) &packet->yiaddr); + putenv(*curr++); opt_name = dhcp_option_strings; i = 0; @@ -178,62 +173,63 @@ static char **fill_envp(struct dhcpMessage *packet) temp = get_option(packet, dhcp_options[i].code); if (!temp) goto next; - envp[j++] = alloc_fill_opts(temp, &dhcp_options[i], opt_name); + *curr = alloc_fill_opts(temp, &dhcp_options[i], opt_name); + putenv(*curr++); /* Fill in a subnet bits option for things like /24 */ if (dhcp_options[i].code == DHCP_SUBNET) { uint32_t subnet; - memcpy(&subnet, temp, 4); - envp[j++] = xasprintf("mask=%d", mton(subnet)); + move_from_unaligned32(subnet, temp); + *curr = xasprintf("mask=%d", mton(subnet)); + putenv(*curr++); } next: opt_name += strlen(opt_name) + 1; i++; } if (packet->siaddr) { - envp[j] = xmalloc(sizeof("siaddr=255.255.255.255")); - sprintip(envp[j++], "siaddr=", (uint8_t *) &packet->siaddr); + *curr = xmalloc(sizeof("siaddr=255.255.255.255")); + sprintip(*curr, "siaddr=", (uint8_t *) &packet->siaddr); + putenv(*curr++); } if (!(over & FILE_FIELD) && packet->file[0]) { /* watch out for invalid packets */ packet->file[sizeof(packet->file) - 1] = '\0'; - envp[j++] = xasprintf("boot_file=%s", packet->file); + *curr = xasprintf("boot_file=%s", packet->file); + putenv(*curr++); } if (!(over & SNAME_FIELD) && packet->sname[0]) { /* watch out for invalid packets */ packet->sname[sizeof(packet->sname) - 1] = '\0'; - envp[j++] = xasprintf("sname=%s", packet->sname); + *curr = xasprintf("sname=%s", packet->sname); + putenv(*curr++); } return envp; } /* Call a script with a par file and env vars */ -void udhcp_run_script(struct dhcpMessage *packet, const char *name) +void FAST_FUNC udhcp_run_script(struct dhcpMessage *packet, const char *name) { - int pid; char **envp, **curr; + char *argv[3]; if (client_config.script == NULL) return; - DEBUG("vfork'ing and execle'ing %s", client_config.script); + DEBUG("vfork'ing and exec'ing %s", client_config.script); envp = fill_envp(packet); /* call script */ -// can we use wait4pid(spawn(...)) here? - pid = vfork(); - if (pid < 0) return; - if (pid == 0) { - /* close fd's? */ - /* exec script */ - execle(client_config.script, client_config.script, - name, NULL, envp); - bb_perror_msg_and_die("exec %s", client_config.script); - } - safe_waitpid(pid, NULL, 0); - for (curr = envp; *curr; curr++) + argv[0] = (char*) client_config.script; + argv[1] = (char*) name; + argv[2] = NULL; + wait4pid(spawn(argv)); + + for (curr = envp; *curr; curr++) { + bb_unsetenv(*curr); free(*curr); + } free(envp); } diff --git a/release/src/router/busybox/networking/udhcp/serverpacket.c b/release/src/router/busybox/networking/udhcp/serverpacket.c index fc6249725e..8b0f1856bf 100644 --- a/release/src/router/busybox/networking/udhcp/serverpacket.c +++ b/release/src/router/busybox/networking/udhcp/serverpacket.c @@ -50,7 +50,7 @@ static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcas DEBUG("unicasting packet to client ciaddr"); ciaddr = payload->ciaddr; chaddr = payload->chaddr; - } else if (ntohs(payload->flags) & BROADCAST_FLAG) { + } else if (payload->flags & htons(BROADCAST_FLAG)) { DEBUG("broadcasting packet to client (requested)"); ciaddr = INADDR_BROADCAST; chaddr = MAC_BCAST_ADDR; @@ -59,8 +59,10 @@ static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcas ciaddr = payload->yiaddr; chaddr = payload->chaddr; } - return udhcp_send_raw_packet(payload, server_config.server, SERVER_PORT, - ciaddr, CLIENT_PORT, chaddr, server_config.ifindex); + return udhcp_send_raw_packet(payload, + /*src*/ server_config.server, SERVER_PORT, + /*dst*/ ciaddr, CLIENT_PORT, chaddr, + server_config.ifindex); } @@ -97,78 +99,75 @@ static void add_bootp_options(struct dhcpMessage *packet) /* send a DHCP OFFER to a DHCP DISCOVER */ -int send_offer(struct dhcpMessage *oldpacket) +int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; - struct dhcpOfferedAddr *lease = NULL; - uint32_t req_align, lease_time_align = server_config.lease; - uint8_t *req, *lease_time; + uint32_t req_align; + uint32_t lease_time_aligned = server_config.lease; + uint32_t static_lease_ip; + uint8_t *req, *lease_time, *p_host_name; struct option_set *curr; struct in_addr addr; - uint32_t static_lease_ip; - init_packet(&packet, oldpacket, DHCPOFFER); static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); /* ADDME: if static, short circuit */ if (!static_lease_ip) { - /* the client is in our lease/offered table */ + struct dhcpOfferedAddr *lease; + lease = find_lease_by_chaddr(oldpacket->chaddr); + /* the client is in our lease/offered table */ if (lease) { - if (!lease_expired(lease)) - lease_time_align = lease->expires - time(0); + signed_leasetime_t tmp = lease->expires - time(NULL); + if (tmp >= 0) + lease_time_aligned = tmp; packet.yiaddr = lease->yiaddr; - /* Or the client has a requested ip */ - } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) + /* Or the client has requested an ip */ + } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL /* Don't look here (ugly hackish thing to do) */ - && memcpy(&req_align, req, 4) + && (move_from_unaligned32(req_align, req), 1) /* and the ip is in the lease range */ && ntohl(req_align) >= server_config.start_ip && ntohl(req_align) <= server_config.end_ip - && !static_lease_ip /* Check that its not a static lease */ /* and is not already taken/offered */ && (!(lease = find_lease_by_yiaddr(req_align)) - /* or its taken, but expired */ /* ADDME: or maybe in here */ + /* or its taken, but expired */ || lease_expired(lease)) ) { - packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ - /* otherwise, find a free IP */ + packet.yiaddr = req_align; + /* otherwise, find a free IP */ } else { - /* Is it a static lease? (No, because find_address skips static lease) */ - packet.yiaddr = find_address(0); - /* try for an expired lease */ - if (!packet.yiaddr) - packet.yiaddr = find_address(1); + packet.yiaddr = find_free_or_expired_address(); } if (!packet.yiaddr) { bb_error_msg("no IP addresses to give - OFFER abandoned"); return -1; } - if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) { bb_error_msg("lease pool is full - OFFER abandoned"); return -1; } lease_time = get_option(oldpacket, DHCP_LEASE_TIME); if (lease_time) { - memcpy(&lease_time_align, lease_time, 4); - lease_time_align = ntohl(lease_time_align); - if (lease_time_align > server_config.lease) - lease_time_align = server_config.lease; + move_from_unaligned32(lease_time_aligned, lease_time); + lease_time_aligned = ntohl(lease_time_aligned); + if (lease_time_aligned > server_config.lease) + lease_time_aligned = server_config.lease; } /* Make sure we aren't just using the lease time from the previous offer */ - if (lease_time_align < server_config.min_lease) - lease_time_align = server_config.lease; - /* ADDME: end of short circuit */ + if (lease_time_aligned < server_config.min_lease) + lease_time_aligned = server_config.min_lease; } else { /* It is a static lease... use it */ packet.yiaddr = static_lease_ip; } - add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); + add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned)); curr = server_config.options; while (curr) { @@ -185,7 +184,7 @@ int send_offer(struct dhcpMessage *oldpacket) } -int send_NAK(struct dhcpMessage *oldpacket) +int FAST_FUNC send_NAK(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; @@ -196,28 +195,29 @@ int send_NAK(struct dhcpMessage *oldpacket) } -int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) +int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) { struct dhcpMessage packet; struct option_set *curr; uint8_t *lease_time; - uint32_t lease_time_align = server_config.lease; + uint32_t lease_time_aligned = server_config.lease; struct in_addr addr; + uint8_t *p_host_name; init_packet(&packet, oldpacket, DHCPACK); packet.yiaddr = yiaddr; lease_time = get_option(oldpacket, DHCP_LEASE_TIME); if (lease_time) { - memcpy(&lease_time_align, lease_time, 4); - lease_time_align = ntohl(lease_time_align); - if (lease_time_align > server_config.lease) - lease_time_align = server_config.lease; - else if (lease_time_align < server_config.min_lease) - lease_time_align = server_config.lease; + move_from_unaligned32(lease_time_aligned, lease_time); + lease_time_aligned = ntohl(lease_time_aligned); + if (lease_time_aligned > server_config.lease) + lease_time_aligned = server_config.lease; + else if (lease_time_aligned < server_config.min_lease) + lease_time_aligned = server_config.min_lease; } - add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); + add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned)); curr = server_config.options; while (curr) { @@ -234,7 +234,8 @@ int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) if (send_packet(&packet, 0) < 0) return -1; - add_lease(packet.chaddr, packet.yiaddr, lease_time_align); + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name); if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { /* rewrite the file with leases at every new acceptance */ write_leases(); @@ -244,7 +245,7 @@ int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) } -int send_inform(struct dhcpMessage *oldpacket) +int FAST_FUNC send_inform(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; struct option_set *curr; diff --git a/release/src/router/busybox/networking/udhcp/signalpipe.c b/release/src/router/busybox/networking/udhcp/signalpipe.c index 1486b3b2db..a025bd8b5d 100644 --- a/release/src/router/busybox/networking/udhcp/signalpipe.c +++ b/release/src/router/busybox/networking/udhcp/signalpipe.c @@ -35,7 +35,7 @@ static void signal_handler(int sig) /* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ -void udhcp_sp_setup(void) +void FAST_FUNC udhcp_sp_setup(void) { /* was socketpair, but it needs AF_UNIX in kernel */ xpiped_pair(signal_pipe); @@ -53,7 +53,7 @@ void udhcp_sp_setup(void) /* Quick little function to setup the rfds. Will return the * max_fd for use with select. Limited in that you can only pass * one extra fd */ -int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) +int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd) { FD_ZERO(rfds); FD_SET(signal_pipe.rd, rfds); @@ -68,7 +68,7 @@ int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) /* Read a signal from the signal pipe. Returns 0 if there is * no signal, -1 on error (and sets errno appropriately), and * your signal on success */ -int udhcp_sp_read(const fd_set *rfds) +int FAST_FUNC udhcp_sp_read(const fd_set *rfds) { unsigned char sig; diff --git a/release/src/router/busybox/networking/udhcp/socket.c b/release/src/router/busybox/networking/udhcp/socket.c index 2cbd4aa884..edf4355b50 100644 --- a/release/src/router/busybox/networking/udhcp/socket.c +++ b/release/src/router/busybox/networking/udhcp/socket.c @@ -37,7 +37,7 @@ #include "common.h" -int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) +int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) { int fd; struct ifreq ifr; @@ -47,7 +47,7 @@ int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, interface); if (addr) { if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, "is interface %s up and configured?", interface) @@ -57,7 +57,7 @@ int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t } our_ip = (struct sockaddr_in *) &ifr.ifr_addr; *addr = our_ip->sin_addr.s_addr; - DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); + DEBUG("ip of %s = %s", interface, inet_ntoa(our_ip->sin_addr)); } if (ifindex) { @@ -85,10 +85,9 @@ int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t /* 1. None of the callers expects it to ever fail */ /* 2. ip was always INADDR_ANY */ -int listen_socket(/*uint32_t ip,*/ int port, const char *inf) +int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) { int fd; - struct ifreq interface; struct sockaddr_in addr; DEBUG("Opening listen socket on *:%d %s", port, inf); @@ -98,9 +97,9 @@ int listen_socket(/*uint32_t ip,*/ int port, const char *inf) if (setsockopt_broadcast(fd) == -1) bb_perror_msg_and_die("SO_BROADCAST"); - strncpy(interface.ifr_name, inf, IFNAMSIZ); - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) == -1) - bb_perror_msg_and_die("SO_BINDTODEVICE"); + /* 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.sin_family = AF_INET; diff --git a/release/src/router/busybox/networking/udhcp/static_leases.c b/release/src/router/busybox/networking/udhcp/static_leases.c index aabfb81aaa..1e77a58f9d 100644 --- a/release/src/router/busybox/networking/udhcp/static_leases.c +++ b/release/src/router/busybox/networking/udhcp/static_leases.c @@ -5,6 +5,7 @@ * * Wade Berrier September 2004 * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "common.h" @@ -14,85 +15,64 @@ /* Takes the address of the pointer to the static_leases linked list, * Address to a 6 byte mac address * Address to a 4 byte ip address */ -int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip) +void FAST_FUNC addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip) { - struct static_lease *cur; struct static_lease *new_static_lease; /* Build new node */ - new_static_lease = xmalloc(sizeof(struct static_lease)); - new_static_lease->mac = mac; + new_static_lease = xzalloc(sizeof(struct static_lease)); + memcpy(new_static_lease->mac, mac, 6); new_static_lease->ip = ip; - new_static_lease->next = NULL; + /*new_static_lease->next = NULL;*/ /* If it's the first node to be added... */ if (*lease_struct == NULL) { *lease_struct = new_static_lease; } else { - cur = *lease_struct; - while (cur->next) { + struct static_lease *cur = *lease_struct; + while (cur->next) cur = cur->next; - } - cur->next = new_static_lease; } - - return 1; } /* Check to see if a mac has an associated static lease */ -uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) +uint32_t FAST_FUNC getIpByMac(struct static_lease *lease_struct, void *mac) { - uint32_t return_ip; - struct static_lease *cur = lease_struct; - uint8_t *mac = arg; - - return_ip = 0; - - while (cur) { - /* If the client has the correct mac */ - if (memcmp(cur->mac, mac, 6) == 0) { - return_ip = *(cur->ip); - } - - cur = cur->next; + while (lease_struct) { + if (memcmp(lease_struct->mac, mac, 6) == 0) + return lease_struct->ip; + lease_struct = lease_struct->next; } - return return_ip; + return 0; } /* Check to see if an ip is reserved as a static ip */ -uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip) +int FAST_FUNC reservedIp(struct static_lease *lease_struct, uint32_t ip) { - struct static_lease *cur = lease_struct; - - uint32_t return_val = 0; - - while (cur) { - /* If the client has the correct ip */ - if (*cur->ip == ip) - return_val = 1; - - cur = cur->next; + while (lease_struct) { + if (lease_struct->ip == ip) + return 1; + lease_struct = lease_struct->next; } - return return_val; + return 0; } -#if ENABLE_FEATURE_UDHCP_DEBUG +#if ENABLE_UDHCP_DEBUG /* Print out static leases just to check what's going on */ /* Takes the address of the pointer to the static_leases linked list */ -void printStaticLeases(struct static_lease **arg) +void FAST_FUNC printStaticLeases(struct static_lease **arg) { - /* Get a pointer to the linked list */ struct static_lease *cur = *arg; while (cur) { - /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */ - printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac)); - /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */ - printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip)); - + printf("PrintStaticLeases: Lease mac Value: %02x:%02x:%02x:%02x:%02x:%02x\n", + cur->mac[0], cur->mac[1], cur->mac[2], + cur->mac[3], cur->mac[4], cur->mac[5] + ); + printf("PrintStaticLeases: Lease ip Value: %x\n", cur->ip); cur = cur->next; } } diff --git a/release/src/router/busybox/networking/vconfig.c b/release/src/router/busybox/networking/vconfig.c index 3f12e7609c..00379fc2f9 100644 --- a/release/src/router/busybox/networking/vconfig.c +++ b/release/src/router/busybox/networking/vconfig.c @@ -50,13 +50,14 @@ struct vlan_ioctl_args { #define VLAN_GROUP_ARRAY_LEN 4096 #define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ -/* On entry, table points to the length of the current string plus - * nul terminator plus data length for the subsequent entry. The - * return value is the last data entry for the matching string. */ +/* On entry, table points to the length of the current string + * plus NUL terminator plus data length for the subsequent entry. + * 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) { - if (!*(table += table[0])) { + table += table[0]; + if (!*table) { bb_show_usage(); } } @@ -121,7 +122,7 @@ int vconfig_main(int argc, char **argv) /* Will die if 802.1q is not present */ xopen(conf_file_name, O_RDONLY); - memset(&ifr, 0, sizeof(struct vlan_ioctl_args)); + memset(&ifr, 0, sizeof(ifr)); ++argv; p = xfind_str(cmds+2, *argv); @@ -133,7 +134,7 @@ int vconfig_main(int argc, char **argv) if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ ifr.u.name_type = *xfind_str(name_types+1, argv[1]); } else { - strncpy(ifr.device1, argv[1], IFNAMSIZ); + strncpy_IFNAMSIZ(ifr.device1, argv[1]); p = argv[2]; /* I suppose one could try to combine some of the function calls below, diff --git a/release/src/router/busybox/networking/wget.c b/release/src/router/busybox/networking/wget.c index d782cc4fea..48759049df 100644 --- a/release/src/router/busybox/networking/wget.c +++ b/release/src/router/busybox/networking/wget.c @@ -4,6 +4,7 @@ * * Chip Rosenthal Covad Communications * + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "libbb.h" @@ -54,14 +55,14 @@ enum { STALLTIME = 5 /* Seconds when xfer considered "stalled" */ }; -static unsigned int getttywidth(void) +static unsigned int get_tty2_width(void) { unsigned width; - get_terminal_width_height(0, &width, NULL); + get_terminal_width_height(2, &width, NULL); return width; } -static void progressmeter(int flag) +static void progress_meter(int flag) { /* We can be called from signal handler */ int save_errno = errno; @@ -70,7 +71,7 @@ static void progressmeter(int flag) unsigned ratio; int barlength, i; - if (flag == -1) { /* first call to progressmeter */ + if (flag == -1) { /* first call to progress_meter */ start_sec = monotonic_sec(); lastupdate_sec = start_sec; lastsize = 0; @@ -86,7 +87,7 @@ static void progressmeter(int flag) fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio); - barlength = getttywidth() - 49; + barlength = get_tty2_width() - 49; if (barlength > 0) { /* god bless gcc for variable arrays :) */ i = barlength * ratio / 100; @@ -138,13 +139,13 @@ static void progressmeter(int flag) } if (flag == 0) { - /* last call to progressmeter */ + /* last call to progress_meter */ alarm(0); transferred = 0; fputc('\n', stderr); } else { - if (flag == -1) { /* first call to progressmeter */ - signal_SA_RESTART_empty_mask(SIGALRM, progressmeter); + if (flag == -1) { /* first call to progress_meter */ + signal_SA_RESTART_empty_mask(SIGALRM, progress_meter); } alarm(1); } @@ -188,7 +189,7 @@ static void progressmeter(int flag) */ #else /* FEATURE_WGET_STATUSBAR */ -static ALWAYS_INLINE void progressmeter(int flag UNUSED_PARAM) { } +static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { } #endif @@ -202,6 +203,7 @@ static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) do { clearerr(stream); + errno = 0; ret = fread(p, 1, nmemb, stream); p += ret; nmemb -= ret; @@ -218,6 +220,7 @@ static char *safe_fgets(char *s, int size, FILE *stream) do { clearerr(stream); + errno = 0; ret = fgets(s, size, stream); } while (ret == NULL && ferror(stream) && errno == EINTR); @@ -384,6 +387,43 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) 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 int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wget_main(int argc UNUSED_PARAM, char **argv) @@ -399,6 +439,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) char *proxy = 0; char *dir_prefix = NULL; #if ENABLE_FEATURE_WGET_LONG_OPTIONS + char *post_data; char *extra_headers = NULL; llist_t *headers_llist = NULL; #endif @@ -417,15 +458,18 @@ int wget_main(int argc UNUSED_PARAM, char **argv) KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location }; enum { - WGET_OPT_CONTINUE = 0x1, - WGET_OPT_SPIDER = 0x2, - WGET_OPT_QUIET = 0x4, - WGET_OPT_OUTNAME = 0x8, - WGET_OPT_PREFIX = 0x10, - WGET_OPT_PROXY = 0x20, - WGET_OPT_USER_AGENT = 0x40, - WGET_OPT_PASSIVE = 0x80, - WGET_OPT_HEADER = 0x100, + WGET_OPT_CONTINUE = (1 << 0), + WGET_OPT_SPIDER = (1 << 1), + WGET_OPT_QUIET = (1 << 2), + WGET_OPT_OUTNAME = (1 << 3), + WGET_OPT_PREFIX = (1 << 4), + WGET_OPT_PROXY = (1 << 5), + WGET_OPT_USER_AGENT = (1 << 6), + WGET_OPT_RETRIES = (1 << 7), + WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 8), + WGET_OPT_PASSIVE = (1 << 9), + WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, + WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, }; #if ENABLE_FEATURE_WGET_LONG_OPTIONS static const char wget_longopts[] ALIGN1 = @@ -437,8 +481,13 @@ int wget_main(int argc UNUSED_PARAM, char **argv) "directory-prefix\0" Required_argument "P" "proxy\0" Required_argument "Y" "user-agent\0" Required_argument "U" + /* Ignored: */ + // "tries\0" Required_argument "t" + // "timeout\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" ; #endif @@ -455,6 +504,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) NULL, /* -t RETRIES */ NULL /* -T NETWORK_READ_TIMEOUT */ USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) + USE_FEATURE_WGET_LONG_OPTIONS(, &post_data) ); if (strcmp(proxy_flag, "off") == 0) { /* Use the proxy if necessary */ @@ -555,7 +605,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv) target.is_ftp ? "f" : "ht", target.host, target.path); } else { - fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); + if (opt & 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", @@ -577,12 +630,24 @@ int wget_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (extra_headers) fputs(extra_headers, sfp); + + if (opt & WGET_OPT_POST_DATA) { + char *estr = URL_escape(post_data); + fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n"); + fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s", + (int) strlen(estr), estr); + /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/ + /*fprintf(sfp, "%s\r\n", estr);*/ + free(estr); + } else #endif - fprintf(sfp, "Connection: close\r\n\r\n"); + { /* If "Connection:" is needed, document why */ + fprintf(sfp, /* "Connection: close\r\n" */ "\r\n"); + } /* - * Retrieve HTTP response line and check for "200" status code. - */ + * 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"); @@ -765,7 +830,7 @@ However, in real world it was observed that some web servers * Retrieve file */ - /* Do it before progressmeter (want to have nice error message) */ + /* Do it before progress_meter (want to have nice error message) */ if (output_fd < 0) { int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; /* compat with wget: -O FILE can overwrite */ @@ -775,7 +840,7 @@ However, in real world it was observed that some web servers } if (!(opt & WGET_OPT_QUIET)) - progressmeter(-1); + progress_meter(-1); if (chunked) goto get_clen; @@ -817,7 +882,7 @@ However, in real world it was observed that some web servers } if (!(opt & WGET_OPT_QUIET)) - progressmeter(0); + progress_meter(0); if ((use_proxy == 0) && target.is_ftp) { fclose(dfp); diff --git a/release/src/router/busybox/networking/zcip.c b/release/src/router/busybox/networking/zcip.c index 221edd322a..df4c0ec2de 100644 --- a/release/src/router/busybox/networking/zcip.c +++ b/release/src/router/busybox/networking/zcip.c @@ -75,35 +75,40 @@ enum { }; struct globals { - char *intf; struct sockaddr saddr; + struct ether_addr eth_addr; }; #define G (*(struct globals*)&bb_common_bufsiz1) -#define intf (G.intf ) -#define saddr (G.saddr) +#define saddr (G.saddr ) +#define eth_addr (G.eth_addr) /** * Pick a random link local IP address on 169.254/16, except that * the first and last 256 addresses are reserved. */ -static void pick(struct in_addr *ip) +static uint32_t pick(void) { unsigned tmp; do { tmp = rand() & IN_CLASSB_HOST; } while (tmp > (IN_CLASSB_HOST - 0x0200)); - ip->s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp); + return htonl((LINKLOCAL_ADDR + 0x0100) + tmp); } /** * Broadcast an ARP packet. */ -static void arp(int op, - const struct ether_addr *source_eth, struct in_addr source_ip, +static void arp( + /* int op, - always ARPOP_REQUEST */ + /* const struct ether_addr *source_eth, - always ð_addr */ + struct in_addr source_ip, const struct ether_addr *target_eth, struct in_addr target_ip) { + enum { op = ARPOP_REQUEST }; +#define source_eth (ð_addr) + struct arp_packet p; memset(&p, 0, sizeof(p)); @@ -124,38 +129,44 @@ static void arp(int op, memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa)); // send it + // Even though sock_fd is already bound to saddr, just send() + // won't work, because "socket is not connected" + // (and connect() won't fix that, "operation not supported"). + // Thus we sendto() to saddr. I wonder which sockaddr + // (from bind() or from sendto()?) kernel actually uses + // to determine iface to emit the packet from... xsendto(sock_fd, &p, sizeof(p), &saddr, sizeof(saddr)); - - // Currently all callers ignore errors, that's why returns are - // commented out... - //return 0; +#undef source_eth } /** - * Run a script. argv[2] is already NULL. + * Run a script. + * argv[0]:intf argv[1]:script_name argv[2]:junk argv[3]:NULL */ -static int run(char *argv[3], struct in_addr *ip) +static int run(char *argv[3], const char *param, struct in_addr *ip) { int status; char *addr = addr; /* for gcc */ const char *fmt = "%s %s %s" + 3; - VDBG("%s run %s %s\n", intf, argv[0], argv[1]); + argv[2] = (char*)param; + + VDBG("%s run %s %s\n", argv[0], argv[1], argv[2]); if (ip) { addr = inet_ntoa(*ip); - setenv("ip", addr, 1); + xsetenv("ip", addr); fmt -= 3; } - bb_info_msg(fmt, argv[1], intf, addr); + bb_info_msg(fmt, argv[2], argv[0], addr); - status = wait4pid(spawn(argv)); + status = wait4pid(spawn(argv + 1)); if (status < 0) { - bb_perror_msg("%s %s %s" + 3, argv[1], intf); + bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]); return -errno; } if (status != 0) - bb_error_msg("script %s %s failed, exitcode=%d", argv[0], argv[1], status); + bb_error_msg("script %s %s failed, exitcode=%d", argv[1], argv[2], status); return status; } @@ -173,8 +184,7 @@ static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs) int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int zcip_main(int argc, char **argv) { - int state = PROBE; - struct ether_addr eth_addr; + int state; char *r_opt; unsigned opts; @@ -184,7 +194,6 @@ int zcip_main(int argc, char **argv) const struct ether_addr null_addr; struct in_addr ip; struct ifreq ifr; - char *script_av[3]; int timeout_ms; /* must be signed */ unsigned conflicts; unsigned nprobes; @@ -196,7 +205,6 @@ int zcip_main(int argc, char **argv) #define null_addr (L.null_addr ) #define ip (L.ip ) #define ifr (L.ifr ) -#define script_av (L.script_av ) #define timeout_ms (L.timeout_ms) #define conflicts (L.conflicts ) #define nprobes (L.nprobes ) @@ -234,29 +242,33 @@ int zcip_main(int argc, char **argv) } } argc -= optind; - argv += optind; + argv += optind - 1; + + /* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */ + /* We need to make space for script argument: */ + argv[0] = argv[1]; + argv[1] = argv[2]; + /* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */ +#define argv_intf (argv[0]) - intf = argv[0]; - script_av[0] = argv[1]; - setenv("interface", intf, 1); + xsetenv("interface", argv_intf); // initialize the interface (modprobe, ifup, etc) - script_av[1] = (char*)"init"; - if (run(script_av, NULL)) + if (run(argv, "init", NULL)) return EXIT_FAILURE; // initialize saddr // saddr is: { u16 sa_family; u8 sa_data[14]; } //memset(&saddr, 0, sizeof(saddr)); //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! - safe_strncpy(saddr.sa_data, intf, sizeof(saddr.sa_data)); + safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data)); // bind to the interface's ARP socket xbind(sock_fd, &saddr, sizeof(saddr)); // get the interface's ethernet address //memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name)); + strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); xioctl(sock_fd, SIOCGIFHWADDR, &ifr); memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); @@ -268,11 +280,11 @@ int zcip_main(int argc, char **argv) // depending on when we detect conflicts. { uint32_t t; - memcpy(&t, (char*)ð_addr + 2, 4); + move_from_unaligned32(t, ((char *)ð_addr + 2)); srand(t); } if (ip.s_addr == 0) - pick(&ip); + ip.s_addr = pick(); // FIXME cases to handle: // - zcip already running! @@ -283,7 +295,7 @@ int zcip_main(int argc, char **argv) #if BB_MMU bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); #endif - bb_info_msg("start, interface %s", intf); + bb_info_msg("start, interface %s", argv_intf); } // run the dynamic address negotiation protocol, @@ -294,6 +306,14 @@ int zcip_main(int argc, char **argv) // - arp announcements that we're claiming it // - use it // - defend it, within limits + // exit if: + // - address is successfully obtained and -q was given: + // run ",," \ -e "s,color\.css,<% nv('web_css'); %>\.css," \ @@ -36,7 +36,7 @@ install: # make sure old and debugging crap is gone - @rm -f $(INSTALLDIR)/debug.js + @rm -f $(INSTALLDIR)/www/debug.js @rm -f $(INSTALLDIR)/www/*-x.* @rm -f $(INSTALLDIR)/www/*-old.* @rm -f $(INSTALLDIR)/www/color.css diff --git a/release/src/router/www/about.asp b/release/src/router/www/about.asp index 576d5fdd4f..58799494e6 100644 --- a/release/src/router/www/about.asp +++ b/release/src/router/www/about.asp @@ -1,7 +1,7 @@