aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/Config.in8
-rw-r--r--target/Makefile.in1
-rw-r--r--target/cramfs/Config.in6
-rw-r--r--target/cramfs/Makefile.in3
-rw-r--r--target/cramfs/cramfs.mk52
-rw-r--r--target/cramfs/cramfs.patch1269
-rw-r--r--target/default/device_table.txt162
-rw-r--r--target/default/skel.tar.gzbin0 -> 4846 bytes
-rw-r--r--target/default/target_skeleton/etc/TZ1
-rw-r--r--target/default/target_skeleton/etc/fstab8
-rw-r--r--target/default/target_skeleton/etc/group10
-rw-r--r--target/default/target_skeleton/etc/hostname1
-rw-r--r--target/default/target_skeleton/etc/hosts1
-rwxr-xr-xtarget/default/target_skeleton/etc/init.d/S20urandom44
-rwxr-xr-xtarget/default/target_skeleton/etc/init.d/S40network35
-rwxr-xr-xtarget/default/target_skeleton/etc/init.d/rcS27
-rw-r--r--target/default/target_skeleton/etc/inittab47
-rw-r--r--target/default/target_skeleton/etc/inputrc44
-rw-r--r--target/default/target_skeleton/etc/issue4
-rw-r--r--target/default/target_skeleton/etc/network/interfaces4
-rw-r--r--target/default/target_skeleton/etc/passwd13
-rw-r--r--target/default/target_skeleton/etc/profile48
-rw-r--r--target/default/target_skeleton/etc/protocols31
-rw-r--r--target/default/target_skeleton/etc/random-seedbin0 -> 512 bytes
-rw-r--r--target/default/target_skeleton/etc/resolv.conf2
-rw-r--r--target/default/target_skeleton/etc/securetty12
-rw-r--r--target/default/target_skeleton/etc/services302
-rw-r--r--target/default/target_skeleton/etc/shadow12
-rw-r--r--target/default/target_skeleton/root/.bash_history0
-rw-r--r--target/default/target_skeleton/root/.bash_logout7
-rw-r--r--target/default/target_skeleton/root/.bash_profile15
-rw-r--r--target/default/target_skeleton/root/.bashrc48
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/a/ansibin0 -> 1450 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/d/dumbbin0 -> 308 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/l/linuxbin0 -> 1552 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/r/rxvtbin0 -> 1627 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/s/screenbin0 -> 1318 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/s/screen-wbin0 -> 1334 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/s/sunbin0 -> 1019 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/v/vt100bin0 -> 1143 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/v/vt220bin0 -> 975 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/v/vt52bin0 -> 462 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/x/xtermbin0 -> 1366 bytes
-rw-r--r--target/default/target_skeleton/usr/share/terminfo/x/xterm-xfree86bin0 -> 1840 bytes
-rwxr-xr-xtarget/default/target_skeleton/usr/share/udhcpc/default.script39
-rw-r--r--target/ext2/ext2root.mk55
-rw-r--r--target/ext2/genext2fs.patch2457
-rw-r--r--target/jffs2/jffs2root.mk49
-rw-r--r--target/squashfs/squashfs.patch36
-rw-r--r--target/squashfs/squashfsroot.mk51
50 files changed, 4904 insertions, 0 deletions
diff --git a/target/Config.in b/target/Config.in
new file mode 100644
index 0000000000..dbc631725a
--- /dev/null
+++ b/target/Config.in
@@ -0,0 +1,8 @@
+#
+
+menu "Target Options"
+
+source "target/cramfs/Config.in"
+
+endmenu
+
diff --git a/target/Makefile.in b/target/Makefile.in
new file mode 100644
index 0000000000..c01ade299a
--- /dev/null
+++ b/target/Makefile.in
@@ -0,0 +1 @@
+# Nothing
diff --git a/target/cramfs/Config.in b/target/cramfs/Config.in
new file mode 100644
index 0000000000..2ba1cdece8
--- /dev/null
+++ b/target/cramfs/Config.in
@@ -0,0 +1,6 @@
+config BR2_TARGET_ROOTFS_CRAMFS
+ bool "Build a cramfs root filesystem for the target device"
+ default n
+ help
+ Build a cramfs root filesystem
+
diff --git a/target/cramfs/Makefile.in b/target/cramfs/Makefile.in
new file mode 100644
index 0000000000..45d9b67ce6
--- /dev/null
+++ b/target/cramfs/Makefile.in
@@ -0,0 +1,3 @@
+ifeq ($(strip $(BR2_TARGET_ROOTFS_CRAMFS)),y)
+TARGETS+=cramfsroot
+endif
diff --git a/target/cramfs/cramfs.mk b/target/cramfs/cramfs.mk
new file mode 100644
index 0000000000..0f1204a258
--- /dev/null
+++ b/target/cramfs/cramfs.mk
@@ -0,0 +1,52 @@
+#############################################################
+#
+# mkcramfs to build to target cramfs filesystems
+#
+#############################################################
+CRAMFS_DIR=$(BUILD_DIR)/cramfs-1.1
+CRAMFS_SOURCE=cramfs-1.1.tar.gz
+CRAMFS_SITE=http://aleron.dl.sourceforge.net/sourceforge/cramfs
+CRAMFS_PATCH=$(SOURCE_DIR)/cramfs.patch
+
+$(DL_DIR)/$(CRAMFS_SOURCE):
+ $(WGET) -P $(DL_DIR) $(CRAMFS_SITE)/$(CRAMFS_SOURCE)
+
+$(CRAMFS_DIR): $(DL_DIR)/$(CRAMFS_SOURCE) $(CRAMFS_PATCH)
+ zcat $(DL_DIR)/$(CRAMFS_SOURCE) | tar -C $(BUILD_DIR) -xvf -
+ cat $(CRAMFS_PATCH) | patch -p1 -d $(CRAMFS_DIR)
+
+$(CRAMFS_DIR)/mkcramfs: $(CRAMFS_DIR)
+ $(MAKE) CFLAGS="-Wall -O2 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" -C $(CRAMFS_DIR);
+ touch -c $(CRAMFS_DIR)/mkcramfs
+
+cramfs: $(CRAMFS_DIR)/mkcramfs
+
+cramfs-source: $(DL_DIR)/$(CRAMFS_SOURCE)
+
+cramfs-clean:
+ -$(MAKE) -C $(CRAMFS_DIR) clean
+
+cramfs-dirclean:
+ rm -rf $(CRAMFS_DIR)
+
+#############################################################
+#
+# Build the cramfs root filesystem image
+#
+#############################################################
+
+cramfsroot: cramfs
+ #-@find $(TARGET_DIR)/lib -type f -name \*.so\* | xargs $(STRIP) --strip-unneeded 2>/dev/null || true;
+ -@find $(TARGET_DIR) -type f -perm +111 | xargs $(STRIP) 2>/dev/null || true;
+ @rm -rf $(TARGET_DIR)/usr/man
+ @rm -rf $(TARGET_DIR)/usr/info
+ $(CRAMFS_DIR)/mkcramfs -q -D $(SOURCE_DIR)/device_table.txt $(TARGET_DIR) $(IMAGE)
+
+cramfsroot-source: cramfs-source
+
+cramfsroot-clean:
+ -$(MAKE) -C $(CRAMFS_DIR) clean
+
+cramfsroot-dirclean:
+ rm -rf $(CRAMFS_DIR)
+
diff --git a/target/cramfs/cramfs.patch b/target/cramfs/cramfs.patch
new file mode 100644
index 0000000000..884eb8cb83
--- /dev/null
+++ b/target/cramfs/cramfs.patch
@@ -0,0 +1,1269 @@
+--- cramfs-1.1.orig/cramfsck.c 2002-02-22 17:00:42.000000000 -0700
++++ cramfs-1.1/cramfsck.c 2002-12-21 01:25:17.000000000 -0700
+@@ -51,10 +51,11 @@
+ #include <utime.h>
+ #include <sys/ioctl.h>
+ #define _LINUX_STRING_H_
+-#include <linux/fs.h>
+-#include <linux/cramfs_fs.h>
++#include "linux/cramfs_fs.h"
+ #include <zlib.h>
+
++#define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
++
+ /* Exit codes used by fsck-type programs */
+ #define FSCK_OK 0 /* No errors */
+ #define FSCK_NONDESTRUCT 1 /* File system errors corrected */
+@@ -75,7 +76,7 @@
+ static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */
+ #ifdef INCLUDE_FS_TESTS
+ static int opt_extract = 0; /* extract cramfs (-x) */
+-static char *extract_dir = "root"; /* extraction directory (-x) */
++static char *extract_dir = "/"; /* extraction directory (-x) */
+ static uid_t euid; /* effective UID */
+
+ /* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */
+@@ -155,7 +156,7 @@
+ }
+
+ if (*length < sizeof(struct cramfs_super)) {
+- die(FSCK_UNCORRECTED, 0, "file length too short");
++ die(FSCK_UNCORRECTED, 0, "filesystem smaller than a cramfs superblock!");
+ }
+
+ /* find superblock */
+@@ -190,7 +191,8 @@
+ die(FSCK_UNCORRECTED, 0, "zero file count");
+ }
+ if (*length < super.size) {
+- die(FSCK_UNCORRECTED, 0, "file length too short");
++ die(FSCK_UNCORRECTED, 0, "file length too short, %lu is smaller than %lu",
++ *length, super.size);
+ }
+ else if (*length > super.size) {
+ fprintf(stderr, "warning: file extends past end of filesystem\n");
+@@ -267,11 +269,11 @@
+ #ifdef INCLUDE_FS_TESTS
+ static void print_node(char type, struct cramfs_inode *i, char *name)
+ {
+- char info[10];
++ char info[11];
+
+ if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) {
+ /* major/minor numbers can be as high as 2^12 or 4096 */
+- snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size));
++ snprintf(info, 11, "%4d,%4d", major(i->size), minor(i->size));
+ }
+ else {
+ /* size be as high as 2^24 or 16777216 */
+@@ -445,8 +447,10 @@
+ }
+ /* TODO: Do we need to check end_dir for empty case? */
+ memcpy(newpath, path, pathlen);
+- newpath[pathlen] = '/';
+- pathlen++;
++ if (pathlen > 1) {
++ newpath[pathlen] = '/';
++ pathlen++;
++ }
+ if (opt_verbose) {
+ print_node('d', i, path);
+ }
+--- cramfs-1.1.orig/device_table.txt 1969-12-31 17:00:00.000000000 -0700
++++ cramfs-1.1/device_table.txt 2003-01-01 05:13:44.000000000 -0700
+@@ -0,0 +1,129 @@
++# When building a target filesystem, it is desirable to not have to
++# become root and then run 'mknod' a thousand times. Using a device
++# table you can create device nodes and directories "on the fly".
++#
++# This is a sample device table file for use with mkcramfs. You can
++# do all sorts of interesting things with a device table file. For
++# example, if you want to adjust the permissions on a particular file
++# you can just add an entry like:
++# /sbin/foobar f 2755 0 0 - - - - -
++# and (assuming the file /sbin/foobar exists) it will be made setuid
++# root (regardless of what its permissions are on the host filesystem.
++# Furthermore, you can use a single table entry to create a many device
++# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
++# I could just use the following two table entries:
++# /dev/hda b 640 0 0 3 0 0 0 -
++# /dev/hda b 640 0 0 3 1 1 1 15
++#
++# Device table entries take the form of:
++# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++# where name is the file name, type can be one of:
++# f A regular file
++# d Directory
++# c Character special device file
++# b Block special device file
++# p Fifo (named pipe)
++# uid is the user id for the target file, gid is the group id for the
++# target file. The rest of the entries (major, minor, etc) apply only
++# to device special files.
++
++# Have fun
++# -Erik Andersen <andersen@codepoet.org>
++#
++
++#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++/dev d 755 0 0 - - - - -
++/dev/mem c 640 0 0 1 1 0 0 -
++/dev/kmem c 640 0 0 1 2 0 0 -
++/dev/null c 640 0 0 1 3 0 0 -
++/dev/zero c 640 0 0 1 5 0 0 -
++/dev/random c 640 0 0 1 8 0 0 -
++/dev/urandom c 640 0 0 1 9 0 0 -
++/dev/tty c 666 0 0 5 0 0 0 -
++/dev/tty c 666 0 0 4 0 0 1 6
++/dev/console c 640 0 0 5 1 0 0 -
++/dev/ram b 640 0 0 1 1 0 0 -
++/dev/ram b 640 0 0 1 0 0 1 4
++/dev/loop b 640 0 0 7 0 0 1 2
++/dev/ptmx c 666 0 0 5 2 0 0 -
++#/dev/ttyS c 640 0 0 4 64 0 1 4
++#/dev/psaux c 640 0 0 10 1 0 0 -
++#/dev/rtc c 640 0 0 10 135 0 0 -
++
++# Adjust permissions on some normal files
++#/etc/shadow f 600 0 0 - - - - -
++#/bin/tinylogin f 4755 0 0 - - - - -
++
++# User-mode Linux stuff
++/dev/ubda b 640 0 0 98 0 0 0 -
++/dev/ubda b 640 0 0 98 1 1 1 15
++
++# IDE Devices
++/dev/hda b 640 0 0 3 0 0 0 -
++/dev/hda b 640 0 0 3 1 1 1 15
++/dev/hdb b 640 0 0 3 64 0 0 -
++/dev/hdb b 640 0 0 3 65 1 1 15
++#/dev/hdc b 640 0 0 22 0 0 0 -
++#/dev/hdc b 640 0 0 22 1 1 1 15
++#/dev/hdd b 640 0 0 22 64 0 0 -
++#/dev/hdd b 640 0 0 22 65 1 1 15
++#/dev/hde b 640 0 0 33 0 0 0 -
++#/dev/hde b 640 0 0 33 1 1 1 15
++#/dev/hdf b 640 0 0 33 64 0 0 -
++#/dev/hdf b 640 0 0 33 65 1 1 15
++#/dev/hdg b 640 0 0 34 0 0 0 -
++#/dev/hdg b 640 0 0 34 1 1 1 15
++#/dev/hdh b 640 0 0 34 64 0 0 -
++#/dev/hdh b 640 0 0 34 65 1 1 15
++
++# SCSI Devices
++#/dev/sda b 640 0 0 8 0 0 0 -
++#/dev/sda b 640 0 0 8 1 1 1 15
++#/dev/sdb b 640 0 0 8 16 0 0 -
++#/dev/sdb b 640 0 0 8 17 1 1 15
++#/dev/sdc b 640 0 0 8 32 0 0 -
++#/dev/sdc b 640 0 0 8 33 1 1 15
++#/dev/sdd b 640 0 0 8 48 0 0 -
++#/dev/sdd b 640 0 0 8 49 1 1 15
++#/dev/sde b 640 0 0 8 64 0 0 -
++#/dev/sde b 640 0 0 8 65 1 1 15
++#/dev/sdf b 640 0 0 8 80 0 0 -
++#/dev/sdf b 640 0 0 8 81 1 1 15
++#/dev/sdg b 640 0 0 8 96 0 0 -
++#/dev/sdg b 640 0 0 8 97 1 1 15
++#/dev/sdh b 640 0 0 8 112 0 0 -
++#/dev/sdh b 640 0 0 8 113 1 1 15
++#/dev/sg c 640 0 0 21 0 0 1 15
++#/dev/scd b 640 0 0 11 0 0 1 15
++#/dev/st c 640 0 0 9 0 0 1 8
++#/dev/nst c 640 0 0 9 128 0 1 8
++#/dev/st c 640 0 0 9 32 1 1 4
++#/dev/st c 640 0 0 9 64 1 1 4
++#/dev/st c 640 0 0 9 96 1 1 4
++
++# Floppy disk devices
++#/dev/fd b 640 0 0 2 0 0 1 2
++#/dev/fd0d360 b 640 0 0 2 4 0 0 -
++#/dev/fd1d360 b 640 0 0 2 5 0 0 -
++#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
++#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
++#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
++#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
++#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
++#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
++
++# All the proprietary cdrom devices in the world
++#/dev/aztcd b 640 0 0 29 0 0 0 -
++#/dev/bpcd b 640 0 0 41 0 0 0 -
++#/dev/capi20 c 640 0 0 68 0 0 1 2
++#/dev/cdu31a b 640 0 0 15 0 0 0 -
++#/dev/cdu535 b 640 0 0 24 0 0 0 -
++#/dev/cm206cd b 640 0 0 32 0 0 0 -
++#/dev/sjcd b 640 0 0 18 0 0 0 -
++#/dev/sonycd b 640 0 0 15 0 0 0 -
++#/dev/gscd b 640 0 0 16 0 0 0 -
++#/dev/sbpcd b 640 0 0 25 0 0 0 -
++#/dev/sbpcd b 640 0 0 25 0 0 1 4
++#/dev/mcd b 640 0 0 23 0 0 0 -
++#/dev/optcd b 640 0 0 17 0 0 0 -
++
+--- cramfs-1.1.orig/mkcramfs.c 2002-02-20 01:03:32.000000000 -0700
++++ cramfs-1.1/mkcramfs.c 2002-12-21 01:25:17.000000000 -0700
+@@ -1,3 +1,4 @@
++/* vi: set sw=8 ts=8: */
+ /*
+ * mkcramfs - make a cramfs file system
+ *
+@@ -16,12 +17,21 @@
+ * 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
++ *
++ * Added device table support (code taken from mkfs.jffs2.c, credit to
++ * Erik Andersen <andersen@codepoet.org>) as well as an option to squash
++ * permissions. - Russ Dill <Russ.Dill@asu.edu> September 2002
++ *
++ * Reworked, cleaned up, and updated for cramfs-1.1, December 2002
++ * - Erik Andersen <andersen@codepoet.org>
++ *
+ */
+
+ /*
+ * If you change the disk format of cramfs, please update fs/cramfs/README.
+ */
+
++#define _GNU_SOURCE
+ #include <sys/types.h>
+ #include <stdio.h>
+ #include <sys/stat.h>
+@@ -33,8 +43,15 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <stdarg.h>
++#include <libgen.h>
++#include <ctype.h>
++#include <assert.h>
++#include <getopt.h>
+ #include <linux/cramfs_fs.h>
+ #include <zlib.h>
++#ifdef DMALLOC
++#include <dmalloc.h>
++#endif
+
+ /* Exit codes used by mkfs-type programs */
+ #define MKFS_OK 0 /* No errors */
+@@ -71,11 +88,17 @@
+ + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
+ + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
+
++
++/* The kernel assumes PAGE_CACHE_SIZE as block size. */
++#define PAGE_CACHE_SIZE (4096)
++
++
+ static const char *progname = "mkcramfs";
+ static unsigned int blksize = PAGE_CACHE_SIZE;
+ static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
+ static int image_length = 0;
+
++
+ /*
+ * If opt_holes is set, then mkcramfs can create explicit holes in the
+ * data, which saves 26 bytes per hole (which is a lot smaller a
+@@ -91,10 +114,12 @@
+ static int opt_holes = 0;
+ static int opt_pad = 0;
+ static int opt_verbose = 0;
++static int opt_squash = 0;
+ static char *opt_image = NULL;
+ static char *opt_name = NULL;
+
+ static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
++static const char *const memory_exhausted = "memory exhausted";
+
+ /* In-core version of inode / directory entry. */
+ struct entry {
+@@ -123,7 +148,7 @@
+ {
+ FILE *stream = status ? stderr : stdout;
+
+- fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
++ fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] [-D file] dirname outfile\n"
+ " -h print this help\n"
+ " -E make all warnings errors (non-zero exit status)\n"
+ " -e edition set edition number (part of fsid)\n"
+@@ -133,39 +158,157 @@
+ " -s sort directory entries (old option, ignored)\n"
+ " -v be more verbose\n"
+ " -z make explicit holes (requires >= 2.3.39)\n"
+- " dirname root of the directory tree to be compressed\n"
++ " -D Use the named FILE as a device table file\n"
++ " -q squash permissions (make everything owned by root)\n"
++ " dirname root of the filesystem to be compressed\n"
+ " outfile output file\n", progname, PAD_SIZE);
+
+ exit(status);
+ }
+
+-static void die(int status, int syserr, const char *fmt, ...)
++static void verror_msg(const char *s, va_list p)
++{
++ fflush(stdout);
++ fprintf(stderr, "mkcramfs: ");
++ vfprintf(stderr, s, p);
++}
++
++static void vperror_msg(const char *s, va_list p)
++{
++ int err = errno;
++
++ if (s == 0)
++ s = "";
++ verror_msg(s, p);
++ if (*s)
++ s = ": ";
++ fprintf(stderr, "%s%s\n", s, strerror(err));
++}
++
++static void perror_msg(const char *s, ...)
++{
++ va_list p;
++
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++}
++
++static void error_msg_and_die(const char *s, ...)
++{
++ va_list p;
++
++ va_start(p, s);
++ verror_msg(s, p);
++ va_end(p);
++ putc('\n', stderr);
++ exit(MKFS_ERROR);
++}
++
++static void perror_msg_and_die(const char *s, ...)
++{
++ va_list p;
++
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++ exit(MKFS_ERROR);
++}
++#ifndef DMALLOC
++extern char *xstrdup(const char *s)
++{
++ char *t;
++
++ if (s == NULL)
++ return NULL;
++ t = strdup(s);
++ if (t == NULL)
++ error_msg_and_die(memory_exhausted);
++ return t;
++}
++
++extern void *xmalloc(size_t size)
++{
++ void *ptr = malloc(size);
++
++ if (ptr == NULL && size != 0)
++ error_msg_and_die(memory_exhausted);
++ return ptr;
++}
++
++extern void *xcalloc(size_t nmemb, size_t size)
++{
++ void *ptr = calloc(nmemb, size);
++
++ if (ptr == NULL && nmemb != 0 && size != 0)
++ error_msg_and_die(memory_exhausted);
++ return ptr;
++}
++
++extern void *xrealloc(void *ptr, size_t size)
++{
++ ptr = realloc(ptr, size);
++ if (ptr == NULL && size != 0)
++ error_msg_and_die(memory_exhausted);
++ return ptr;
++}
++#endif
++
++static FILE *xfopen(const char *path, const char *mode)
+ {
+- va_list arg_ptr;
+- int save = errno;
++ FILE *fp;
++
++ if ((fp = fopen(path, mode)) == NULL)
++ perror_msg_and_die("%s", path);
++ return fp;
++}
+
+- fflush(0);
+- va_start(arg_ptr, fmt);
+- fprintf(stderr, "%s: ", progname);
+- vfprintf(stderr, fmt, arg_ptr);
+- if (syserr) {
+- fprintf(stderr, ": %s", strerror(save));
++extern int xopen(const char *pathname, int flags, mode_t mode)
++{
++ int ret;
++
++ if (flags & O_CREAT)
++ ret = open(pathname, flags, mode);
++ else
++ ret = open(pathname, flags);
++ if (ret == -1) {
++ perror_msg_and_die("%s", pathname);
+ }
+- fprintf(stderr, "\n");
+- va_end(arg_ptr);
+- exit(status);
++ return ret;
+ }
+
++extern char *xreadlink(const char *path)
++{
++ static const int GROWBY = 80; /* how large we will grow strings by */
++
++ char *buf = NULL;
++ int bufsize = 0, readsize = 0;
++
++ do {
++ buf = xrealloc(buf, bufsize += GROWBY);
++ readsize = readlink(path, buf, bufsize); /* 1st try */
++ if (readsize == -1) {
++ perror_msg("%s:%s", progname, path);
++ return NULL;
++ }
++ }
++ while (bufsize < readsize + 1);
++
++ buf[readsize] = '\0';
++
++ return buf;
++}
++
+ static void map_entry(struct entry *entry)
+ {
+ if (entry->path) {
+ entry->fd = open(entry->path, O_RDONLY);
+ if (entry->fd < 0) {
+- die(MKFS_ERROR, 1, "open failed: %s", entry->path);
++ error_msg_and_die("open failed: %s", entry->path);
+ }
+ entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, entry->fd, 0);
+ if (entry->uncompressed == MAP_FAILED) {
+- die(MKFS_ERROR, 1, "mmap failed: %s", entry->path);
++ error_msg_and_die("mmap failed: %s", entry->path);
+ }
+ }
+ }
+@@ -174,8 +317,9 @@
+ {
+ if (entry->path) {
+ if (munmap(entry->uncompressed, entry->size) < 0) {
+- die(MKFS_ERROR, 1, "munmap failed: %s", entry->path);
++ error_msg_and_die("munmap failed: %s", entry->path);
+ }
++ entry->uncompressed=NULL;
+ close(entry->fd);
+ }
+ }
+@@ -204,7 +348,8 @@
+ find_identical_file(orig->next, newfile));
+ }
+
+-static void eliminate_doubles(struct entry *root, struct entry *orig) {
++static void eliminate_doubles(struct entry *root, struct entry *orig)
++{
+ if (orig) {
+ if (orig->size && (orig->path || orig->uncompressed))
+ find_identical_file(root, orig);
+@@ -232,10 +377,7 @@
+
+ /* Set up the path. */
+ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
+- path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
+- if (!path) {
+- die(MKFS_ERROR, 1, "malloc failed");
+- }
++ path = xmalloc(len + 1 + MAX_INPUT_NAMELEN + 1);
+ memcpy(path, name, len);
+ endpath = path + len;
+ *endpath = '/';
+@@ -245,7 +387,7 @@
+ dircount = scandir(name, &dirlist, 0, cramsort);
+
+ if (dircount < 0) {
+- die(MKFS_ERROR, 1, "scandir failed: %s", name);
++ error_msg_and_die("scandir failed: %s", name);
+ }
+
+ /* process directory */
+@@ -269,25 +411,20 @@
+ }
+ namelen = strlen(dirent->d_name);
+ if (namelen > MAX_INPUT_NAMELEN) {
+- die(MKFS_ERROR, 0,
+- "very long (%u bytes) filename found: %s\n"
+- "please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile",
++ error_msg_and_die(
++ "Very long (%u bytes) filename `%s' found.\n"
++ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n",
+ namelen, dirent->d_name);
+ }
+ memcpy(endpath, dirent->d_name, namelen + 1);
+
+ if (lstat(path, &st) < 0) {
++ perror(endpath);
+ warn_skip = 1;
+ continue;
+ }
+- entry = calloc(1, sizeof(struct entry));
+- if (!entry) {
+- die(MKFS_ERROR, 1, "calloc failed");
+- }
+- entry->name = strdup(dirent->d_name);
+- if (!entry->name) {
+- die(MKFS_ERROR, 1, "strdup failed");
+- }
++ entry = xcalloc(1, sizeof(struct entry));
++ entry->name = xstrdup(dirent->d_name);
+ /* truncate multi-byte UTF-8 filenames on character boundary */
+ if (namelen > CRAMFS_MAXPATHLEN) {
+ namelen = CRAMFS_MAXPATHLEN;
+@@ -297,24 +434,25 @@
+ namelen--;
+ /* are we reasonably certain it was UTF-8 ? */
+ if (entry->name[namelen] < 0x80 || !namelen) {
+- die(MKFS_ERROR, 0, "cannot truncate filenames not encoded in UTF-8");
++ error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
+ }
+ }
+ entry->name[namelen] = '\0';
+ }
+ entry->mode = st.st_mode;
+ entry->size = st.st_size;
+- entry->uid = st.st_uid;
++ entry->uid = opt_squash ? 0 : st.st_uid;
+ if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
+ warn_uid = 1;
+- entry->gid = st.st_gid;
+- if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
++ entry->gid = opt_squash ? 0 : st.st_gid;
++ if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
+ /* TODO: We ought to replace with a default
+ gid instead of truncating; otherwise there
+ are security problems. Maybe mode should
+ be &= ~070. Same goes for uid once Linux
+ supports >16-bit uids. */
+ warn_gid = 1;
++ }
+ size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
+ *fslen_ub += size;
+ if (S_ISDIR(st.st_mode)) {
+@@ -325,21 +463,15 @@
+ warn_skip = 1;
+ continue;
+ }
+- entry->path = strdup(path);
+- if (!entry->path) {
+- die(MKFS_ERROR, 1, "strdup failed");
+- }
++ entry->path = xstrdup(path);
+ if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
+ warn_size = 1;
+ entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
+ }
+ }
+ } else if (S_ISLNK(st.st_mode)) {
+- entry->uncompressed = malloc(entry->size);
++ entry->uncompressed = xreadlink(path);
+ if (!entry->uncompressed) {
+- die(MKFS_ERROR, 1, "malloc failed");
+- }
+- if (readlink(path, entry->uncompressed, entry->size) < 0) {
+ warn_skip = 1;
+ continue;
+ }
+@@ -351,7 +483,7 @@
+ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
+ warn_dev = 1;
+ } else {
+- die(MKFS_ERROR, 0, "bogus file type: %s", entry->name);
++ error_msg_and_die("bogus file type: %s", entry->name);
+ }
+
+ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+@@ -378,7 +510,9 @@
+ struct cramfs_super *super = (struct cramfs_super *) base;
+ unsigned int offset = sizeof(struct cramfs_super) + image_length;
+
+- offset += opt_pad; /* 0 if no padding */
++ if (opt_pad) {
++ offset += opt_pad; /* 0 if no padding */
++ }
+
+ super->magic = CRAMFS_MAGIC;
+ super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
+@@ -414,10 +548,10 @@
+ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
+
+ if ((offset & 3) != 0) {
+- die(MKFS_ERROR, 0, "illegal offset of %lu bytes", offset);
++ error_msg_and_die("illegal offset of %lu bytes", offset);
+ }
+ if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
+- die(MKFS_ERROR, 0, "filesystem too big");
++ error_msg_and_die("filesystem too big");
+ }
+ inode->offset = (offset >> 2);
+ }
+@@ -429,7 +563,7 @@
+ */
+ static void print_node(struct entry *e)
+ {
+- char info[10];
++ char info[12];
+ char type = '?';
+
+ if (S_ISREG(e->mode)) type = 'f';
+@@ -442,11 +576,11 @@
+
+ if (S_ISCHR(e->mode) || (S_ISBLK(e->mode))) {
+ /* major/minor numbers can be as high as 2^12 or 4096 */
+- snprintf(info, 10, "%4d,%4d", major(e->size), minor(e->size));
++ snprintf(info, 11, "%4d,%4d", major(e->size), minor(e->size));
+ }
+ else {
+ /* size be as high as 2^24 or 16777216 */
+- snprintf(info, 10, "%9d", e->size);
++ snprintf(info, 11, "%9d", e->size);
+ }
+
+ printf("%c %04o %s %5d:%-3d %s\n",
+@@ -462,17 +596,9 @@
+ {
+ int stack_entries = 0;
+ int stack_size = 64;
+- struct entry **entry_stack;
+-
+- entry_stack = malloc(stack_size * sizeof(struct entry *));
+- if (!entry_stack) {
+- die(MKFS_ERROR, 1, "malloc failed");
+- }
+-
+- if (opt_verbose) {
+- printf("root:\n");
+- }
++ struct entry **entry_stack = NULL;
+
++ entry_stack = xmalloc(stack_size * sizeof(struct entry *));
+ for (;;) {
+ int dir_start = stack_entries;
+ while (entry) {
+@@ -506,10 +632,7 @@
+ if (entry->child) {
+ if (stack_entries >= stack_size) {
+ stack_size *= 2;
+- entry_stack = realloc(entry_stack, stack_size * sizeof(struct entry *));
+- if (!entry_stack) {
+- die(MKFS_ERROR, 1, "realloc failed");
+- }
++ entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
+ }
+ entry_stack[stack_entries] = entry;
+ stack_entries++;
+@@ -543,7 +666,7 @@
+
+ set_data_offset(entry, base, offset);
+ if (opt_verbose) {
+- printf("%s:\n", entry->name);
++ printf("'%s':\n", entry->name);
+ }
+ entry = entry->child;
+ }
+@@ -553,16 +676,21 @@
+
+ static int is_zero(char const *begin, unsigned len)
+ {
+- /* Returns non-zero iff the first LEN bytes from BEGIN are all NULs. */
+- return (len-- == 0 ||
+- (begin[0] == '\0' &&
+- (len-- == 0 ||
+- (begin[1] == '\0' &&
+- (len-- == 0 ||
+- (begin[2] == '\0' &&
+- (len-- == 0 ||
+- (begin[3] == '\0' &&
+- memcmp(begin, begin + 4, len) == 0))))))));
++ if (opt_holes)
++ /* Returns non-zero iff the first LEN bytes from BEGIN are
++ all NULs. */
++ return (len-- == 0 ||
++ (begin[0] == '\0' &&
++ (len-- == 0 ||
++ (begin[1] == '\0' &&
++ (len-- == 0 ||
++ (begin[2] == '\0' &&
++ (len-- == 0 ||
++ (begin[3] == '\0' &&
++ memcmp(begin, begin + 4, len) == 0))))))));
++ else
++ /* Never create holes. */
++ return 0;
+ }
+
+ /*
+@@ -575,37 +703,34 @@
+ * Note that size > 0, as a zero-sized file wouldn't ever
+ * have gotten here in the first place.
+ */
+-static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
++static unsigned int do_compress(char *base, unsigned int offset, struct entry *entry)
+ {
++ unsigned int size = entry->size;
+ unsigned long original_size = size;
+ unsigned long original_offset = offset;
+ unsigned long new_size;
+ unsigned long blocks = (size - 1) / blksize + 1;
+ unsigned long curr = offset + 4 * blocks;
+ int change;
++ char *uncompressed = entry->uncompressed;
+
+- total_blocks += blocks;
++ total_blocks += blocks;
+
+ do {
+ unsigned long len = 2 * blksize;
+ unsigned int input = size;
+- int err;
+-
+ if (input > blksize)
+ input = blksize;
+ size -= input;
+- if (!(opt_holes && is_zero (uncompressed, input))) {
+- err = compress2(base + curr, &len, uncompressed, input, Z_BEST_COMPRESSION);
+- if (err != Z_OK) {
+- die(MKFS_ERROR, 0, "compression error: %s", zError(err));
+- }
++ if (!is_zero (uncompressed, input)) {
++ compress(base + curr, &len, uncompressed, input);
+ curr += len;
+ }
+ uncompressed += input;
+
+ if (len > blksize*2) {
+ /* (I don't think this can happen with zlib.) */
+- die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len);
++ error_msg_and_die("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
+ }
+
+ *(u32 *) (base + offset) = curr;
+@@ -618,10 +743,12 @@
+ st_blocks * 512. But if you say that then perhaps
+ administrative data should also be included in both. */
+ change = new_size - original_size;
+- if (opt_verbose > 1) {
+- printf("%6.2f%% (%+d bytes)\t%s\n",
+- (change * 100) / (double) original_size, change, name);
++#if 0
++ if (opt_verbose) {
++ printf("%6.2f%% (%+d bytes)\t%s\n",
++ (change * 100) / (double) original_size, change, entry->name);
+ }
++#endif
+
+ return curr;
+ }
+@@ -644,7 +771,7 @@
+ set_data_offset(entry, base, offset);
+ entry->offset = offset;
+ map_entry(entry);
+- offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
++ offset = do_compress(base, offset, entry);
+ unmap_entry(entry);
+ }
+ }
+@@ -660,13 +787,10 @@
+ int fd;
+ char *buf;
+
+- fd = open(file, O_RDONLY);
+- if (fd < 0) {
+- die(MKFS_ERROR, 1, "open failed: %s", file);
+- }
++ fd = xopen(file, O_RDONLY, 0);
+ buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == MAP_FAILED) {
+- die(MKFS_ERROR, 1, "mmap failed");
++ error_msg_and_die("mmap failed");
+ }
+ memcpy(base + offset, buf, image_length);
+ munmap(buf, image_length);
+@@ -679,6 +803,328 @@
+ return (offset + image_length);
+ }
+
++static struct entry *find_filesystem_entry(struct entry *dir, char *name, mode_t type)
++{
++ struct entry *e = dir;
++
++ if (S_ISDIR(dir->mode)) {
++ e = dir->child;
++ }
++ while (e) {
++ /* Only bother to do the expensive strcmp on matching file types */
++ if (type == (e->mode & S_IFMT) && e->name) {
++ if (S_ISDIR(e->mode)) {
++ int len = strlen(e->name);
++
++ /* Check if we are a parent of the correct path */
++ if (strncmp(e->name, name, len) == 0) {
++ /* Is this an _exact_ match? */
++ if (strcmp(name, e->name) == 0) {
++ return (e);
++ }
++ /* Looks like we found a parent of the correct path */
++ if (name[len] == '/') {
++ if (e->child) {
++ return (find_filesystem_entry (e, name + len + 1, type));
++ } else {
++ return NULL;
++ }
++ }
++ }
++ } else {
++ if (strcmp(name, e->name) == 0) {
++ return (e);
++ }
++ }
++ }
++ e = e->next;
++ }
++ return (NULL);
++}
++
++void modify_entry(char *full_path, unsigned long uid, unsigned long gid,
++ unsigned long mode, unsigned long rdev, struct entry *root, loff_t *fslen_ub)
++{
++ char *name, *path, *full;
++ struct entry *curr, *parent, *entry, *prev;
++
++ full = xstrdup(full_path);
++ path = xstrdup(dirname(full));
++ name = full_path + strlen(path) + 1;
++ free(full);
++ if (strcmp(path, "/") == 0) {
++ parent = root;
++ name = full_path + 1;
++ } else {
++ if (!(parent = find_filesystem_entry(root, path+1, S_IFDIR)))
++ error_msg_and_die("%s/%s: could not find parent\n", path, name);
++ }
++ if ((entry = find_filesystem_entry(parent, name, (mode & S_IFMT)))) {
++ /* its there, just modify permissions */
++ entry->mode = mode;
++ entry->uid = uid;
++ entry->gid = gid;
++ } else { /* make a new entry */
++
++ /* code partially replicated from parse_directory() */
++ size_t namelen;
++ if (S_ISREG(mode)) {
++ error_msg_and_die("%s: regular file from device_table file must exist on disk!", full_path);
++ }
++
++ namelen = strlen(name);
++ if (namelen > MAX_INPUT_NAMELEN) {
++ error_msg_and_die(
++ "Very long (%u bytes) filename `%s' found.\n"
++ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n",
++ namelen, name);
++ }
++ entry = xcalloc(1, sizeof(struct entry));
++ entry->name = xstrdup(name);
++ /* truncate multi-byte UTF-8 filenames on character boundary */
++ if (namelen > CRAMFS_MAXPATHLEN) {
++ namelen = CRAMFS_MAXPATHLEN;
++ warn_namelen = 1;
++ /* the first lost byte must not be a trail byte */
++ while ((entry->name[namelen] & 0xc0) == 0x80) {
++ namelen--;
++ /* are we reasonably certain it was UTF-8 ? */
++ if (entry->name[namelen] < 0x80 || !namelen) {
++ error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
++ }
++ }
++ entry->name[namelen] = '\0';
++ }
++ entry->mode = mode;
++ entry->uid = uid;
++ entry->gid = gid;
++ entry->size = 0;
++ if (S_ISBLK(mode) || S_ISCHR(mode)) {
++ entry->size = rdev;
++ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
++ warn_dev = 1;
++ }
++
++ /* ok, now we have to backup and correct the size of all the entries above us */
++ *fslen_ub += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++ parent->size += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++
++ /* alright, time to link us in */
++ curr = parent->child;
++ prev = NULL;
++ while (curr && strcmp(name, curr->name) > 0) {
++ prev = curr;
++ curr = curr->next;
++ }
++ if (!prev) parent->child = entry;
++ else prev->next = entry;
++ entry->next = curr;
++ entry->child = NULL;
++ }
++ if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
++ warn_uid = 1;
++ if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
++ /* TODO: We ought to replace with a default
++ gid instead of truncating; otherwise there
++ are security problems. Maybe mode should
++ be &= ~070. Same goes for uid once Linux
++ supports >16-bit uids. */
++ warn_gid = 1;
++ }
++ free(path);
++}
++
++/* the GNU C library has a wonderful scanf("%as", string) which will
++ allocate the string with the right size, good to avoid buffer overruns.
++ the following macros use it if available or use a hacky workaround...
++ */
++
++#ifdef __GNUC__
++#define SCANF_PREFIX "a"
++#define SCANF_STRING(s) (&s)
++#define GETCWD_SIZE 0
++#else
++#define SCANF_PREFIX "511"
++#define SCANF_STRING(s) (s = xmalloc(512))
++#define GETCWD_SIZE -1
++inline int snprintf(char *str, size_t n, const char *fmt, ...)
++{
++ int ret;
++ va_list ap;
++
++ va_start(ap, fmt);
++ ret = vsprintf(str, fmt, ap);
++ va_end(ap);
++ return ret;
++}
++#endif
++
++/* device table entries take the form of:
++ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++ /dev/mem c 640 0 0 1 1 0 0 -
++
++ type can be one of:
++ f A regular file
++ d Directory
++ c Character special device file
++ b Block special device file
++ p Fifo (named pipe)
++
++ I don't bother with symlinks (permissions are irrelevant), hard
++ links (special cases of regular files), or sockets (why bother).
++
++ Regular files must exist in the target root directory. If a char,
++ block, fifo, or directory does not exist, it will be created.
++*/
++
++static int interpret_table_entry(char *line, struct entry *root, loff_t *fslen_ub)
++{
++ char type, *name = NULL;
++ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++ unsigned long start = 0, increment = 1, count = 0;
++
++ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
++ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
++ &start, &increment, &count) < 0)
++ {
++ return 1;
++ }
++
++ if (!strcmp(name, "/")) {
++ error_msg_and_die("Device table entries require absolute paths");
++ }
++
++ switch (type) {
++ case 'd':
++ mode |= S_IFDIR;
++ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++ break;
++ case 'f':
++ mode |= S_IFREG;
++ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++ break;
++ case 'p':
++ mode |= S_IFIFO;
++ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++ break;
++ case 'c':
++ case 'b':
++ mode |= (type == 'c') ? S_IFCHR : S_IFBLK;
++ if (count > 0) {
++ char *buf;
++ unsigned long i;
++ dev_t rdev;
++
++ for (i = start; i < count; i++) {
++ asprintf(&buf, "%s%lu", name, i);
++ rdev = makedev(major, minor + (i * increment - start));
++ modify_entry(buf, uid, gid, mode, rdev, root, fslen_ub);
++ free(buf);
++ }
++ } else {
++ dev_t rdev = makedev(major, minor);
++ modify_entry(name, uid, gid, mode, rdev, root, fslen_ub);
++ }
++ break;
++ default:
++ error_msg_and_die("Unsupported file type");
++ }
++ free(name);
++ return 0;
++}
++
++static int parse_device_table(FILE *file, struct entry *root, loff_t *fslen_ub)
++{
++ char *line;
++ int status = 0;
++ size_t length = 0;
++
++ /* Turn off squash, since we must ensure that values
++ * entered via the device table are not squashed */
++ opt_squash = 0;
++
++ /* Looks ok so far. The general plan now is to read in one
++ * line at a time, check for leading comment delimiters ('#'),
++ * then try and parse the line as a device table. If we fail
++ * to parse things, try and help the poor fool to fix their
++ * device table with a useful error msg... */
++ line = NULL;
++ while (getline(&line, &length, file) != -1) {
++ /* First trim off any whitespace */
++ int len = strlen(line);
++
++ /* trim trailing whitespace */
++ while (len > 0 && isspace(line[len - 1]))
++ line[--len] = '\0';
++ /* trim leading whitespace */
++ memmove(line, &line[strspn(line, " \n\r\t\v")], len);
++
++ /* How long are we after trimming? */
++ len = strlen(line);
++
++ /* If this is NOT a comment line, try to interpret it */
++ if (len && *line != '#') {
++ if (interpret_table_entry(line, root, fslen_ub))
++ status = 1;
++ }
++
++ free(line);
++ line = NULL;
++ }
++ free(line);
++ fclose(file);
++
++ return status;
++}
++
++void traverse(struct entry *entry, int depth)
++{
++ struct entry *curr = entry;
++ int i;
++
++ while (curr) {
++ for (i = 0; i < depth; i++) putchar(' ');
++ printf("%s: size=%d mode=%d same=%p\n",
++ (curr->name)? (char*)curr->name : "/",
++ curr->size, curr->mode, curr->same);
++ if (curr->child) traverse(curr->child, depth + 4);
++ curr = curr->next;
++ }
++}
++
++static void free_filesystem_entry(struct entry *dir)
++{
++ struct entry *e = dir, *last;
++
++ if (S_ISDIR(dir->mode)) {
++ e = dir->child;
++ }
++ while (e) {
++ if (e->name)
++ free(e->name);
++ if (e->path)
++ free(e->path);
++ if (e->uncompressed)
++ free(e->uncompressed);
++ last = e;
++ if (e->child) {
++ free_filesystem_entry(e);
++ }
++ e = e->next;
++ free(last);
++ }
++}
++
++
++/*
++ * Usage:
++ *
++ * mkcramfs directory-name outfile
++ *
++ * where "directory-name" is simply the root of the directory
++ * tree that we want to generate a compressed filesystem out
++ * of.
++ */
+ int main(int argc, char **argv)
+ {
+ struct stat st; /* used twice... */
+@@ -692,6 +1138,7 @@
+ u32 crc;
+ int c; /* for getopt */
+ char *ep; /* for strtoul */
++ FILE *devtable = NULL;
+
+ total_blocks = 0;
+
+@@ -699,7 +1146,7 @@
+ progname = argv[0];
+
+ /* command line options */
+- while ((c = getopt(argc, argv, "hEe:i:n:psvz")) != EOF) {
++ while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) {
+ switch (c) {
+ case 'h':
+ usage(MKFS_OK);
+@@ -715,7 +1162,7 @@
+ case 'i':
+ opt_image = optarg;
+ if (lstat(opt_image, &st) < 0) {
+- die(MKFS_ERROR, 1, "lstat failed: %s", opt_image);
++ error_msg_and_die("lstat failed: %s", opt_image);
+ }
+ image_length = st.st_size; /* may be padded later */
+ fslen_ub += (image_length + 3); /* 3 is for padding */
+@@ -736,6 +1183,16 @@
+ case 'z':
+ opt_holes = 1;
+ break;
++ case 'q':
++ opt_squash = 1;
++ break;
++ case 'D':
++ devtable = xfopen(optarg, "r");
++ if (fstat(fileno(devtable), &st) < 0)
++ perror_msg_and_die(optarg);
++ if (st.st_size < 10)
++ error_msg_and_die("%s: not a proper device table file\n", optarg);
++ break;
+ }
+ }
+
+@@ -745,25 +1202,23 @@
+ outfile = argv[optind + 1];
+
+ if (stat(dirname, &st) < 0) {
+- die(MKFS_USAGE, 1, "stat failed: %s", dirname);
+- }
+- fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+- if (fd < 0) {
+- die(MKFS_USAGE, 1, "open failed: %s", outfile);
++ error_msg_and_die("stat failed: %s", dirname);
+ }
++ fd = xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+- root_entry = calloc(1, sizeof(struct entry));
+- if (!root_entry) {
+- die(MKFS_ERROR, 1, "calloc failed");
+- }
++ root_entry = xcalloc(1, sizeof(struct entry));
+ root_entry->mode = st.st_mode;
+ root_entry->uid = st.st_uid;
+ root_entry->gid = st.st_gid;
+
+ root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
+
++ if (devtable) {
++ parse_device_table(devtable, root_entry, &fslen_ub);
++ }
++
+ /* always allocate a multiple of blksize bytes because that's
+- what we're going to write later on */
++ what we're going to write later on */
+ fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
+
+ if (fslen_ub > MAXFSLEN) {
+@@ -790,7 +1245,7 @@
+ rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ if (rom_image == MAP_FAILED) {
+- die(MKFS_ERROR, 1, "mmap failed");
++ error_msg_and_die("mmap failed");
+ }
+
+ /* Skip the first opt_pad bytes for boot loader code */
+@@ -807,6 +1262,7 @@
+ }
+
+ offset = write_directory_structure(root_entry->child, rom_image, offset);
++ if (opt_verbose)
+ printf("Directory data: %d bytes\n", offset);
+
+ offset = write_data(root_entry, rom_image, offset);
+@@ -814,30 +1270,38 @@
+ /* We always write a multiple of blksize bytes, so that
+ losetup works. */
+ offset = ((offset - 1) | (blksize - 1)) + 1;
++ if (opt_verbose)
+ printf("Everything: %d kilobytes\n", offset >> 10);
+
+ /* Write the superblock now that we can fill in all of the fields. */
+ write_superblock(root_entry, rom_image+opt_pad, offset);
++ if (opt_verbose)
+ printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
+
+ /* Put the checksum in. */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
+ ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
++ if (opt_verbose)
+ printf("CRC: %x\n", crc);
+
+ /* Check to make sure we allocated enough space. */
+ if (fslen_ub < offset) {
+- die(MKFS_ERROR, 0, "not enough space allocated for ROM image (%Ld allocated, %d used)", fslen_ub, offset);
++ error_msg_and_die("not enough space allocated for ROM "
++ "image (%Ld allocated, %d used)", fslen_ub, offset);
+ }
+
+ written = write(fd, rom_image, offset);
+ if (written < 0) {
+- die(MKFS_ERROR, 1, "write failed");
++ error_msg_and_die("write failed");
+ }
+ if (offset != written) {
+- die(MKFS_ERROR, 0, "ROM image write failed (wrote %d of %d bytes)", written, offset);
++ error_msg_and_die("ROM image write failed (wrote %d of %d bytes)", written, offset);
+ }
++
++ /* Free up memory */
++ free_filesystem_entry(root_entry);
++ free(root_entry);
+
+ /* (These warnings used to come at the start, but they scroll off the
+ screen too quickly.) */
diff --git a/target/default/device_table.txt b/target/default/device_table.txt
new file mode 100644
index 0000000000..8b46ca0323
--- /dev/null
+++ b/target/default/device_table.txt
@@ -0,0 +1,162 @@
+# When building a target filesystem, it is desirable to not have to
+# become root and then run 'mknod' a thousand times. Using a device
+# table you can create device nodes and directories "on the fly".
+#
+# This is a sample device table file for use with genext2fs. You can
+# do all sorts of interesting things with a device table file. For
+# example, if you want to adjust the permissions on a particular file
+# you can just add an entry like:
+# /sbin/foobar f 2755 0 0 - - - - -
+# and (assuming the file /sbin/foobar exists) it will be made setuid
+# root (regardless of what its permissions are on the host filesystem.
+# Furthermore, you can use a single table entry to create a many device
+# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
+# I could just use the following two table entries:
+# /dev/hda b 640 0 0 3 0 0 0 -
+# /dev/hda b 640 0 0 3 1 1 1 15
+#
+# Device table entries take the form of:
+# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+# where name is the file name, type can be one of:
+# f A regular file
+# d Directory
+# c Character special device file
+# b Block special device file
+# p Fifo (named pipe)
+# uid is the user id for the target file, gid is the group id for the
+# target file. The rest of the entries (major, minor, etc) apply only
+# to device special files.
+
+# Have fun
+# -Erik Andersen <andersen@codepoet.org>
+#
+
+#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+/dev d 755 0 0 - - - - -
+/dev/pts d 755 0 0 - - - - -
+/tmp d 1777 0 0 - - - - -
+/etc d 755 0 0 - - - - -
+/home/default d 2755 1000 1000 - - - - -
+#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+/bin/busybox f 4755 0 0 - - - - -
+/etc/shadow f 600 0 0 - - - - -
+/etc/passwd f 644 0 0 - - - - -
+/etc/network/if-up.d d 755 0 0 - - - - -
+/etc/network/if-pre-up.d d 755 0 0 - - - - -
+/etc/network/if-down.d d 755 0 0 - - - - -
+/etc/network/if-post-down.d d 755 0 0 - - - - -
+/usr/share/udhcpc/default.script f 755 0 0 - - - - -
+# uncomment this to allow starting x as non-root
+#/usr/X11R6/bin/Xfbdev f 4755 0 0 - - - - -
+# Normal system devices
+/dev/mem c 640 0 0 1 1 0 0 -
+/dev/kmem c 640 0 0 1 2 0 0 -
+/dev/null c 666 0 0 1 3 0 0 -
+/dev/zero c 666 0 0 1 5 0 0 -
+/dev/random c 666 0 0 1 8 0 0 -
+/dev/urandom c 666 0 0 1 9 0 0 -
+/dev/ram b 640 0 0 1 1 0 0 -
+/dev/ram b 640 0 0 1 0 0 1 4
+/dev/loop b 640 0 0 7 0 0 1 2
+/dev/rtc c 640 0 0 10 135 - - -
+/dev/console c 666 0 0 5 1 - - -
+/dev/tty c 666 0 0 5 0 - - -
+/dev/tty c 666 0 0 4 0 0 1 8
+/dev/ttyp c 666 0 0 3 0 0 1 10
+/dev/ptyp c 666 0 0 2 0 0 1 10
+/dev/ptmx c 666 0 0 5 2 - - -
+/dev/ttyP c 666 0 0 57 0 0 1 4
+/dev/ttyS c 666 0 0 4 64 0 1 4
+/dev/fb c 640 0 5 29 0 0 32 4
+#/dev/ttySA c 666 0 0 204 5 0 1 3
+/dev/psaux c 666 0 0 10 1 0 0 -
+#/dev/ppp c 666 0 0 108 0 - - -
+
+# MTD stuff
+/dev/mtd c 640 0 0 90 0 0 2 4
+/dev/mtdblock b 640 0 0 31 0 0 1 4
+
+#Tun/tap driver
+/dev/net d 755 0 0 - - - - -
+/dev/net/tun c 660 0 0 10 200 - - -
+
+# Audio stuff
+#/dev/audio c 666 0 29 14 4 - - -
+#/dev/audio1 c 666 0 29 14 20 - - -
+#/dev/dsp c 666 0 29 14 3 - - -
+#/dev/dsp1 c 666 0 29 14 19 - - -
+#/dev/sndstat c 666 0 29 14 6 - - -
+
+# User-mode Linux stuff
+/dev/ubda b 640 0 0 98 0 0 0 -
+/dev/ubda b 640 0 0 98 1 1 1 15
+
+# IDE Devices
+/dev/hda b 640 0 0 3 0 0 0 -
+/dev/hda b 640 0 0 3 1 1 1 15
+/dev/hdb b 640 0 0 3 64 0 0 -
+/dev/hdb b 640 0 0 3 65 1 1 15
+#/dev/hdc b 640 0 0 22 0 0 0 -
+#/dev/hdc b 640 0 0 22 1 1 1 15
+#/dev/hdd b 640 0 0 22 64 0 0 -
+#/dev/hdd b 640 0 0 22 65 1 1 15
+#/dev/hde b 640 0 0 33 0 0 0 -
+#/dev/hde b 640 0 0 33 1 1 1 15
+#/dev/hdf b 640 0 0 33 64 0 0 -
+#/dev/hdf b 640 0 0 33 65 1 1 15
+#/dev/hdg b 640 0 0 34 0 0 0 -
+#/dev/hdg b 640 0 0 34 1 1 1 15
+#/dev/hdh b 640 0 0 34 64 0 0 -
+#/dev/hdh b 640 0 0 34 65 1 1 15
+
+# SCSI Devices
+#/dev/sda b 640 0 0 8 0 0 0 -
+#/dev/sda b 640 0 0 8 1 1 1 15
+#/dev/sdb b 640 0 0 8 16 0 0 -
+#/dev/sdb b 640 0 0 8 17 1 1 15
+#/dev/sdc b 640 0 0 8 32 0 0 -
+#/dev/sdc b 640 0 0 8 33 1 1 15
+#/dev/sdd b 640 0 0 8 48 0 0 -
+#/dev/sdd b 640 0 0 8 49 1 1 15
+#/dev/sde b 640 0 0 8 64 0 0 -
+#/dev/sde b 640 0 0 8 65 1 1 15
+#/dev/sdf b 640 0 0 8 80 0 0 -
+#/dev/sdf b 640 0 0 8 81 1 1 15
+#/dev/sdg b 640 0 0 8 96 0 0 -
+#/dev/sdg b 640 0 0 8 97 1 1 15
+#/dev/sdh b 640 0 0 8 112 0 0 -
+#/dev/sdh b 640 0 0 8 113 1 1 15
+#/dev/sg c 640 0 0 21 0 0 1 15
+#/dev/scd b 640 0 0 11 0 0 1 15
+#/dev/st c 640 0 0 9 0 0 1 8
+#/dev/nst c 640 0 0 9 128 0 1 8
+#/dev/st c 640 0 0 9 32 1 1 4
+#/dev/st c 640 0 0 9 64 1 1 4
+#/dev/st c 640 0 0 9 96 1 1 4
+
+# Floppy disk devices
+#/dev/fd b 640 0 0 2 0 0 1 2
+#/dev/fd0d360 b 640 0 0 2 4 0 0 -
+#/dev/fd1d360 b 640 0 0 2 5 0 0 -
+#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
+#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
+#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
+#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
+#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
+#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
+
+# All the proprietary cdrom devices in the world
+#/dev/aztcd b 640 0 0 29 0 0 0 -
+#/dev/bpcd b 640 0 0 41 0 0 0 -
+#/dev/capi20 c 640 0 0 68 0 0 1 2
+#/dev/cdu31a b 640 0 0 15 0 0 0 -
+#/dev/cdu535 b 640 0 0 24 0 0 0 -
+#/dev/cm206cd b 640 0 0 32 0 0 0 -
+#/dev/sjcd b 640 0 0 18 0 0 0 -
+#/dev/sonycd b 640 0 0 15 0 0 0 -
+#/dev/gscd b 640 0 0 16 0 0 0 -
+#/dev/sbpcd b 640 0 0 25 0 0 0 -
+#/dev/sbpcd b 640 0 0 25 0 0 1 4
+#/dev/mcd b 640 0 0 23 0 0 0 -
+#/dev/optcd b 640 0 0 17 0 0 0 -
+
diff --git a/target/default/skel.tar.gz b/target/default/skel.tar.gz
new file mode 100644
index 0000000000..301c5cfa28
--- /dev/null
+++ b/target/default/skel.tar.gz
Binary files differ
diff --git a/target/default/target_skeleton/etc/TZ b/target/default/target_skeleton/etc/TZ
new file mode 100644
index 0000000000..9fcb2a3c56
--- /dev/null
+++ b/target/default/target_skeleton/etc/TZ
@@ -0,0 +1 @@
+MST7MDT
diff --git a/target/default/target_skeleton/etc/fstab b/target/default/target_skeleton/etc/fstab
new file mode 100644
index 0000000000..6d33629a7b
--- /dev/null
+++ b/target/default/target_skeleton/etc/fstab
@@ -0,0 +1,8 @@
+# /etc/fstab: static file system information.
+#
+# <file system> <mount pt> <type> <options> <dump> <pass>
+/dev/root / ext2 rw,noauto 0 1
+proc /proc proc defaults 0 0
+devpts /dev/pts devpts defaults,gid=5,mode=620 0 0
+tmpfs /tmp tmpfs defaults 0 0
+
diff --git a/target/default/target_skeleton/etc/group b/target/default/target_skeleton/etc/group
new file mode 100644
index 0000000000..a21ef0f769
--- /dev/null
+++ b/target/default/target_skeleton/etc/group
@@ -0,0 +1,10 @@
+root:x:0:
+daemon:x:1:
+bin:x:2:
+sys:x:3:
+adm:x:4:
+tty:x:5:
+disk:x:6:
+utmp:x:43:
+staff:x:50:
+default:x:1000:
diff --git a/target/default/target_skeleton/etc/hostname b/target/default/target_skeleton/etc/hostname
new file mode 100644
index 0000000000..52e67d68aa
--- /dev/null
+++ b/target/default/target_skeleton/etc/hostname
@@ -0,0 +1 @@
+uclibc
diff --git a/target/default/target_skeleton/etc/hosts b/target/default/target_skeleton/etc/hosts
new file mode 100644
index 0000000000..ba712fe033
--- /dev/null
+++ b/target/default/target_skeleton/etc/hosts
@@ -0,0 +1 @@
+127.0.0.1 localhost
diff --git a/target/default/target_skeleton/etc/init.d/S20urandom b/target/default/target_skeleton/etc/init.d/S20urandom
new file mode 100755
index 0000000000..433fafee4e
--- /dev/null
+++ b/target/default/target_skeleton/etc/init.d/S20urandom
@@ -0,0 +1,44 @@
+#! /bin/sh
+#
+# urandom This script saves the random seed between reboots.
+# It is called from the boot, halt and reboot scripts.
+#
+# Version: @(#)urandom 1.33 22-Jun-1998 miquels@cistron.nl
+#
+
+[ -c /dev/urandom ] || exit 0
+#. /etc/default/rcS
+
+case "$1" in
+ start|"")
+ if [ "$VERBOSE" != no ]
+ then
+ echo -n "Initializing random number generator... "
+ fi
+ # Load and then save 512 bytes,
+ # which is the size of the entropy pool
+ if [ -f /etc/random-seed ]
+ then
+ cat /etc/random-seed >/dev/urandom
+ fi
+ rm -f /etc/random-seed
+ umask 077
+ dd if=/dev/urandom of=/etc/random-seed count=1 \
+ >/dev/null 2>&1 || echo "urandom start: failed."
+ umask 022
+ [ "$VERBOSE" != no ] && echo "done."
+ ;;
+ stop)
+ # Carry a random seed from shut-down to start-up;
+ # see documentation in linux/drivers/char/random.c
+ [ "$VERBOSE" != no ] && echo -n "Saving random seed... "
+ umask 077
+ dd if=/dev/urandom of=/etc/random-seed count=1 \
+ >/dev/null 2>&1 || echo "urandom stop: failed."
+ [ "$VERBOSE" != no ] && echo "done."
+ ;;
+ *)
+ echo "Usage: urandom {start|stop}" >&2
+ exit 1
+ ;;
+esac
diff --git a/target/default/target_skeleton/etc/init.d/S40network b/target/default/target_skeleton/etc/init.d/S40network
new file mode 100755
index 0000000000..d835d9c72a
--- /dev/null
+++ b/target/default/target_skeleton/etc/init.d/S40network
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Start the network....
+#
+
+start() {
+ echo "Starting network..."
+ /sbin/ifup -a
+}
+stop() {
+ echo -n "Stopping network..."
+ /sbin/ifdown -a
+}
+restart() {
+ stop
+ start
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart|reload)
+ restart
+ ;;
+ *)
+ echo $"Usage: $0 {start|stop|restart}"
+ exit 1
+esac
+
+exit $?
+
diff --git a/target/default/target_skeleton/etc/init.d/rcS b/target/default/target_skeleton/etc/init.d/rcS
new file mode 100755
index 0000000000..de411534da
--- /dev/null
+++ b/target/default/target_skeleton/etc/init.d/rcS
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+
+# Start all init scripts in /etc/init.d
+# executing them in numerical order.
+#
+for i in /etc/init.d/S??* ;do
+
+ # Ignore dangling symlinks (if any).
+ [ ! -f "$i" ] && continue
+
+ case "$i" in
+ *.sh)
+ # Source shell script for speed.
+ (
+ trap - INT QUIT TSTP
+ set start
+ . $i
+ )
+ ;;
+ *)
+ # No sh extension, so fork subprocess.
+ $i start
+ ;;
+ esac
+done
+
diff --git a/target/default/target_skeleton/etc/inittab b/target/default/target_skeleton/etc/inittab
new file mode 100644
index 0000000000..a6c014e751
--- /dev/null
+++ b/target/default/target_skeleton/etc/inittab
@@ -0,0 +1,47 @@
+# /etc/inittab
+#
+# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
+#
+# Note: BusyBox init doesn't support runlevels. The runlevels field is
+# completely ignored by BusyBox init. If you want runlevels, use
+# sysvinit.
+#
+# Format for each entry: <id>:<runlevels>:<action>:<process>
+#
+# id == tty to run on, or empty for /dev/console
+# runlevels == ignored
+# action == one of sysinit, respawn, askfirst, wait, and once
+# process == program to run
+
+# Startup the system
+null::sysinit:/bin/mount -o remount,rw /
+null::sysinit:/bin/mount -t proc proc /proc
+null::sysinit:/bin/mount -a
+null::sysinit:/bin/hostname -F /etc/hostname
+null::sysinit:/sbin/ifconfig lo 127.0.0.1 up
+null::sysinit:/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
+# now run any rc scripts
+::sysinit:/etc/init.d/rcS
+
+# Set up a couple of getty's
+tty1::respawn:/sbin/getty 38400 tty1
+tty2::respawn:/sbin/getty 38400 tty2
+
+# Put a getty on the serial port
+#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
+
+# Logging junk
+null::sysinit:/bin/touch /var/log/messages
+null::respawn:/sbin/syslogd -n -m 0
+null::respawn:/sbin/klogd -n
+tty3::respawn:/usr/bin/tail -f /var/log/messages
+
+# Stuff to do for the 3-finger salute
+::ctrlaltdel:/sbin/reboot
+
+# Stuff to do before rebooting
+null::shutdown:/usr/bin/killall klogd
+null::shutdown:/usr/bin/killall syslogd
+null::shutdown:/bin/umount -a -r
+null::shutdown:/sbin/swapoff -a
+
diff --git a/target/default/target_skeleton/etc/inputrc b/target/default/target_skeleton/etc/inputrc
new file mode 100644
index 0000000000..2f1cb601a5
--- /dev/null
+++ b/target/default/target_skeleton/etc/inputrc
@@ -0,0 +1,44 @@
+# /etc/inputrc - global inputrc for libreadline
+# See readline(3readline) and `info readline' for more information.
+
+# Be 8 bit clean.
+set input-meta on
+set output-meta on
+set bell-style visible
+
+# To allow the use of 8bit-characters like the german umlauts, comment out
+# the line below. However this makes the meta key not work as a meta key,
+# which is annoying to those which don't need to type in 8-bit characters.
+
+# set convert-meta off
+
+"\e0d": backward-word
+"\e0c": forward-word
+"\e[h": beginning-of-line
+"\e[f": end-of-line
+"\e[1~": beginning-of-line
+"\e[4~": end-of-line
+#"\e[5~": beginning-of-history
+#"\e[6~": end-of-history
+"\e[3~": delete-char
+"\e[2~": quoted-insert
+
+# Common standard keypad and cursor
+# (codes courtsey Werner Fink, <werner@suse.de>)
+#"\e[1~": history-search-backward
+"\e[2~": yank
+"\e[3~": delete-char
+#"\e[4~": set-mark
+"\e[5~": history-search-backward
+"\e[6~": history-search-forward
+# Normal keypad and cursor of xterm
+"\e[F": end-of-line
+"\e[H": beginning-of-line
+# Application keypad and cursor of xterm
+"\eOA": previous-history
+"\eOC": forward-char
+"\eOB": next-history
+"\eOD": backward-char
+"\eOF": end-of-line
+"\eOH": beginning-of-line
+
diff --git a/target/default/target_skeleton/etc/issue b/target/default/target_skeleton/etc/issue
new file mode 100644
index 0000000000..f24b862c97
--- /dev/null
+++ b/target/default/target_skeleton/etc/issue
@@ -0,0 +1,4 @@
+
+
+Welcome to the Erik's uClibc development environment.
+
diff --git a/target/default/target_skeleton/etc/network/interfaces b/target/default/target_skeleton/etc/network/interfaces
new file mode 100644
index 0000000000..218b82cde5
--- /dev/null
+++ b/target/default/target_skeleton/etc/network/interfaces
@@ -0,0 +1,4 @@
+# Configure Loopback
+auto lo
+iface lo inet loopback
+
diff --git a/target/default/target_skeleton/etc/passwd b/target/default/target_skeleton/etc/passwd
new file mode 100644
index 0000000000..e0f473fc7b
--- /dev/null
+++ b/target/default/target_skeleton/etc/passwd
@@ -0,0 +1,13 @@
+root:x:0:0:root:/root:/bin/sh
+daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+bin:x:2:2:bin:/bin:/bin/sh
+sys:x:3:3:sys:/dev:/bin/sh
+sync:x:4:100:sync:/bin:/bin/sync
+mail:x:8:8:mail:/var/spool/mail:/bin/sh
+proxy:x:13:13:proxy:/bin:/bin/sh
+www-data:x:33:33:www-data:/var/www:/bin/sh
+backup:x:34:34:backup:/var/backups:/bin/sh
+operator:x:37:37:Operator:/var:/bin/sh
+sshd:x:103:99:Operator:/var:/bin/sh
+nobody:x:99:99:nobody:/home:/bin/sh
+default:x:1000:1000:Default non-root user:/home/default:/bin/sh
diff --git a/target/default/target_skeleton/etc/profile b/target/default/target_skeleton/etc/profile
new file mode 100644
index 0000000000..cc2e0beb87
--- /dev/null
+++ b/target/default/target_skeleton/etc/profile
@@ -0,0 +1,48 @@
+# ~/.bashrc: executed by bash(1) for non-login interactive shells.
+
+export PATH=\
+/bin:\
+/sbin:\
+/usr/bin:\
+/usr/sbin:\
+/usr/bin/X11:\
+/usr/local/bin
+
+# If running interactively, then:
+if [ "$PS1" ]; then
+
+ if [ "$BASH" ]; then
+ export PS1="[\u@\h \W]\\$ "
+ alias ll='/bin/ls --color=tty -laFh'
+ alias ls='/bin/ls --color=tty -F'
+ export LS_COLORS='no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.png=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:';
+ else
+ if [ "`id -u`" -eq 0 ]; then
+ export PS1='# '
+ else
+ export PS1='$ '
+ fi
+ fi
+
+ export USER=`id -un`
+ export LOGNAME=$USER
+ export HOSTNAME=`/bin/hostname`
+ export HISTSIZE=1000
+ export HISTFILESIZE=1000
+ export PAGER='/bin/more '
+ export EDITOR='/bin/vi'
+ export INPUTRC=/etc/inputrc
+ export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile
+
+ ### Some aliases
+ alias ps2='ps facux '
+ alias ps1='ps faxo "%U %t %p %a" '
+ alias af='ps af'
+ alias cls='clear'
+ alias df='df -h'
+ alias indent='indent -bad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs -npsl -nsc -nsob -nss -ts4 '
+ #alias bc='bc -l'
+ alias minicom='minicom -c on'
+ alias calc='calc -Cd '
+ alias bc='calc -Cd '
+fi;
diff --git a/target/default/target_skeleton/etc/protocols b/target/default/target_skeleton/etc/protocols
new file mode 100644
index 0000000000..1ac8a40967
--- /dev/null
+++ b/target/default/target_skeleton/etc/protocols
@@ -0,0 +1,31 @@
+# /etc/protocols:
+# $Id: protocols,v 1.1 2004/10/09 02:49:18 andersen Exp $
+#
+# Internet (IP) protocols
+#
+# from: @(#)protocols 5.1 (Berkeley) 4/17/89
+#
+# Updated for NetBSD based on RFC 1340, Assigned Numbers (July 1992).
+
+ip 0 IP # internet protocol, pseudo protocol number
+icmp 1 ICMP # internet control message protocol
+igmp 2 IGMP # Internet Group Management
+ggp 3 GGP # gateway-gateway protocol
+ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'')
+st 5 ST # ST datagram mode
+tcp 6 TCP # transmission control protocol
+egp 8 EGP # exterior gateway protocol
+pup 12 PUP # PARC universal packet protocol
+udp 17 UDP # user datagram protocol
+hmp 20 HMP # host monitoring protocol
+xns-idp 22 XNS-IDP # Xerox NS IDP
+rdp 27 RDP # "reliable datagram" protocol
+iso-tp4 29 ISO-TP4 # ISO Transport Protocol class 4
+xtp 36 XTP # Xpress Tranfer Protocol
+ddp 37 DDP # Datagram Delivery Protocol
+idpr-cmtp 39 IDPR-CMTP # IDPR Control Message Transport
+rspf 73 RSPF #Radio Shortest Path First.
+vmtp 81 VMTP # Versatile Message Transport
+ospf 89 OSPFIGP # Open Shortest Path First IGP
+ipip 94 IPIP # Yet Another IP encapsulation
+encap 98 ENCAP # Yet Another IP encapsulation
diff --git a/target/default/target_skeleton/etc/random-seed b/target/default/target_skeleton/etc/random-seed
new file mode 100644
index 0000000000..f26038adc5
--- /dev/null
+++ b/target/default/target_skeleton/etc/random-seed
Binary files differ
diff --git a/target/default/target_skeleton/etc/resolv.conf b/target/default/target_skeleton/etc/resolv.conf
new file mode 100644
index 0000000000..71a86dd76c
--- /dev/null
+++ b/target/default/target_skeleton/etc/resolv.conf
@@ -0,0 +1,2 @@
+domain dev.null
+nameserver 127.0.0.1
diff --git a/target/default/target_skeleton/etc/securetty b/target/default/target_skeleton/etc/securetty
new file mode 100644
index 0000000000..81616f38ea
--- /dev/null
+++ b/target/default/target_skeleton/etc/securetty
@@ -0,0 +1,12 @@
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+tty7
+tty8
+ttyS0
+ttyS1
+ttyS2
+ttyS3
diff --git a/target/default/target_skeleton/etc/services b/target/default/target_skeleton/etc/services
new file mode 100644
index 0000000000..b287b63ea0
--- /dev/null
+++ b/target/default/target_skeleton/etc/services
@@ -0,0 +1,302 @@
+# /etc/services:
+# $Id: services,v 1.1 2004/10/09 02:49:18 andersen Exp $
+#
+# Network services, Internet style
+#
+# Note that it is presently the policy of IANA to assign a single well-known
+# port number for both TCP and UDP; hence, most entries here have two entries
+# even if the protocol doesn't support UDP operations.
+# Updated from RFC 1700, ``Assigned Numbers'' (October 1994). Not all ports
+# are included, only the more common ones.
+
+tcpmux 1/tcp # TCP port service multiplexer
+echo 7/tcp
+echo 7/udp
+discard 9/tcp sink null
+discard 9/udp sink null
+systat 11/tcp users
+daytime 13/tcp
+daytime 13/udp
+netstat 15/tcp
+qotd 17/tcp quote
+msp 18/tcp # message send protocol
+msp 18/udp # message send protocol
+chargen 19/tcp ttytst source
+chargen 19/udp ttytst source
+ftp-data 20/tcp
+ftp 21/tcp
+fsp 21/udp fspd
+ssh 22/tcp # SSH Remote Login Protocol
+ssh 22/udp # SSH Remote Login Protocol
+telnet 23/tcp
+# 24 - private
+smtp 25/tcp mail
+# 26 - unassigned
+time 37/tcp timserver
+time 37/udp timserver
+rlp 39/udp resource # resource location
+nameserver 42/tcp name # IEN 116
+whois 43/tcp nicname
+re-mail-ck 50/tcp # Remote Mail Checking Protocol
+re-mail-ck 50/udp # Remote Mail Checking Protocol
+domain 53/tcp nameserver # name-domain server
+domain 53/udp nameserver
+mtp 57/tcp # deprecated
+bootps 67/tcp # BOOTP server
+bootps 67/udp
+bootpc 68/tcp # BOOTP client
+bootpc 68/udp
+tftp 69/udp
+gopher 70/tcp # Internet Gopher
+gopher 70/udp
+rje 77/tcp netrjs
+finger 79/tcp
+www 80/tcp http # WorldWideWeb HTTP
+www 80/udp # HyperText Transfer Protocol
+link 87/tcp ttylink
+kerberos 88/tcp kerberos5 krb5 # Kerberos v5
+kerberos 88/udp kerberos5 krb5 # Kerberos v5
+supdup 95/tcp
+# 100 - reserved
+hostnames 101/tcp hostname # usually from sri-nic
+iso-tsap 102/tcp tsap # part of ISODE.
+csnet-ns 105/tcp cso-ns # also used by CSO name server
+csnet-ns 105/udp cso-ns
+# unfortunately the poppassd (Eudora) uses a port which has already
+# been assigned to a different service. We list the poppassd as an
+# alias here. This should work for programs asking for this service.
+# (due to a bug in inetd the 3com-tsmux line is disabled)
+#3com-tsmux 106/tcp poppassd
+#3com-tsmux 106/udp poppassd
+rtelnet 107/tcp # Remote Telnet
+rtelnet 107/udp
+pop-2 109/tcp postoffice # POP version 2
+pop-2 109/udp
+pop-3 110/tcp # POP version 3
+pop-3 110/udp
+sunrpc 111/tcp portmapper # RPC 4.0 portmapper TCP
+sunrpc 111/udp portmapper # RPC 4.0 portmapper UDP
+auth 113/tcp authentication tap ident
+sftp 115/tcp
+uucp-path 117/tcp
+nntp 119/tcp readnews untp # USENET News Transfer Protocol
+ntp 123/tcp
+ntp 123/udp # Network Time Protocol
+netbios-ns 137/tcp # NETBIOS Name Service
+netbios-ns 137/udp
+netbios-dgm 138/tcp # NETBIOS Datagram Service
+netbios-dgm 138/udp
+netbios-ssn 139/tcp # NETBIOS session service
+netbios-ssn 139/udp
+imap2 143/tcp # Interim Mail Access Proto v2
+imap2 143/udp
+snmp 161/udp # Simple Net Mgmt Proto
+snmp-trap 162/udp snmptrap # Traps for SNMP
+cmip-man 163/tcp # ISO mgmt over IP (CMOT)
+cmip-man 163/udp
+cmip-agent 164/tcp
+cmip-agent 164/udp
+xdmcp 177/tcp # X Display Mgr. Control Proto
+xdmcp 177/udp
+nextstep 178/tcp NeXTStep NextStep # NeXTStep window
+nextstep 178/udp NeXTStep NextStep # server
+bgp 179/tcp # Border Gateway Proto.
+bgp 179/udp
+prospero 191/tcp # Cliff Neuman's Prospero
+prospero 191/udp
+irc 194/tcp # Internet Relay Chat
+irc 194/udp
+smux 199/tcp # SNMP Unix Multiplexer
+smux 199/udp
+at-rtmp 201/tcp # AppleTalk routing
+at-rtmp 201/udp
+at-nbp 202/tcp # AppleTalk name binding
+at-nbp 202/udp
+at-echo 204/tcp # AppleTalk echo
+at-echo 204/udp
+at-zis 206/tcp # AppleTalk zone information
+at-zis 206/udp
+qmtp 209/tcp # The Quick Mail Transfer Protocol
+qmtp 209/udp # The Quick Mail Transfer Protocol
+z3950 210/tcp wais # NISO Z39.50 database
+z3950 210/udp wais
+ipx 213/tcp # IPX
+ipx 213/udp
+imap3 220/tcp # Interactive Mail Access
+imap3 220/udp # Protocol v3
+ulistserv 372/tcp # UNIX Listserv
+ulistserv 372/udp
+https 443/tcp # MCom
+https 443/udp # MCom
+snpp 444/tcp # Simple Network Paging Protocol
+snpp 444/udp # Simple Network Paging Protocol
+saft 487/tcp # Simple Asynchronous File Transfer
+saft 487/udp # Simple Asynchronous File Transfer
+npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS
+npmp-local 610/udp dqs313_qmaster # npmp-local / DQS
+npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS
+npmp-gui 611/udp dqs313_execd # npmp-gui / DQS
+hmmp-ind 612/tcp dqs313_intercell# HMMP Indication / DQS
+hmmp-ind 612/udp dqs313_intercell# HMMP Indication / DQS
+#
+# UNIX specific services
+#
+exec 512/tcp
+biff 512/udp comsat
+login 513/tcp
+who 513/udp whod
+shell 514/tcp cmd # no passwords used
+syslog 514/udp
+printer 515/tcp spooler # line printer spooler
+talk 517/udp
+ntalk 518/udp
+route 520/udp router routed # RIP
+timed 525/udp timeserver
+tempo 526/tcp newdate
+courier 530/tcp rpc
+conference 531/tcp chat
+netnews 532/tcp readnews
+netwall 533/udp # -for emergency broadcasts
+uucp 540/tcp uucpd # uucp daemon
+afpovertcp 548/tcp # AFP over TCP
+afpovertcp 548/udp # AFP over TCP
+remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem
+klogin 543/tcp # Kerberized `rlogin' (v5)
+kshell 544/tcp krcmd # Kerberized `rsh' (v5)
+kerberos-adm 749/tcp # Kerberos `kadmin' (v5)
+#
+webster 765/tcp # Network dictionary
+webster 765/udp
+#
+# From ``Assigned Numbers'':
+#
+#> The Registered Ports are not controlled by the IANA and on most systems
+#> can be used by ordinary user processes or programs executed by ordinary
+#> users.
+#
+#> Ports are used in the TCP [45,106] to name the ends of logical
+#> connections which carry long term conversations. For the purpose of
+#> providing services to unknown callers, a service contact port is
+#> defined. This list specifies the port used by the server process as its
+#> contact port. While the IANA can not control uses of these ports it
+#> does register or list uses of these ports as a convienence to the
+#> community.
+#
+nfsdstatus 1110/tcp
+nfsd-keepalive 1110/udp
+
+ingreslock 1524/tcp
+ingreslock 1524/udp
+prospero-np 1525/tcp # Prospero non-privileged
+prospero-np 1525/udp
+datametrics 1645/tcp old-radius # datametrics / old radius entry
+datametrics 1645/udp old-radius # datametrics / old radius entry
+sa-msg-port 1646/tcp old-radacct # sa-msg-port / old radacct entry
+sa-msg-port 1646/udp old-radacct # sa-msg-port / old radacct entry
+radius 1812/tcp # Radius
+radius 1812/udp # Radius
+radacct 1813/tcp # Radius Accounting
+radacct 1813/udp # Radius Accounting
+nfsd 2049/tcp nfs
+nfsd 2049/udp nfs
+cvspserver 2401/tcp # CVS client/server operations
+cvspserver 2401/udp # CVS client/server operations
+mysql 3306/tcp # MySQL
+mysql 3306/udp # MySQL
+rfe 5002/tcp # Radio Free Ethernet
+rfe 5002/udp # Actually uses UDP only
+cfengine 5308/tcp # CFengine
+cfengine 5308/udp # CFengine
+bbs 7000/tcp # BBS service
+#
+#
+# Kerberos (Project Athena/MIT) services
+# Note that these are for Kerberos v4, and are unofficial. Sites running
+# v4 should uncomment these and comment out the v5 entries above.
+#
+kerberos4 750/udp kerberos-iv kdc # Kerberos (server) udp
+kerberos4 750/tcp kerberos-iv kdc # Kerberos (server) tcp
+kerberos_master 751/udp # Kerberos authentication
+kerberos_master 751/tcp # Kerberos authentication
+passwd_server 752/udp # Kerberos passwd server
+krb_prop 754/tcp # Kerberos slave propagation
+krbupdate 760/tcp kreg # Kerberos registration
+kpasswd 761/tcp kpwd # Kerberos "passwd"
+kpop 1109/tcp # Pop with Kerberos
+knetd 2053/tcp # Kerberos de-multiplexor
+zephyr-srv 2102/udp # Zephyr server
+zephyr-clt 2103/udp # Zephyr serv-hm connection
+zephyr-hm 2104/udp # Zephyr hostmanager
+eklogin 2105/tcp # Kerberos encrypted rlogin
+#
+# Unofficial but necessary (for NetBSD) services
+#
+supfilesrv 871/tcp # SUP server
+supfiledbg 1127/tcp # SUP debugging
+#
+# Datagram Delivery Protocol services
+#
+rtmp 1/ddp # Routing Table Maintenance Protocol
+nbp 2/ddp # Name Binding Protocol
+echo 4/ddp # AppleTalk Echo Protocol
+zip 6/ddp # Zone Information Protocol
+#
+# Services added for the Debian GNU/Linux distribution
+poppassd 106/tcp # Eudora
+poppassd 106/udp # Eudora
+mailq 174/tcp # Mailer transport queue for Zmailer
+mailq 174/tcp # Mailer transport queue for Zmailer
+omirr 808/tcp omirrd # online mirror
+omirr 808/udp omirrd # online mirror
+rmtcfg 1236/tcp # Gracilis Packeten remote config server
+xtel 1313/tcp # french minitel
+coda_opcons 1355/udp # Coda opcons (Coda fs)
+coda_venus 1363/udp # Coda venus (Coda fs)
+coda_auth 1357/udp # Coda auth (Coda fs)
+coda_udpsrv 1359/udp # Coda udpsrv (Coda fs)
+coda_filesrv 1361/udp # Coda filesrv (Coda fs)
+codacon 1423/tcp venus.cmu # Coda Console (Coda fs)
+coda_aux1 1431/tcp # coda auxiliary service (Coda fs)
+coda_aux1 1431/udp # coda auxiliary service (Coda fs)
+coda_aux2 1433/tcp # coda auxiliary service (Coda fs)
+coda_aux2 1433/udp # coda auxiliary service (Coda fs)
+coda_aux3 1435/tcp # coda auxiliary service (Coda fs)
+coda_aux3 1435/udp # coda auxiliary service (Coda fs)
+cfinger 2003/tcp # GNU Finger
+afbackup 2988/tcp # Afbackup system
+afbackup 2988/udp # Afbackup system
+icp 3130/tcp # Internet Cache Protocol (Squid)
+icp 3130/udp # Internet Cache Protocol (Squid)
+postgres 5432/tcp # POSTGRES
+postgres 5432/udp # POSTGRES
+fax 4557/tcp # FAX transmission service (old)
+hylafax 4559/tcp # HylaFAX client-server protocol (new)
+noclog 5354/tcp # noclogd with TCP (nocol)
+noclog 5354/udp # noclogd with UDP (nocol)
+hostmon 5355/tcp # hostmon uses TCP (nocol)
+hostmon 5355/udp # hostmon uses TCP (nocol)
+ircd 6667/tcp # Internet Relay Chat
+ircd 6667/udp # Internet Relay Chat
+webcache 8080/tcp # WWW caching service
+webcache 8080/udp # WWW caching service
+tproxy 8081/tcp # Transparent Proxy
+tproxy 8081/udp # Transparent Proxy
+mandelspawn 9359/udp mandelbrot # network mandelbrot
+amanda 10080/udp # amanda backup services
+amandaidx 10082/tcp # amanda backup services
+amidxtape 10083/tcp # amanda backup services
+isdnlog 20011/tcp # isdn logging system
+isdnlog 20011/udp # isdn logging system
+vboxd 20012/tcp # voice box system
+vboxd 20012/udp # voice box system
+binkp 24554/tcp # Binkley
+binkp 24554/udp # Binkley
+asp 27374/tcp # Address Search Protocol
+asp 27374/udp # Address Search Protocol
+tfido 60177/tcp # Ifmail
+tfido 60177/udp # Ifmail
+fido 60179/tcp # Ifmail
+fido 60179/udp # Ifmail
+
+# Local services
+
diff --git a/target/default/target_skeleton/etc/shadow b/target/default/target_skeleton/etc/shadow
new file mode 100644
index 0000000000..4941a1ac53
--- /dev/null
+++ b/target/default/target_skeleton/etc/shadow
@@ -0,0 +1,12 @@
+root::10933:0:99999:7:::
+bin:*:10933:0:99999:7:::
+daemon:*:10933:0:99999:7:::
+adm:*:10933:0:99999:7:::
+lp:*:10933:0:99999:7:::
+sync:*:10933:0:99999:7:::
+shutdown:*:10933:0:99999:7:::
+halt:*:10933:0:99999:7:::
+uucp:*:10933:0:99999:7:::
+operator:*:10933:0:99999:7:::
+nobody:*:10933:0:99999:7:::
+default::10933:0:99999:7:::
diff --git a/target/default/target_skeleton/root/.bash_history b/target/default/target_skeleton/root/.bash_history
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/target/default/target_skeleton/root/.bash_history
diff --git a/target/default/target_skeleton/root/.bash_logout b/target/default/target_skeleton/root/.bash_logout
new file mode 100644
index 0000000000..77ef1f9508
--- /dev/null
+++ b/target/default/target_skeleton/root/.bash_logout
@@ -0,0 +1,7 @@
+# ~/.bash_logout: executed by bash(1) when login shell exits.
+
+# when leaving the console clear the screen to increase privacy
+
+case "`tty`" in
+ /dev/tty[0-9]*) clear
+esac
diff --git a/target/default/target_skeleton/root/.bash_profile b/target/default/target_skeleton/root/.bash_profile
new file mode 100644
index 0000000000..27bf14953d
--- /dev/null
+++ b/target/default/target_skeleton/root/.bash_profile
@@ -0,0 +1,15 @@
+# .bash_profile
+
+export PATH=\
+/bin:\
+/sbin:\
+/usr/bin:\
+/usr/sbin:\
+/usr/bin/X11:\
+/usr/local/bin
+
+umask 022
+
+if [ -f ~/.bashrc ]; then
+ source ~/.bashrc
+fi
diff --git a/target/default/target_skeleton/root/.bashrc b/target/default/target_skeleton/root/.bashrc
new file mode 100644
index 0000000000..d13c8f9026
--- /dev/null
+++ b/target/default/target_skeleton/root/.bashrc
@@ -0,0 +1,48 @@
+# ~/.bashrc: executed by bash(1) for non-login interactive shells.
+
+export PATH=\
+/bin:\
+/sbin:\
+/usr/bin:\
+/usr/sbin:\
+/usr/bin/X11:\
+/usr/local/bin
+
+# If running interactively, then:
+if [ "$PS1" ]; then
+
+ if [ "$BASH" ]; then
+ export PS1="[\u@\h \W]\\$ "
+ else
+ if [ "`id -u`" -eq 0 ]; then
+ export PS1='# '
+ else
+ export PS1='$ '
+ fi
+ fi
+
+ export USER=`id -un`
+ export LOGNAME=$USER
+ export HOSTNAME=`/bin/hostname`
+ export HISTSIZE=1000
+ export HISTFILESIZE=1000
+ export PAGER='/bin/more '
+ export EDITOR='/bin/vi'
+ export INPUTRC=/etc/inputrc
+ export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile
+ export LS_COLORS='no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.png=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:';
+
+ ### Some aliases
+ alias ps2='ps facux '
+ alias ps1='ps faxo "%U %t %p %a" '
+ alias af='ps af'
+ alias cls='clear'
+ alias ll='/bin/ls --color=tty -laFh'
+ alias ls='/bin/ls --color=tty -F'
+ alias df='df -h'
+ alias indent='indent -bad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs -npsl -nsc -nsob -nss -ts4 '
+ #alias bc='bc -l'
+ alias minicom='minicom -c on'
+ alias calc='calc -Cd '
+ alias bc='calc -Cd '
+fi;
diff --git a/target/default/target_skeleton/usr/share/terminfo/a/ansi b/target/default/target_skeleton/usr/share/terminfo/a/ansi
new file mode 100644
index 0000000000..3884faec40
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/a/ansi
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/d/dumb b/target/default/target_skeleton/usr/share/terminfo/d/dumb
new file mode 100644
index 0000000000..fd4091a994
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/d/dumb
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/l/linux b/target/default/target_skeleton/usr/share/terminfo/l/linux
new file mode 100644
index 0000000000..7f5844cef5
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/l/linux
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/r/rxvt b/target/default/target_skeleton/usr/share/terminfo/r/rxvt
new file mode 100644
index 0000000000..359465fea8
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/r/rxvt
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/s/screen b/target/default/target_skeleton/usr/share/terminfo/s/screen
new file mode 100644
index 0000000000..b8377500ad
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/s/screen
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/s/screen-w b/target/default/target_skeleton/usr/share/terminfo/s/screen-w
new file mode 100644
index 0000000000..8533897b95
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/s/screen-w
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/s/sun b/target/default/target_skeleton/usr/share/terminfo/s/sun
new file mode 100644
index 0000000000..77aaa3a958
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/s/sun
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/v/vt100 b/target/default/target_skeleton/usr/share/terminfo/v/vt100
new file mode 100644
index 0000000000..647ca5c133
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/v/vt100
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/v/vt220 b/target/default/target_skeleton/usr/share/terminfo/v/vt220
new file mode 100644
index 0000000000..f10553acd6
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/v/vt220
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/v/vt52 b/target/default/target_skeleton/usr/share/terminfo/v/vt52
new file mode 100644
index 0000000000..61a8ad04d3
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/v/vt52
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/x/xterm b/target/default/target_skeleton/usr/share/terminfo/x/xterm
new file mode 100644
index 0000000000..310a7fb62a
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/x/xterm
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/terminfo/x/xterm-xfree86 b/target/default/target_skeleton/usr/share/terminfo/x/xterm-xfree86
new file mode 100644
index 0000000000..e4d9966c72
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/terminfo/x/xterm-xfree86
Binary files differ
diff --git a/target/default/target_skeleton/usr/share/udhcpc/default.script b/target/default/target_skeleton/usr/share/udhcpc/default.script
new file mode 100755
index 0000000000..a52a7f8122
--- /dev/null
+++ b/target/default/target_skeleton/usr/share/udhcpc/default.script
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# udhcpc script edited by Tim Riker <Tim@Rikers.org>
+
+[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
+
+RESOLV_CONF="/etc/resolv.conf"
+[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+
+case "$1" in
+ deconfig)
+ /sbin/ifconfig $interface 0.0.0.0
+ ;;
+
+ renew|bound)
+ /sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+
+ if [ -n "$router" ] ; then
+ echo "deleting routers"
+ while route del default gw 0.0.0.0 dev $interface ; do
+ :
+ done
+
+ for i in $router ; do
+ route add default gw $i dev $interface
+ done
+ fi
+
+ echo -n > $RESOLV_CONF
+ [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
+ for i in $dns ; do
+ echo adding dns $i
+ echo nameserver $i >> $RESOLV_CONF
+ done
+ ;;
+esac
+
+exit 0
diff --git a/target/ext2/ext2root.mk b/target/ext2/ext2root.mk
new file mode 100644
index 0000000000..ff2877145f
--- /dev/null
+++ b/target/ext2/ext2root.mk
@@ -0,0 +1,55 @@
+#############################################################
+#
+# genext2fs to build to target ext2 filesystems
+#
+#############################################################
+GENEXT2_DIR=$(BUILD_DIR)/genext2fs-1.3
+GENEXT2_SOURCE=genext2fs_1.3.orig.tar.gz
+GENEXT2_SITE=http://ftp.debian.org/debian/pool/main/g/genext2fs
+GENEXT2_PATCH=$(SOURCE_DIR)/genext2fs.patch
+
+$(DL_DIR)/$(GENEXT2_SOURCE):
+ $(WGET) -P $(DL_DIR) $(GENEXT2_SITE)/$(GENEXT2_SOURCE)
+
+$(GENEXT2_DIR): $(DL_DIR)/$(GENEXT2_SOURCE) $(GENEXT2_PATCH)
+ zcat $(DL_DIR)/$(GENEXT2_SOURCE) | tar -C $(BUILD_DIR) -xvf -
+ mv $(GENEXT2_DIR).orig $(GENEXT2_DIR)
+ cat $(GENEXT2_PATCH) | patch -p1 -d $(GENEXT2_DIR)
+
+$(GENEXT2_DIR)/genext2fs: $(GENEXT2_DIR)
+ $(MAKE) CFLAGS="-Wall -O2 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE \
+ -D_FILE_OFFSET_BITS=64" -C $(GENEXT2_DIR);
+ touch -c $(GENEXT2_DIR)/genext2fs
+
+genext2fs: $(GENEXT2_DIR)/genext2fs
+
+
+
+#############################################################
+#
+# Build the ext2 root filesystem image
+#
+#############################################################
+
+# How much KB we want to add to the calculated size for slack space
+GENEXT2_REALSIZE=$(subst total,, $(shell LANG=C du $(TARGET_DIR) -s -c -k | grep total ))
+GENEXT2_ADDTOROOTSIZE=$(shell if [ $(GENEXT2_REALSIZE) -ge 20000 ] ; then echo 16384; else echo 16; fi)
+GENEXT2_SIZE=$(shell expr $(GENEXT2_REALSIZE) + $(GENEXT2_ADDTOROOTSIZE) + 200)
+# We currently add about 400 device nodes, so add that into the total
+GENEXT2_INODES=$(shell expr $(shell find $(TARGET_DIR) | wc -l) + 400)
+#GENEXT2_SIZE=100000
+
+ext2root: genext2fs
+ #-@find $(TARGET_DIR)/lib -type f -name \*.so\* | xargs $(STRIP) --strip-unneeded 2>/dev/null || true;
+ -@find $(TARGET_DIR) -type f -perm +111 | xargs $(STRIP) 2>/dev/null || true;
+ $(GENEXT2_DIR)/genext2fs -i $(GENEXT2_INODES) -b $(GENEXT2_SIZE) \
+ -d $(TARGET_DIR) -q -D $(SOURCE_DIR)/device_table.txt $(IMAGE)
+
+ext2root-source: $(DL_DIR)/$(GENEXT2_SOURCE)
+
+ext2root-clean:
+ -$(MAKE) -C $(GENEXT2_DIR) clean
+
+ext2root-dirclean:
+ rm -rf $(GENEXT2_DIR)
+
diff --git a/target/ext2/genext2fs.patch b/target/ext2/genext2fs.patch
new file mode 100644
index 0000000000..73e5ce0aaa
--- /dev/null
+++ b/target/ext2/genext2fs.patch
@@ -0,0 +1,2457 @@
+diff -urN genext2fs-1.3.orig/Makefile genext2fs-1.3/Makefile
+--- genext2fs-1.3.orig/Makefile 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/Makefile 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,46 @@
++CC=gcc
++CFLAGS=-Wall -O0 -g
++
++SRC=genext2fs.c
++OBJS=$(patsubst %.c,%.o, $(SRC))
++
++all: genext2fs
++INSTALL=install
++
++genext2fs: $(OBJS)
++ $(CC) $(CFLAGS) -o $@ $(OBJS) -o $@
++
++$(OBJS): %.o : %.c
++ $(CC) $(CFLAGS) -c $< -o $@
++
++$(OBJS): Makefile
++
++install:
++ $(INSTALL) -d $(DESTDIR)/usr/bin/
++ $(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/
++ $(INSTALL) -d $(DESTDIR)/usr/share/man/man8/
++ $(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/
++
++clean:
++ rm -rf *.o *.a core genext2fs
++ rm -rf test ext2.img
++
++check: all
++ mkdir -p test
++ dd if=/dev/zero of=test/zero count=1
++ ./genext2fs -b 4096 -d test ext2.img
++
++ md5=`md5sum ext2.img | cut -f 1 -d " "`; \
++ if [ "$$md5" != "89471302d95f96a76fbb2cff98182cde" ] ; then \
++ echo "test failed."; \
++ else \
++ echo "test succeeded."; \
++ fi
++
++# test genext2fs by creating the image and comparing checksums
++test: all
++ sh ./test.sh
++
++# test genext2fs by actually mounting the created image.
++test-mount: all
++ sudo sh ./test-mount.sh
+diff -urN genext2fs-1.3.orig/debian/changelog genext2fs-1.3/debian/changelog
+--- genext2fs-1.3.orig/debian/changelog 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/changelog 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,17 @@
++genext2fs (1.3-2) unstable; urgency=low
++
++ * apply fix from upstream cvs that appears to fix endian bug
++ (closes: #122411)
++ * mention filesystem size limit in manpage (closes: #122729)
++ * mention that hard links are not supported in manpage
++ (closes: #155464)
++ * add sanity check at the end of the build
++
++ -- David Kimdon <dwhedon@debian.org> Fri, 8 Mar 2002 23:17:36 -0800
++
++genext2fs (1.3-1) unstable; urgency=low
++
++ * Initial Release. (closes: #105263)
++
++ -- David Kimdon <dwhedon@debian.org> Sat, 14 Jul 2001 13:24:49 -0700
++
+diff -urN genext2fs-1.3.orig/debian/control genext2fs-1.3/debian/control
+--- genext2fs-1.3.orig/debian/control 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/control 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,19 @@
++Source: genext2fs
++Section: admin
++Priority: optional
++Maintainer: David Kimdon <dwhedon@debian.org>
++Build-Depends: debhelper (>> 3.0.0)
++Standards-Version: 3.5.2
++
++Package: genext2fs
++Architecture: any
++Depends: ${shlibs:Depends}
++Description: ext2 filesystem generator for embedded systems
++ `genext2fs' is meant to generate an ext2 filesystem
++ as a normal (non-root) user. It doesn't require you to mount
++ the image file to copy files on it. It doesn't even require
++ you to be the superuser to make device nodes.
++ .
++ Warning ! `genext2fs' has been designed for embedded
++ systems. As such, it will generate a filesystem for single-user
++ usage: all files/directories/etc... will belong to UID/GID 0
+diff -urN genext2fs-1.3.orig/debian/copyright genext2fs-1.3/debian/copyright
+--- genext2fs-1.3.orig/debian/copyright 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/copyright 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,15 @@
++This package was debianized by David Kimdon <dwhedon@debian.org> on
++Sat, 14 Jul 2001 13:24:49 -0700.
++
++It was downloaded from http://freshmeat.net/projects/genext2fs/
++Upstream Author(s): Xavier Bestel <xbestel@aplio.fr>
++
++Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
++
++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.
++
++On Debian systems, the complete text of the GNU General Public
++License can be found in /usr/share/common-licenses/GPL file.
+diff -urN genext2fs-1.3.orig/debian/rules genext2fs-1.3/debian/rules
+--- genext2fs-1.3.orig/debian/rules 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/rules 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,70 @@
++#!/usr/bin/make -f
++# Sample debian/rules that uses debhelper.
++# GNU copyright 1997 to 1999 by Joey Hess.
++
++# Uncomment this to turn on verbose mode.
++#export DH_VERBOSE=1
++
++# This is the debhelper compatability version to use.
++export DH_COMPAT=2
++
++configure: configure-stamp
++configure-stamp:
++ dh_testdir
++ # Add here commands to configure the package.
++ # ./configure --prefix=/usr --mandir=/usr/share/man/
++
++ touch configure-stamp
++
++build: configure-stamp build-stamp
++build-stamp:
++ dh_testdir
++
++ # Add here commands to compile the package.
++ $(MAKE)
++ $(MAKE) check
++
++ touch build-stamp
++
++clean:
++ dh_testdir
++ dh_testroot
++ rm -f build-stamp configure-stamp
++
++ # Add here commands to clean up after the build process.
++ -$(MAKE) clean
++
++ dh_clean
++
++install: build
++ dh_testdir
++ dh_testroot
++ dh_clean -k
++ dh_installdirs
++
++ # Add here commands to install the package into debian/genext2fs.
++ $(MAKE) install DESTDIR=`pwd`/debian/genext2fs
++
++
++# Build architecture-independent files here.
++binary-indep: build install
++# We have nothing to do by default.
++
++# Build architecture-dependent files here.
++binary-arch: build install
++ dh_testdir
++ dh_testroot
++ dh_installdocs
++ dh_installchangelogs
++ dh_link
++ dh_strip
++ dh_compress
++ dh_fixperms
++ dh_installdeb
++ dh_shlibdeps
++ dh_gencontrol
++ dh_md5sums
++ dh_builddeb
++
++binary: binary-indep binary-arch
++.PHONY: build clean binary-indep binary-arch binary install configure
+diff -urN genext2fs-1.3.orig/dev.txt genext2fs-1.3/dev.txt
+--- genext2fs-1.3.orig/dev.txt 2000-09-28 09:03:19.000000000 -0600
++++ genext2fs-1.3/dev.txt 1969-12-31 17:00:00.000000000 -0700
+@@ -1,94 +0,0 @@
+-drwx /dev
+-crw- 10,190 /dev/lcd
+-crw- 10,191 /dev/splc781
+-crw- 4,0 /dev/console
+-crw- 5,64 /dev/cua0
+-crw- 5,65 /dev/cua1
+-crw- 5,66 /dev/cua2
+-crw- 5,70 /dev/cua6
+-crw- 5,71 /dev/cua7
+-crw- 5,72 /dev/cua8
+-crw- 5,73 /dev/cua9
+-crw- 29,0 /dev/fb0
+-crw- 29,32 /dev/fb1
+-crw- 1,2 /dev/kmem
+-crw- 1,1 /dev/mem
+-crw- 1,3 /dev/null
+-crw- 2,2 /dev/ptyp2
+-crw- 2,3 /dev/ptyp3
+-crw- 2,5 /dev/ptyp5
+-crw- 2,4 /dev/ptyp4
+-crw- 10,178 /dev/triokb
+-crw- 2,0 /dev/ptyp0
+-crw- 2,6 /dev/ptyp6
+-crw- 2,7 /dev/ptyp7
+-crw- 2,8 /dev/ptyp8
+-crw- 2,9 /dev/ptyp9
+-crw- 2,10 /dev/ptypa
+-crw- 2,11 /dev/ptypb
+-crw- 2,12 /dev/ptypc
+-crw- 2,13 /dev/ptypd
+-crw- 2,14 /dev/ptype
+-crw- 2,15 /dev/ptypf
+-brw- 1,0 /dev/ram0
+-brw- 1,1 /dev/ram1
+-brw- 1,2 /dev/ram2
+-brw- 1,3 /dev/ram3
+-br-- 31,0 /dev/rom0
+-brw- 31,1 /dev/rom1
+-brw- 31,2 /dev/rom2
+-brw- 31,3 /dev/rom3
+-crw- 5,0 /dev/tty
+-crw- 4,0 /dev/tty0
+-crwx 4,1 /dev/tty1
+-crwx 4,2 /dev/tty2
+-crwx 4,3 /dev/tty3
+-crwx 4,4 /dev/tty4
+-crw- 4,5 /dev/tty5
+-crwx 4,6 /dev/tty6
+-crw- 4,7 /dev/tty7
+-crw- 4,8 /dev/tty8
+-crw- 4,9 /dev/tty9
+-crw- 4,64 /dev/ttyS0
+-crw- 4,65 /dev/ttyS1
+-crw- 4,66 /dev/ttyS2
+-crw- 4,67 /dev/ttyS3
+-crw- 4,68 /dev/ttyS4
+-crw- 4,69 /dev/ttyS5
+-crw- 4,70 /dev/ttyS6
+-crw- 4,71 /dev/ttyS7
+-crw- 4,72 /dev/ttyS8
+-crw- 4,73 /dev/ttyS9
+-crw- 3,0 /dev/ttyp0
+-crw- 3,1 /dev/ttyp1
+-crw- 3,2 /dev/ttyp2
+-crw- 3,3 /dev/ttyp3
+-crw- 3,4 /dev/ttyp4
+-crw- 3,5 /dev/ttyp5
+-crw- 3,6 /dev/ttyp6
+-crw- 3,7 /dev/ttyp7
+-crw- 3,8 /dev/ttyp8
+-crw- 3,9 /dev/ttyp9
+-crw- 3,10 /dev/ttypa
+-crw- 3,11 /dev/ttypb
+-crw- 3,12 /dev/ttypc
+-crw- 3,13 /dev/ttypd
+-crw- 3,14 /dev/ttype
+-crw- 3,15 /dev/ttypf
+-crw- 1,5 /dev/zero
+-crwx 10,111 /dev/dtedrv
+-crwx 4,110 /dev/ttyM
+-crw- 77,1 /dev/tssnd
+-crw- 77,2 /dev/tstone
+-crw- 2,1 /dev/ptyp1
+-crwx 10,180 /dev/triohook
+-crw- 90,0 /dev/mtd0
+-brw- 44,0 /dev/ftl0
+-crw- 10,175 /dev/tporta
+-crw- 10,176 /dev/tportb
+-crwx 10,100 /dev/softmodem
+-crwx 10,101 /dev/softmodem_signals
+-crwx 10,181 /dev/triovoice
+-crw- 5,67 /dev/cua3
+-crw- 5,68 /dev/cua4
+-crw- 5,69 /dev/cua5
+diff -urN genext2fs-1.3.orig/device_table.txt genext2fs-1.3/device_table.txt
+--- genext2fs-1.3.orig/device_table.txt 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/device_table.txt 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,129 @@
++# When building a target filesystem, it is desirable to not have to
++# become root and then run 'mknod' a thousand times. Using a device
++# table you can create device nodes and directories "on the fly".
++#
++# This is a sample device table file for use with genext2fs. You can
++# do all sorts of interesting things with a device table file. For
++# example, if you want to adjust the permissions on a particular file
++# you can just add an entry like:
++# /sbin/foobar f 2755 0 0 - - - - -
++# and (assuming the file /sbin/foobar exists) it will be made setuid
++# root (regardless of what its permissions are on the host filesystem.
++# Furthermore, you can use a single table entry to create a many device
++# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
++# I could just use the following two table entries:
++# /dev/hda b 640 0 0 3 0 0 0 -
++# /dev/hda b 640 0 0 3 1 1 1 15
++#
++# Device table entries take the form of:
++# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++# where name is the file name, type can be one of:
++# f A regular file
++# d Directory
++# c Character special device file
++# b Block special device file
++# p Fifo (named pipe)
++# uid is the user id for the target file, gid is the group id for the
++# target file. The rest of the entries (major, minor, etc) apply only
++# to device special files.
++
++# Have fun
++# -Erik Andersen <andersen@codepoet.org>
++#
++
++#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++/dev d 755 0 0 - - - - -
++/dev/mem c 640 0 0 1 1 0 0 -
++/dev/kmem c 640 0 0 1 2 0 0 -
++/dev/null c 640 0 0 1 3 0 0 -
++/dev/zero c 640 0 0 1 5 0 0 -
++/dev/random c 640 0 0 1 8 0 0 -
++/dev/urandom c 640 0 0 1 9 0 0 -
++/dev/tty c 666 0 0 5 0 0 0 -
++/dev/tty c 666 0 0 4 0 0 1 6
++/dev/console c 640 0 0 5 1 0 0 -
++/dev/ram b 640 0 0 1 1 0 0 -
++/dev/ram b 640 0 0 1 0 0 1 4
++/dev/loop b 640 0 0 7 0 0 1 2
++/dev/ptmx c 666 0 0 5 2 0 0 -
++#/dev/ttyS c 640 0 0 4 64 0 1 4
++#/dev/psaux c 640 0 0 10 1 0 0 -
++#/dev/rtc c 640 0 0 10 135 0 0 -
++
++# Adjust permissions on some normal files
++#/etc/shadow f 600 0 0 - - - - -
++#/bin/tinylogin f 4755 0 0 - - - - -
++
++# User-mode Linux stuff
++/dev/ubda b 640 0 0 98 0 0 0 -
++/dev/ubda b 640 0 0 98 1 1 1 15
++
++# IDE Devices
++/dev/hda b 640 0 0 3 0 0 0 -
++/dev/hda b 640 0 0 3 1 1 1 15
++/dev/hdb b 640 0 0 3 64 0 0 -
++/dev/hdb b 640 0 0 3 65 1 1 15
++#/dev/hdc b 640 0 0 22 0 0 0 -
++#/dev/hdc b 640 0 0 22 1 1 1 15
++#/dev/hdd b 640 0 0 22 64 0 0 -
++#/dev/hdd b 640 0 0 22 65 1 1 15
++#/dev/hde b 640 0 0 33 0 0 0 -
++#/dev/hde b 640 0 0 33 1 1 1 15
++#/dev/hdf b 640 0 0 33 64 0 0 -
++#/dev/hdf b 640 0 0 33 65 1 1 15
++#/dev/hdg b 640 0 0 34 0 0 0 -
++#/dev/hdg b 640 0 0 34 1 1 1 15
++#/dev/hdh b 640 0 0 34 64 0 0 -
++#/dev/hdh b 640 0 0 34 65 1 1 15
++
++# SCSI Devices
++#/dev/sda b 640 0 0 8 0 0 0 -
++#/dev/sda b 640 0 0 8 1 1 1 15
++#/dev/sdb b 640 0 0 8 16 0 0 -
++#/dev/sdb b 640 0 0 8 17 1 1 15
++#/dev/sdc b 640 0 0 8 32 0 0 -
++#/dev/sdc b 640 0 0 8 33 1 1 15
++#/dev/sdd b 640 0 0 8 48 0 0 -
++#/dev/sdd b 640 0 0 8 49 1 1 15
++#/dev/sde b 640 0 0 8 64 0 0 -
++#/dev/sde b 640 0 0 8 65 1 1 15
++#/dev/sdf b 640 0 0 8 80 0 0 -
++#/dev/sdf b 640 0 0 8 81 1 1 15
++#/dev/sdg b 640 0 0 8 96 0 0 -
++#/dev/sdg b 640 0 0 8 97 1 1 15
++#/dev/sdh b 640 0 0 8 112 0 0 -
++#/dev/sdh b 640 0 0 8 113 1 1 15
++#/dev/sg c 640 0 0 21 0 0 1 15
++#/dev/scd b 640 0 0 11 0 0 1 15
++#/dev/st c 640 0 0 9 0 0 1 8
++#/dev/nst c 640 0 0 9 128 0 1 8
++#/dev/st c 640 0 0 9 32 1 1 4
++#/dev/st c 640 0 0 9 64 1 1 4
++#/dev/st c 640 0 0 9 96 1 1 4
++
++# Floppy disk devices
++#/dev/fd b 640 0 0 2 0 0 1 2
++#/dev/fd0d360 b 640 0 0 2 4 0 0 -
++#/dev/fd1d360 b 640 0 0 2 5 0 0 -
++#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
++#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
++#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
++#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
++#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
++#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
++
++# All the proprietary cdrom devices in the world
++#/dev/aztcd b 640 0 0 29 0 0 0 -
++#/dev/bpcd b 640 0 0 41 0 0 0 -
++#/dev/capi20 c 640 0 0 68 0 0 1 2
++#/dev/cdu31a b 640 0 0 15 0 0 0 -
++#/dev/cdu535 b 640 0 0 24 0 0 0 -
++#/dev/cm206cd b 640 0 0 32 0 0 0 -
++#/dev/sjcd b 640 0 0 18 0 0 0 -
++#/dev/sonycd b 640 0 0 15 0 0 0 -
++#/dev/gscd b 640 0 0 16 0 0 0 -
++#/dev/sbpcd b 640 0 0 25 0 0 0 -
++#/dev/sbpcd b 640 0 0 25 0 0 1 4
++#/dev/mcd b 640 0 0 23 0 0 0 -
++#/dev/optcd b 640 0 0 17 0 0 0 -
++
+diff -urN genext2fs-1.3.orig/genext2fs.8 genext2fs-1.3/genext2fs.8
+--- genext2fs-1.3.orig/genext2fs.8 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/genext2fs.8 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,125 @@
++.\" Hey, EMACS: -*- nroff -*-
++.\" First parameter, NAME, should be all caps
++.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
++.\" other parameters are allowed: see man(7), man(1)
++.TH GENEXT2FS 8 "July 14, 2001"
++.\" Please adjust this date whenever revising the manpage.
++.\"
++.\" Some roff macros, for reference:
++.\" .nh disable hyphenation
++.\" .hy enable hyphenation
++.\" .ad l left justify
++.\" .ad b justify to both left and right margins
++.\" .nf disable filling
++.\" .fi enable filling
++.\" .br insert line break
++.\" .sp <n> insert n+1 empty lines
++.\" for manpage-specific macros, see man(7)
++.SH NAME
++genext2fs \- ext2 filesystem generator for embedded systems
++.SH SYNOPSIS
++.B genext2fs
++.RI [ options ] " image"
++.SH DESCRIPTION
++\fBgenext2fs\fP generates an ext2 filesystem
++as a normal (non-root) user. It doesn't require you to mount
++the image file to copy files on it. It doesn't even require
++you to be the superuser to make device nodes.
++.SH OPTIONS
++.TP
++.BI -x \ image
++Use this image as a starting point
++.TP
++.BI -d \ directory
++Add this directory as source
++.TP
++.BI -f \ FILE
++.TP
++.BI -D \ FILE
++Uses the named FILE as a device table file, to create device
++nodes and directories "on the fly".
++.TP
++.BI -b \ blocks
++Size in blocks
++.TP
++.BI -i \ inodes
++Number of inodes
++.TP
++.BI -r \ reserved
++Number of reserved blocks
++.TP
++.BI -g \ path
++Generate a block map file for this path
++.TP
++.BI -e \ value
++Fill unallocated blocks with value
++.TP
++.BI -z
++Make files with holes
++.TP
++.BI -U
++Squash owners making all files be owned by root
++.TP
++.BI -P
++Squash permissions on all files
++.TP
++.BI -q
++Squash permissions and owners (same as -P -U)
++.TP
++.BI -v
++Print resulting filesystem structure
++.TP
++.BI -h
++Display help
++.TP
++.SH EXAMPLES
++
++.EX
++.B
++ genext2fs -b 1440 -d src /dev/fd0
++.EE
++
++All files in the
++.I src
++directory will be written to
++.B /dev/fd0
++as a new ext2 filesystem image. You can then mount the floppy as
++usual.
++
++.EX
++.B
++ genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
++.EE
++
++This example builds a filesystem from all the files in
++.I src
++, then device nodes are created based on the content the device_table file
++.I dev.txt.
++An example device file follows:
++
++.EX
++ #<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++ /dev d 755 0 0 - - - - -
++ /dev/mem c 640 0 0 1 1 0 0 -
++ /dev/tty c 666 0 0 5 0 0 0 -
++ /dev/tty c 666 0 0 4 0 0 1 6
++ /dev/loop b 640 0 0 7 0 0 1 2
++ /dev/hda b 640 0 0 3 0 0 0 -
++ /dev/hda b 640 0 0 3 1 1 1 16
++.EE
++
++This device table creates the /dev directory, a character device
++node /dev/mem (major 1, minor 1), it also creates /dev/tty,
++/dev/tty[0-5], /dev/loop[0-1], /dev/hda, and /dev/hda0 to /dev/hda15
++.SH BUGS
++\fBgenext2fs\fP does not support hard links. Hard links present in the input
++tree will be represented as separate files in the ext2 image.
++
++.SH SEE ALSO
++.BR mkfs (8),
++.BR genromfs (8),
++.BR mkisofs (8).
++.br
++.SH AUTHOR
++This manual page was written by David Kimdon <dwhedon@debian.org>,
++for the Debian GNU/Linux system (but may be used by others).
+diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs-1.3/genext2fs.c
+--- genext2fs-1.3.orig/genext2fs.c 2001-06-18 02:11:32.000000000 -0600
++++ genext2fs-1.3/genext2fs.c 2003-04-21 01:48:35.000000000 -0600
+@@ -1,3 +1,4 @@
++/* vi: set sw=8 ts=8: */
+ // genext2fs.c
+ //
+ // ext2 filesystem generator for embedded systems
+@@ -26,6 +27,22 @@
+ // Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr
+ // Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr
+ // 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com
++// 23 Mar 2002 Bugfix: test for IFCHR or IFBLK was flawed
++// 10 Oct 2002 Added comments,makefile targets, vsundar@ixiacom.com
++// endianess swap assert check.
++// Copyright (C) 2002 Ixia communications
++// 12 Oct 2002 Added support for triple indirection vsundar@ixiacom.com
++// Copyright (C) 2002 Ixia communications
++// 14 Oct 2002 Added support for groups vsundar@ixiacom.com
++// Copyright (C) 2002 Ixia communications
++// 5 Jan 2003 Bugfixes: reserved inodes should be set vsundar@usc.edu
++// only in the first group; directory names
++// need to be null padded at the end; and
++// number of blocks per group should be a
++// multiple of 8. Updated md5 values.
++// 6 Jan 2003 Erik Andersen <andersee@debian.org> added
++// mkfs.jffs2 compatible device table support,
++// along with -q, -P, -U
+
+
+ // `genext2fs' is a mean to generate an ext2 filesystem
+@@ -33,10 +50,6 @@
+ // the image file to copy files on it. It doesn't even require
+ // you to be the superuser to make device nodes.
+ //
+-// Warning ! `genext2fs' has been designed for embedded
+-// systems. As such, it will generate a filesystem for single-user
+-// usage: all files/directories/etc... will belong to UID/GID 0
+-//
+ // Example usage:
+ //
+ // # genext2fs -b 1440 -d srcdir /dev/fd0
+@@ -45,21 +58,15 @@
+ // a new ext2 filesystem image. You can then mount the floppy as
+ // usual.
+ //
+-// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img
++// # genext2fs -b 1024 -d builddir -D device_table.txt flashdisk.img
+ //
+ // This one would build a filesystem from all the files in builddir,
+-// then would read a devices list and make apropriate nodes. The
+-// format for the device list is:
+-//
+-// drwx /dev
+-// crw- 10,190 /dev/lcd
+-// brw- 1,0 /dev/ram0
+-//
+-// This device list builds the /dev directory, a character device
+-// node /dev/lcd (major 10, minor 190) and a block device node
+-// /dev/ram0 (major 1, minor 0)
++// then would read the device_table.txt file and make apropriate nodes.
++// The format for the device table file is covered in detail in the sample
++// device_table.txt file provided with the genext2fs source.
+
+
++#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -67,6 +74,11 @@
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
++#include <assert.h>
++#include <time.h>
++#include <ctype.h>
++#include <errno.h>
++#include <fcntl.h>
+
+
+
+@@ -76,10 +88,14 @@
+ #define BLOCKSIZE 1024
+ #define BLOCKS_PER_GROUP 8192
+ #define BYTES_PER_INODE (8*BLOCKSIZE)
++/* Percentage of blocks that are reserved.*/
+ #define RESERVED_INODES 5/100
+
+
+ // inode block size (why is it != BLOCKSIZE ?!?)
++/* The field i_blocks in the ext2 inode stores the number of data blocks
++ but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
++ INOBLK is the number of such blocks in an actual disk block */
+
+ #define INODE_BLOCKSIZE 512
+ #define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE)
+@@ -147,6 +163,39 @@
+
+ #define OP_HOLES 0x01 // make files with holes
+
++/* Defines for accessing group details */
++
++// Number of groups in the filesystem
++#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group )
++
++// Get group block bitmap (bbm) given the group number
++#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
++
++// Get group inode bitmap (ibm) given the group number
++#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
++
++// Given an inode number find the group it belongs to
++#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
++
++//Given an inode number get the inode bitmap that covers it
++#define GRP_GET_INODE_BITMAP(fs,nod) \
++ ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
++
++//Given an inode number find its offset within the inode bitmap that covers it
++#define GRP_IBM_OFFSET(fs,nod) \
++ ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
++
++// Given a block number find the group it belongs to
++#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
++
++//Given a block number get the block bitmap that covers it
++#define GRP_GET_BLOCK_BITMAP(fs,blk) \
++ ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
++
++//Given a block number find its offset within the block bitmap that covers it
++#define GRP_BBM_OFFSET(fs,blk) \
++ ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
++
+
+ // used types
+
+@@ -287,7 +336,6 @@
+ {
+ groupdescriptor_decl
+ uint32 bg_reserved[3];
+- uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];
+ } groupdescriptor;
+
+ typedef struct
+@@ -304,6 +352,32 @@
+
+ typedef uint8 block[BLOCKSIZE];
+
++/* blockwalker fields:
++ The blockwalker is used to access all the blocks of a file (including
++ the indirection blocks) through repeated calls to walk_bw.
++
++ bpdir -> index into the inode->i_block[]. Indicates level of indirection.
++ bnum -> total number of blocks so far accessed. including indirection
++ blocks.
++ bpind,bpdind,bptind -> index into indirection blocks.
++
++ bpind, bpdind, bptind do *NOT* index into single, double and triple
++ indirect blocks resp. as you might expect from their names. Instead
++ they are in order the 1st, 2nd & 3rd index to be used
++
++ As an example..
++ To access data block number 70000:
++ bpdir: 15 (we are doing triple indirection)
++ bpind: 0 ( index into the triple indirection block)
++ bpdind: 16 ( index into the double indirection block)
++ bptind: 99 ( index into the single indirection block)
++ 70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
++
++ So,for double indirection bpind will index into the double indirection
++ block and bpdind into the single indirection block. For single indirection
++ only bpind will be used.
++*/
++
+ typedef struct
+ {
+ uint32 bnum;
+@@ -313,15 +387,14 @@
+ uint32 bptind;
+ } blockwalker;
+
++
++/* Filesystem structure that support groups */
+ #if BLOCKSIZE == 1024
+ typedef struct
+ {
+ block zero; // The famous block 0
+ superblock sb; // The superblock
+- groupdescriptor gd; // The group desciptor
+- block bbm; // The block bitmap
+- block ibm; // The inode bitmap
+- inode itab[0]; // The inode table
++ groupdescriptor gd[0]; // The group descriptors
+ } filesystem;
+ #else
+ #error UNHANDLED BLOCKSIZE
+@@ -389,25 +462,113 @@
+ #undef udecl32
+ #undef utdecl32
+
+-char * argv0;
++static char * app_name;
++static int squash_uids = 0;
++static int squash_perms = 0;
++static const char *const memory_exhausted = "memory exhausted";
+
+ // error (un)handling
+-inline void errexit(const char *fmt, ...)
++static void verror_msg(const char *s, va_list p)
+ {
+- va_list ap;
+- fprintf(stderr, "%s: ", argv0);
+- va_start(ap, fmt);
+- vfprintf(stderr, fmt, ap);
+- va_end(ap);
+- fprintf(stderr, "\n");
+- exit(1);
++ fflush(stdout);
++ fprintf(stderr, "%s: ", app_name);
++ vfprintf(stderr, s, p);
++}
++static void error_msg(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ verror_msg(s, p);
++ va_end(p);
++ putc('\n', stderr);
++}
++
++static void error_msg_and_die(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ verror_msg(s, p);
++ va_end(p);
++ putc('\n', stderr);
++ exit(EXIT_FAILURE);
++}
++
++static void vperror_msg(const char *s, va_list p)
++{
++ int err = errno;
++ if (s == 0)
++ s = "";
++ verror_msg(s, p);
++ if (*s)
++ s = ": ";
++ fprintf(stderr, "%s%s\n", s, strerror(err));
++}
++
++#if 0
++static void perror_msg(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++}
++#endif
++static void perror_msg_and_die(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++ exit(EXIT_FAILURE);
+ }
+
+-inline void pexit(const char * fname)
++static FILE *xfopen(const char *path, const char *mode)
+ {
+- fprintf(stderr, "%s: ", argv0);
+- perror(fname);
+- exit(1);
++ FILE *fp;
++ if ((fp = fopen(path, mode)) == NULL)
++ perror_msg_and_die("%s", path);
++ return fp;
++}
++
++static char *xstrdup(const char *s)
++{
++ char *t;
++
++ if (s == NULL)
++ return NULL;
++ t = strdup(s);
++ if (t == NULL)
++ error_msg_and_die(memory_exhausted);
++ return t;
++}
++
++extern void *xrealloc(void *ptr, size_t size)
++{
++ ptr = realloc(ptr, size);
++ if (ptr == NULL && size != 0)
++ error_msg_and_die(memory_exhausted);
++ return ptr;
++}
++
++static char *xreadlink(const char *path)
++{
++ static const int GROWBY = 80; /* how large we will grow strings by */
++
++ char *buf = NULL;
++ int bufsize = 0, readsize = 0;
++
++ do {
++ buf = xrealloc(buf, bufsize += GROWBY);
++ readsize = readlink(path, buf, bufsize); /* 1st try */
++ if (readsize == -1) {
++ perror_msg_and_die("%s:%s", app_name, path);
++ }
++ }
++ while (bufsize < readsize + 1);
++
++ buf[readsize] = '\0';
++
++ return buf;
+ }
+
+ // printf helper macro
+@@ -423,7 +584,7 @@
+ {
+ }
+
+-// rounds a quantity up to a blocksize
++/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
+ uint32 rndup(uint32 qty, uint32 siz)
+ {
+ return (qty + (siz - 1)) & ~(siz - 1);
+@@ -444,7 +605,13 @@
+ // return a given inode from a filesystem
+ inline inode * get_nod(filesystem *fs, uint32 nod)
+ {
+- return &fs->itab[nod-1];
++ int grp,offset;
++ inode *itab;
++
++ offset = GRP_IBM_OFFSET(fs,nod);
++ grp = GRP_GROUP_OF_INODE(fs,nod);
++ itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
++ return itab+offset-1;
+ }
+
+ // allocate a given block/inode in the bitmap
+@@ -479,29 +646,57 @@
+ }
+
+ // allocate a block
+-uint32 alloc_blk(filesystem *fs)
++uint32 alloc_blk(filesystem *fs, uint32 nod)
+ {
+- uint32 bk;
+- if(!(bk = allocate(fs->bbm, 0)))
+- errexit("couldn't allocate a block (no free space)");
+- if(!(fs->gd.bg_free_blocks_count--))
+- errexit("group descr. free blocks count == 0 (corrupted fs?)");
++ uint32 bk=0;
++ uint32 grp,nbgroups;
++
++ grp = nod/fs->sb.s_inodes_per_group;
++ nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
++ fs->sb.s_blocks_per_group;
++ if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
++ for(grp=0;grp<nbgroups && !bk;grp++)
++ bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
++ grp--;
++ }
++ if (!bk)
++ error_msg_and_die("couldn't allocate a block (no free space)");
++ if(!(fs->gd[grp].bg_free_blocks_count--))
++ error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
+ if(!(fs->sb.s_free_blocks_count--))
+- errexit("superblock free blocks count == 0 (corrupted fs?)");
+- return bk;
++ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++ return fs->sb.s_blocks_per_group*grp + bk;
+ }
+
+ // allocate an inode
+ uint32 alloc_nod(filesystem *fs)
+ {
+- uint32 nod;
+- if(!(nod = allocate(fs->ibm, 0)))
+- errexit("couldn't allocate an inode (no free inode)");
+- if(!(fs->gd.bg_free_inodes_count--))
+- errexit("group descr. free blocks count == 0 (corrupted fs?)");
++ uint32 nod=0,best_group=0;
++ uint32 grp,nbgroups,avefreei;
++
++ nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
++ fs->sb.s_blocks_per_group;
++
++ /* Distribute inodes amongst all the blocks */
++ /* For every block group with more than average number of free inodes */
++ /* find the one with the most free blocks and allocate node there */
++ /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
++ /* We do it for all inodes. */
++ avefreei = fs->sb.s_free_inodes_count / nbgroups;
++ for(grp=0;grp<nbgroups && !nod;grp++) {
++ if (fs->gd[grp].bg_free_inodes_count < avefreei)
++ continue;
++ if (!best_group ||
++ fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
++ best_group = grp;
++ }
++ if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
++ error_msg_and_die("couldn't allocate an inode (no free inode)");
++ if(!(fs->gd[best_group].bg_free_inodes_count--))
++ error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
+ if(!(fs->sb.s_free_inodes_count--))
+- errexit("superblock free blocks count == 0 (corrupted fs?)");
+- return nod;
++ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++ return fs->sb.s_inodes_per_group*best_group+nod;
+ }
+
+ // print a bitmap allocation
+@@ -546,14 +741,14 @@
+ {
+ bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // direct block
+ else if(bw->bpdir < EXT2_NDIR_BLOCKS)
+ {
+ bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in indirect block
+ else if(bw->bpdir == EXT2_NDIR_BLOCKS)
+@@ -562,11 +757,11 @@
+ bw->bpdir = EXT2_IND_BLOCK;
+ bw->bpind = 0;
+ if(extend) // allocate indirect block
+- get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // block in indirect block
+ else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -575,7 +770,7 @@
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in first indirect block in first double indirect block
+ else if(bw->bpdir == EXT2_IND_BLOCK)
+@@ -585,14 +780,14 @@
+ bw->bpind = 0;
+ bw->bpdind = 0;
+ if(extend) // allocate double indirect block
+- get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate first indirect block
+- b[bw->bpind] = alloc_blk(fs);
++ b[bw->bpind] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
+@@ -602,7 +797,7 @@
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -612,20 +807,100 @@
+ bw->bpind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate indirect block
+- b[bw->bpind] = alloc_blk(fs);
++ b[bw->bpind] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++
++ /* Adding support for triple indirection */
++ /* Just starting triple indirection. Allocate the indirection
++ blocks and the first data block
++ */
++ else if (bw->bpdir == EXT2_DIND_BLOCK)
++ {
++ bw->bnum += 3;
++ bw->bpdir = EXT2_TIND_BLOCK;
++ bw->bpind = 0;
++ bw->bpdind = 0;
++ bw->bptind = 0;
++ if(extend) // allocate triple indirect block
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ if(extend) // allocate first double indirect block
++ b[bw->bpind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if(extend) // allocate first indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Still processing a single indirect block down the indirection
++ chain.Allocate a data block for it
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bptind < BLOCKSIZE/4 -1) )
++ {
++ bw->bptind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Finished processing a single indirect block. But still in the
++ same double indirect block. Allocate new single indirect block
++ for it and a data block
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bpdind < BLOCKSIZE/4 -1) )
++ {
++ bw->bnum++;
++ bw->bptind = 0;
++ bw->bpdind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if (extend) // allocate single indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Finished processing a double indirect block. Allocate the next
++ double indirect block and the single,data blocks for it
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bpind < BLOCKSIZE/4 - 1) )
++ {
++ bw->bnum += 2;
++ bw->bpdind = 0;
++ bw->bptind = 0;
++ bw->bpind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ if(extend) // allocate double indirect block
++ b[bw->bpind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if(extend) // allocate single indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+- // I don't do triple indirect - it's such a small filesystem ...
+ else
+- errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod);
++ error_msg_and_die("file too big !");
++ /* End change for walking triple indirection */
++
+ if(*bkref)
+ {
+ bw->bnum++;
+- if(!allocated(fs->bbm, *bkref))
+- errexit("[block %d of inode %d is unallocated !]", *bkref, nod);
++ if(!allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
++ error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
+ }
+ if(extend)
+ get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
+@@ -663,23 +938,40 @@
+ }
+
+ // link an entry (inode #) to a directory
+-void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
++void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name, uint32 mode, uid_t uid, gid_t gid, time_t ctime)
+ {
+ blockwalker bw;
+ uint32 bk;
+ uint8 *b;
+ directory *d;
+ int reclen, nlen;
+- if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR)
+- errexit("can't add '%s' to a non-directory", name);
++ inode *node;
++ inode *pnode;
++
++ /* Squash all permissions so files are owned by root
++ * and file permissions have group/other perms removed */
++ if (squash_uids) {
++ uid = gid = 0;
++ }
++ if (squash_perms) {
++ if (!S_ISLNK(mode)) {
++ mode &= ~(S_IWGRP | S_IWOTH);
++ mode &= ~(S_ISUID | S_ISGID);
++ }
++ }
++
++ pnode = get_nod(fs, dnod);
++
++ if(!S_ISDIR(pnode->i_mode))
++ error_msg_and_die("can't add '%s' to a non-directory", name);
+ if(!*name)
+- errexit("bad name '%s' (not meaningful)", name);
++ error_msg_and_die("bad name '%s' (not meaningful)", name);
+ if(strchr(name, '/'))
+- errexit("bad name '%s' (contains a slash)", name);
++ error_msg_and_die("bad name '%s' (contains a slash)", name);
+ nlen = strlen(name);
+ reclen = sizeof(directory) + rndup(nlen, 4);
+ if(reclen > BLOCKSIZE)
+- errexit("bad name '%s' (too long)", name);
++ error_msg_and_die("bad name '%s' (too long)", name);
+ init_bw(fs, dnod, &bw);
+ while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
+ {
+@@ -691,9 +983,16 @@
+ if((!d->d_inode) && (d->d_rec_len >= reclen))
+ {
+ d->d_inode = nod;
+- get_nod(fs, nod)->i_links_count++;
++ node = get_nod(fs, nod);
++ node->i_links_count++;
+ d->d_name_len = nlen;
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
++ node->i_mode = mode;
++ node->i_uid = uid;
++ node->i_gid = gid;
++ node->i_atime = ctime;
++ node->i_ctime = ctime;
++ node->i_mtime = ctime;
+ return;
+ }
+ // if entry with enough room (last one?), shrink it & use it
+@@ -705,9 +1004,16 @@
+ d = (directory*) (((int8*)d) + d->d_rec_len);
+ d->d_rec_len = reclen;
+ d->d_inode = nod;
+- get_nod(fs, nod)->i_links_count++;
++ node = get_nod(fs, nod);
++ node->i_links_count++;
+ d->d_name_len = nlen;
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
++ node->i_mode = mode;
++ node->i_uid = uid;
++ node->i_gid = gid;
++ node->i_atime = ctime;
++ node->i_ctime = ctime;
++ node->i_mtime = ctime;
+ return;
+ }
+ }
+@@ -716,10 +1022,17 @@
+ b = get_workblk();
+ d = (directory*)b;
+ d->d_inode = nod;
+- get_nod(fs, nod)->i_links_count++;
++ node = get_nod(fs, nod);
++ node->i_links_count++;
+ d->d_rec_len = BLOCKSIZE;
+ d->d_name_len = nlen;
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
++ node->i_mode = mode;
++ node->i_uid = uid;
++ node->i_gid = gid;
++ node->i_atime = ctime;
++ node->i_ctime = ctime;
++ node->i_mtime = ctime;
+ extend_blk(fs, dnod, b, 1);
+ get_nod(fs, dnod)->i_size += BLOCKSIZE;
+ free_workblk(b);
+@@ -747,7 +1060,7 @@
+ // find the inode of a full path
+ uint32 find_path(filesystem *fs, uint32 nod, const char * name)
+ {
+- char *p, *n, *n2 = strdup(name);
++ char *p, *n, *n2 = xstrdup(name);
+ n = n2;
+ while(*n == '/')
+ {
+@@ -770,27 +1083,32 @@
+ }
+
+ // make a full-fledged directory (i.e. with "." & "..")
+-uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode)
++uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
++ uid_t uid, gid_t gid, time_t ctime)
+ {
+ uint32 nod;
+ if((nod = find_dir(fs, parent_nod, name)))
+ return nod;
+ nod = alloc_nod(fs);
+- get_nod(fs, nod)->i_mode = FM_IFDIR | mode;
+- add2dir(fs, parent_nod, nod, name);
+- add2dir(fs, nod, nod, ".");
+- add2dir(fs, nod, parent_nod, "..");
+- fs->gd.bg_used_dirs_count++;
++ if (!(mode & FM_IFDIR))
++ mode |= FM_IFDIR;
++ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
++ add2dir(fs, nod, nod, ".", mode, uid, gid, ctime);
++ add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime);
++ fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
+ return nod;
+ }
+
+ // make a symlink
+-uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b)
++uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size,
++ uint8 * b, uid_t uid, gid_t gid, time_t ctime)
+ {
++ uint32 mode;
+ uint32 nod = alloc_nod(fs);
++ mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ get_nod(fs, nod)->i_size = size;
+- add2dir(fs, parent_nod, nod, name);
++ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
+ if(size <= 4 * (EXT2_TIND_BLOCK+1))
+ {
+ strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
+@@ -801,15 +1119,15 @@
+ }
+
+ // make a file from a FILE*
+-uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f)
++uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, time_t ctime)
+ {
+ uint8 * b;
+ uint32 nod = alloc_nod(fs);
+- get_nod(fs, nod)->i_mode = FM_IFREG | mode;
++ mode |= FM_IFREG;
+ get_nod(fs, nod)->i_size = size;
+- add2dir(fs, parent_nod, nod, name);
++ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
+ if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE))))
+- errexit("not enough mem to read file '%s'", name);
++ error_msg_and_die("not enough mem to read file '%s'", name);
+ memset(b, 0,rndup(size, BLOCKSIZE));
+ if(f)
+ fread(b, size, 1, f);
+@@ -824,6 +1142,15 @@
+ uint32 get_mode(struct stat *st)
+ {
+ uint32 mode = 0;
++
++ /* Squash file permissions as needed */
++ if (squash_perms) {
++ if (!S_ISLNK(mode)) {
++ st->st_mode &= ~(S_IWGRP | S_IWOTH);
++ st->st_mode &= ~(S_ISUID | S_ISGID);
++ }
++ }
++
+ if(st->st_mode & S_IRUSR)
+ mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
+ if(st->st_mode & S_IWUSR)
+@@ -833,30 +1160,17 @@
+ return mode;
+ }
+
+-// retrieves a mode info from a string
+-uint32 get_modestr(const char *p)
+-{
+- uint32 mode = 0;
+- if(p[0] == 'r')
+- mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
+- if(p[1] == 'w')
+- mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH;
+- if(p[2] == 'x' || p[2] == 's')
+- mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
+- return mode;
+-}
+-
+ // basename of a path - free me
+ char * basename(const char * fullpath)
+ {
+ char * p = strrchr(fullpath, '/');
+- return strdup(p ? p + 1 : fullpath);
++ return xstrdup(p ? p + 1 : fullpath);
+ }
+
+ // dirname of a path - free me
+ char * dirname(const char * fullpath)
+ {
+- char * p, * n = strdup(fullpath);
++ char * p, * n = xstrdup(fullpath);
+ if((p = strrchr(n, '/')))
+ *(p+1) = 0;
+ else
+@@ -864,66 +1178,6 @@
+ return n;
+ }
+
+-// adds entries to the filesystem from a text file
+-void add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh)
+-{
+- uint32 mode;
+- uint32 nod, nod2;
+- char cmod[11], *path, *name, *dir;
+- int major, minor;
+- while(fscanf(fh, "%10s", cmod))
+- {
+- if(feof(fh))
+- break;
+- mode = get_modestr(cmod + 1);
+- switch(*cmod)
+- {
+- case 'd':
+- fscanf(fh, "%" SCANF_PREFIX "s\n", SCANF_STRING(path));
+- break;
+- case 'c':
+- mode |= FM_IFCHR;
+- fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
+- break;
+- case 'b':
+- mode |= FM_IFBLK;
+- fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
+- break;
+- case '#':
+- while(fgetc(fh) != '\n');
+- continue;
+- default:
+- errexit("malformed text input file");
+- }
+- name = basename(path);
+- dir = dirname(path);
+- free(path);
+- if(!(nod = find_path(fs, this_nod, dir)))
+- errexit("can't find directory '%s' to create '%s''", dir, name);
+- free(dir);
+- if((!strcmp(name, ".")) || (!strcmp(name, "..")))
+- {
+- free(name);
+- continue;
+- }
+- switch(*cmod)
+- {
+- case 'd':
+- mkdir_fs(fs, nod, name, mode);
+- break;
+- case 'c':
+- case 'b':
+- nod2 = alloc_nod(fs);
+- get_nod(fs, nod2)->i_mode = mode;
+- ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor;
+- ((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
+- add2dir(fs, nod, nod2, name);
+- break;
+- }
+- free(name);
+- }
+-}
+-
+ // adds a tree of entries to the filesystem from current dir
+ void add2fs_from_dir(filesystem *fs, uint32 this_nod)
+ {
+@@ -934,7 +1188,7 @@
+ struct stat st;
+ uint8 *b;
+ if(!(dh = opendir(".")))
+- pexit(".");
++ perror_msg_and_die(".");
+ while((dent = readdir(dh)))
+ {
+ if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+@@ -948,31 +1202,27 @@
+ get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st);
+ ((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff);
+ ((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8);
+- add2dir(fs, this_nod, nod, dent->d_name);
++ add2dir(fs, this_nod, nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
+ break;
+ case S_IFLNK:
+- if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE))))
+- errexit("out of memory");
+- if(readlink(dent->d_name, (char*)b, st.st_size) < 0)
+- pexit(dent->d_name);
+- mklink_fs(fs, this_nod, dent->d_name, st.st_size, b);
++ b = xreadlink(dent->d_name);
++ mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime);
+ free(b);
+ break;
+ case S_IFREG:
+- if(!(fh = fopen(dent->d_name, "r")))
+- pexit(dent->d_name);
+- mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh);
++ fh = xfopen(dent->d_name, "r");
++ mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime);
+ fclose(fh);
+ break;
+ case S_IFDIR:
+- nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st));
++ nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
+ if(chdir(dent->d_name) < 0)
+- pexit(dent->d_name);
++ perror_msg_and_die(dent->d_name);
+ add2fs_from_dir(fs, nod);
+ chdir("..");
+ break;
+ default:
+- fprintf(stderr, "ignoring entry %s", dent->d_name);
++ error_msg("ignoring entry %s", dent->d_name);
+ }
+ }
+ closedir(dh);
+@@ -981,9 +1231,11 @@
+ // endianness swap of x-indirect blocks
+ void swap_goodblocks(filesystem *fs, inode *nod)
+ {
+- int i;
++ int i,j,done=0;
++ uint32 *b,*b2;
++
+ int nblk = nod->i_blocks / INOBLK;
+- if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
++ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ nod->i_block[i] = swab32(nod->i_block[i]);
+ if(nblk <= EXT2_IND_BLOCK)
+@@ -991,20 +1243,55 @@
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
+ return;
++ /* Currently this will fail b'cos the number of blocks as stored
++ in i_blocks also includes the indirection blocks (see
++ walk_bw). But this function assumes that i_blocks only
++ stores the count of data blocks ( Actually according to
++ "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
++ i_blocks IS supposed to store the count of data blocks). so
++ with a file of size 268K nblk would be 269.The above check
++ will be false even though double indirection hasn't been
++ started.This is benign as 0 means block 0 which has been
++ zeroed out and therefore points back to itself from any offset
++ */
++ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ for(i = 0; i < BLOCKSIZE/4; i++)
++ /* Should this be...
++ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
++ */
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+- errexit("too big file on the filesystem");
++ /* Adding support for triple indirection */
++ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++ b2 = (uint32*)get_blk(fs,b[i]);
++ for(j=0; j<BLOCKSIZE/4;j++) {
++ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
++ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ j*(BLOCKSIZE/4)) )
++ swap_block(get_blk(fs,b2[j]));
++ else {
++ done = 1;
++ break;
++ }
++ }
++ swap_block((uint8 *)b2);
++ }
++ swap_block((uint8 *)b);
++ return;
+ }
+
+ void swap_badblocks(filesystem *fs, inode *nod)
+ {
+- int i;
++ int i,j,done=0;
++ uint32 *b,*b2;
++
+ int nblk = nod->i_blocks / INOBLK;
+- if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
++ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ nod->i_block[i] = swab32(nod->i_block[i]);
+ if(nblk <= EXT2_IND_BLOCK)
+@@ -1012,13 +1299,34 @@
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
+ return;
++ /* See comment in swap_goodblocks */
++ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ for(i = 0; i < BLOCKSIZE/4; i++)
++ /* See comment in swap_goodblocks */
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+- errexit("too big file on the filesystem");
++ /* Adding support for triple indirection */
++ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++ swap_block((uint8 *)b);
++ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++ b2 = (uint32*)get_blk(fs,b[i]);
++ swap_block((uint8 *)b2);
++ for(j=0; j<BLOCKSIZE/4;j++) {
++ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
++ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ j*(BLOCKSIZE/4)) )
++ swap_block(get_blk(fs,b2[j]));
++ else {
++ done = 1;
++ break;
++ }
++ }
++ }
++ return;
+ }
+
+ // endianness swap of the whole filesystem
+@@ -1045,7 +1353,8 @@
+ swap_goodblocks(fs, nod);
+ swap_nod(nod);
+ }
+- swap_gd(&fs->gd);
++ for(i=0;i<GRP_NBGROUPS(fs);i++)
++ swap_gd(&(fs->gd[i]));
+ swap_sb(&fs->sb);
+ }
+
+@@ -1053,7 +1362,8 @@
+ {
+ int i;
+ swap_sb(&fs->sb);
+- swap_gd(&fs->gd);
++ for(i=0;i<GRP_NBGROUPS(fs);i++)
++ swap_gd(&(fs->gd[i]));
+ for(i = 1; i < fs->sb.s_inodes_count; i++)
+ {
+ inode *nod = get_nod(fs, i);
+@@ -1084,53 +1394,118 @@
+ directory *d;
+ uint8 * b;
+ uint32 nod;
++ uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
++ free_blocks_per_group,nbblocks_per_group;
++ uint32 gd,itbl,ibmpos,bbmpos,itblpos;
++ int j;
++ uint8 *bbm,*ibm;
++ inode *itab0;
+
+ if(nbblocks < 16) // totally arbitrary
+- errexit("too small filesystem");
+- if(nbblocks >BLOCKS_PER_GROUP) // I build only one group
+- errexit("too big filesystem");
++ error_msg_and_die("too small filesystem");
++
++ /* nbblocks is the total number of blocks in the system. First
++ * calculate how much overhead blocks - inode table blocks,bitmap
++ * blocks,group descriptor blocks etc. - are needed assuming each
++ * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with
++ * this figure. Each group has the same number of blocks. So the fs
++ * has a size atleast the given value but usually rounded off to a i
++ * higher number.
++ */
++ nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP;
++ nbinodes_per_group = nbinodes/nbgroups +1;
++ nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode));
++ if (nbinodes_per_group < 16)
++ nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
++ overhead_per_group = 3 /*super block,ibm,bbm*/
++ + /* No. of blocks that the inodes occupy */
++ nbinodes_per_group *sizeof(inode)/BLOCKSIZE
++ + /* No. of blocks that group descriptors occupy */
++ rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++ free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */;
++ free_blocks_per_group = free_blocks/nbgroups;
++ if (free_blocks > free_blocks_per_group * nbgroups)
++ free_blocks_per_group++;
++ nbblocks_per_group = free_blocks_per_group + overhead_per_group;
++ /* e2fsck complains if nbblocks_per_group is not a multiple of 8 */
++ nbblocks_per_group = rndup(nbblocks_per_group,8);
++ free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++ if (nbblocks_per_group > BLOCKS_PER_GROUP) {
++ /* Can this happen ? */
++ nbblocks_per_group = BLOCKS_PER_GROUP;
++ free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++ }
++ nbblocks = nbblocks_per_group * nbgroups + 1;
++
++
+ if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+- errexit("not enough memory for filesystem");
++ error_msg_and_die("not enough memory for filesystem");
+
+ // create the superblock for an empty filesystem
+- fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode));
++ fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
+ fs->sb.s_blocks_count = nbblocks;
+ fs->sb.s_r_blocks_count = nbresrvd;
+- fs->sb.s_free_blocks_count = nbblocks;
++ fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups;
+ fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
+ fs->sb.s_first_data_block = (BLOCKSIZE == 1024);
+ fs->sb.s_log_block_size = BLOCKSIZE >> 11;
+ fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
+- fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP;
+- fs->sb.s_frags_per_group = BLOCKS_PER_GROUP;
+- fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
++ fs->sb.s_blocks_per_group = nbblocks_per_group;
++ fs->sb.s_frags_per_group = nbblocks_per_group;
++ fs->sb.s_inodes_per_group = nbinodes_per_group;
+ fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+
+ // set up groupdescriptors
+- fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE;
+- fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count;
+- fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count;
+- fs->gd.bg_used_dirs_count = 1;
+- fs->gd.bg_block_bitmap = 3;
+- fs->gd.bg_inode_bitmap = 4;
+- fs->gd.bg_inode_table = 5;
+-
+- // mark non-filesystem blocks and inodes as allocated
+- for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++)
+- allocate(fs->bbm, i);
+- for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++)
+- allocate(fs->ibm, i);
+-
+- // mark system blocsk and inodes as allocated
+- for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++)
+- allocate(fs->bbm, i);
+- for(i = 1; i < EXT2_FIRST_INO; i++)
+- allocate(fs->ibm, i);
+-
+- // make root inode and directory
+- fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+- fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
+- fs->itab[EXT2_ROOT_INO-1].i_links_count = 2;
++ gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++ itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE;
++ for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
++ i<nbgroups;
++ i++, bbmpos += nbblocks_per_group,ibmpos += nbblocks_per_group,
++ itblpos += nbblocks_per_group) {
++
++ fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
++ fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
++ fs->gd[i].bg_used_dirs_count = 0;
++ fs->gd[i].bg_block_bitmap = bbmpos;
++ fs->gd[i].bg_inode_bitmap = ibmpos;
++ fs->gd[i].bg_inode_table = itblpos;
++ }
++
++ /* Mark non-filesystem blocks and inodes as allocated */
++ /* Mark system blocks and inodes as allocated */
++ for(i = 0; i<nbgroups;i++) {
++
++ /* Block bitmap */
++ bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
++ //non-filesystem blocks.
++ for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++)
++ allocate(bbm, j);
++ //system blocks
++ for(j = 1; j <= 3+gd+itbl; j++)
++ allocate(bbm, j);
++
++ /* Inode bitmap */
++ ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
++ //non-filesystem inodes
++ for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
++ allocate(ibm, j);
++ }
++
++ /* We have groups now. Add the root filesystem in group 0 */
++ /* Also allocate the system inodes in group 0 and update */
++ /* directory count and inode count for group 0 */
++
++ ibm = get_blk(fs,fs->gd[0].bg_inode_bitmap);
++ for(j = 1; j < EXT2_FIRST_INO; j++) {
++ allocate(ibm, j);
++ fs->gd[0].bg_free_inodes_count--;
++ }
++ fs->gd[0].bg_used_dirs_count = 1;
++ itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
++ itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
++ itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
++ itab0[EXT2_ROOT_INO-1].i_links_count = 2;
++
+ b = get_workblk();
+ d = (directory*)b;
+ d->d_inode = EXT2_ROOT_INO;
+@@ -1147,9 +1522,14 @@
+ // make lost+found directory and reserve blocks
+ if(fs->sb.s_r_blocks_count)
+ {
+- nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU | FM_IRWXG | FM_IRWXO);
++ nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL));
+ memset(b, 0, BLOCKSIZE);
+ ((directory*)b)->d_rec_len = BLOCKSIZE;
++ /* We run into problems with e2fsck if directory lost+found grows
++ * bigger than this. Need to find out why this happens - sundar
++ */
++ if (fs->sb.s_r_blocks_count > 2049 )
++ fs->sb.s_r_blocks_count=2049;
+ for(i = 1; i < fs->sb.s_r_blocks_count; i++)
+ extend_blk(fs, nod, b, 1);
+ get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
+@@ -1170,24 +1550,24 @@
+ // loads a filesystem from disk
+ filesystem * load_fs(FILE * fh, int swapit)
+ {
+- size_t fssize;
++ size_t fssize = 0;
+ filesystem *fs;
+ if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0))
+- pexit("input filesystem image");
++ perror_msg_and_die("input filesystem image");
+ rewind(fh);
+ fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
+ if(fssize < 16) // totally arbitrary
+- errexit("too small filesystem");
+- if(fssize > BLOCKS_PER_GROUP) // I build only one group
+- errexit("too big filesystem");
++ error_msg_and_die("too small filesystem");
++/* if(fssize > BLOCKS_PER_GROUP) // I build only one group
++ error_msg_and_die("too big filesystem"); */
+ if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
+- errexit("not enough memory for filesystem");
++ error_msg_and_die("not enough memory for filesystem");
+ if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
+- pexit("input filesystem image");
++ perror_msg_and_die("input filesystem image");
+ if(swapit)
+ swap_badfs(fs);
+ if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
+- errexit("not a suitable ext2 filesystem");
++ error_msg_and_die("not a suitable ext2 filesystem");
+ return fs;
+ }
+
+@@ -1230,9 +1610,9 @@
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ {
+ if(fsize <= 0)
+- errexit("wrong size while saving inode %d", nod);
++ error_msg_and_die("wrong size while saving inode %d", nod);
+ if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
+- errexit("error while saving inode %d", nod);
++ error_msg_and_die("error while saving inode %d", nod);
+ fsize -= BLOCKSIZE;
+ }
+ }
+@@ -1250,7 +1630,7 @@
+ {
+ int i, j;
+ if(fsize <= 0)
+- errexit("wrong size while saving inode %d", nod);
++ error_msg_and_die("wrong size while saving inode %d", nod);
+ b = get_blk(fs, bk);
+ for(i = 0; i < 64; i++)
+ {
+@@ -1406,7 +1786,7 @@
+ s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
+ }
+ printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
+- if(!allocated(fs->ibm, nod))
++ if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
+ {
+ printf("unallocated\n");
+ return;
+@@ -1440,24 +1820,46 @@
+ default:
+ list_blocks(fs, nod);
+ }
++ printf("Done with inode %d\n",nod);
+ }
+
+ // describes various fields in a filesystem
+ void print_fs(filesystem *fs)
+ {
+- int i;
+- printf("%d blocks (%d free, %d reserved), first data block: %d\n", fs->sb.s_blocks_count, fs->sb.s_free_blocks_count, fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
+- printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count);
+- printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
+- printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group);
+- printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table);
+- printf("block bitmap allocation:\n");
+- print_bm(fs->bbm, fs->sb.s_blocks_count);
+- printf("inode bitmap allocation:\n");
+- print_bm(fs->ibm, fs->sb.s_inodes_count);
+- for(i=1; i<=fs->sb.s_inodes_count; i++)
+- if(allocated(fs->ibm, i))
+- print_inode(fs, i);
++ int i,j;
++ uint8 *ibm;
++
++ printf("%d blocks (%d free, %d reserved), first data block: %d\n",
++ fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
++ fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
++ printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
++ fs->sb.s_free_inodes_count);
++ printf("block size = %d, frag size = %d\n",
++ fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
++ fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
++ printf("Number of groups: %d\n",GRP_NBGROUPS(fs));
++ printf("%d blocks per group,%d frags per group,%d inodes per group\n",
++ fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
++ fs->sb.s_inodes_per_group);
++ printf("Size of inode table: %d blocks\n",
++ fs->sb.s_inodes_per_group * sizeof(inode)/BLOCKSIZE);
++ for (i = 0; i < GRP_NBGROUPS(fs); i++) {
++ printf("Group No: %d\n", i);
++ printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
++ fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
++ fs->gd[i].bg_inode_table);
++ printf("Free blocks count: %d\n",fs->gd[i].bg_free_blocks_count);
++ printf("Free inodes count: %d\n",fs->gd[i].bg_free_inodes_count);
++ printf("Used dir count: %d\n",fs->gd[i].bg_used_dirs_count);
++ printf("block bitmap allocation:\n");
++ print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
++ printf("inode bitmap allocation:\n");
++ ibm = GRP_GET_GROUP_IBM(fs, i);
++ print_bm(ibm, fs->sb.s_inodes_per_group);
++ for (j = 1; j <= fs->sb.s_inodes_per_group; j++)
++ if (allocated(ibm, j))
++ print_inode(fs, i*fs->sb.s_inodes_per_group + j);
++ }
+ }
+
+ void dump_fs(filesystem *fs, FILE * fh, int swapit)
+@@ -1467,31 +1869,234 @@
+ if(swapit)
+ swap_goodfs(fs);
+ if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
+- pexit("output filesystem image");
++ perror_msg_and_die("output filesystem image");
+ if(swapit)
+ swap_badfs(fs);
+ }
+
++/* device table entries take the form of:
++ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++ /dev/mem c 640 0 0 1 1 0 0 -
++
++ type can be one of:
++ f A regular file
++ d Directory
++ c Character special device file
++ b Block special device file
++ p Fifo (named pipe)
++
++ I don't bother with symlinks (permissions are irrelevant), hard
++ links (special cases of regular files), or sockets (why bother).
++
++ Regular files must exist in the target root directory. If a char,
++ block, fifo, or directory does not exist, it will be created.
++*/
++static int interpret_table_entry(filesystem *fs, char *line)
++{
++ char type, *name = NULL, *tmp, *dir, *bname;
++ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++ unsigned long start = 0, increment = 1, count = 0;
++ inode *entry;
++ uint32 nod, parent;
++
++ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
++ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
++ &start, &increment, &count) < 0)
++ {
++ return 1;
++ }
++
++ if (!strcmp(name, "/")) {
++ error_msg_and_die("Device table entries require absolute paths");
++ }
++
++ /* Check if this file already exists... */
++ switch (type) {
++ case 'd':
++ mode |= S_IFDIR;
++ break;
++ case 'f':
++ mode |= S_IFREG;
++ break;
++ case 'p':
++ mode |= S_IFIFO;
++ break;
++ case 'c':
++ mode |= S_IFCHR;
++ break;
++ case 'b':
++ mode |= S_IFBLK;
++ break;
++ default:
++ error_msg_and_die("Unsupported file type");
++ }
++ nod = 0;
++ if (count==0)
++ nod = find_path(fs, EXT2_ROOT_INO, name);
++ if (nod) {
++ /* Ok, we just need to fixup an existing entry
++ * and we will be all done... */
++ entry = get_nod(fs, nod);
++ entry->i_uid = uid;
++ entry->i_gid = gid;
++ entry->i_mode = mode;
++ if (major) {
++ dev_t rdev = makedev(major, minor);
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ }
++ } else {
++ /* Try and find our parent now */
++ tmp = xstrdup(name);
++ dir = dirname(tmp);
++ parent = find_path(fs, EXT2_ROOT_INO, dir);
++ free(tmp);
++ if (!parent) {
++ error_msg ("skipping device_table entry '%s': no parent directory!", name);
++ free(name);
++ return 1;
++ }
++
++ tmp = xstrdup(name);
++ bname = xstrdup(basename(tmp));
++ free(tmp);
++ switch (type) {
++ case 'd':
++ mkdir_fs(fs, parent, bname, mode|FM_IFDIR, uid, gid, time(NULL));
++ break;
++ case 'f':
++#if 0
++ {
++ // This is a bit odd.. This will try to include
++ // the file of the same name from your _build_
++ // system... Probably a very bad idea....
++ struct stat st;
++ FILE *fh = xfopen(name, "r");
++ lstat(name, &st);
++ mkfile_fs(fs, parent, bname, mode|FM_IFREG, st.st_size, fh, uid, gid, st.st_ctime);
++ fclose(fh);
++ }
++#else
++ error_msg("ignoring entry %s", name);
++#endif
++ break;
++ case 'p':
++ error_msg("ignoring entry %s", name);
++ break;
++ case 'c':
++ case 'b':
++ if (count > 0) {
++ dev_t rdev;
++ char *dname;
++ unsigned long i;
++ for (i = start; i < count; i++) {
++ asprintf(&dname, "%s%lu", bname, i);
++ nod = find_path(fs, EXT2_ROOT_INO, dname);
++ if (nod) {
++ /* We just need to fixup an existing entry */
++ entry = get_nod(fs, nod);
++ } else {
++ nod = alloc_nod(fs);
++ add2dir(fs, parent, nod, dname, mode, uid, gid, time(NULL));
++ entry = get_nod(fs, nod);
++ }
++ entry->i_uid = uid;
++ entry->i_gid = gid;
++ entry->i_mode = mode;
++ rdev = makedev(major, minor + (i * increment - start));
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ free(dname);
++ }
++ } else {
++ dev_t rdev = makedev(major, minor);
++ nod = alloc_nod(fs);
++ add2dir(fs, parent, nod, bname, mode, uid, gid, time(NULL));
++ entry = get_nod(fs, nod);
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ }
++ break;
++ default:
++ error_msg_and_die("Unsupported file type");
++ }
++ free(bname);
++ }
++ free(name);
++ return 0;
++}
++
++static int parse_device_table(filesystem *root, FILE * file)
++{
++ char *line;
++ int status = 0;
++ size_t length = 0;
++
++ /* Turn off squash, since we must ensure that values
++ * entered via the device table are not squashed */
++ squash_uids = 0;
++ squash_perms = 0;
++
++ /* Looks ok so far. The general plan now is to read in one
++ * line at a time, check for leading comment delimiters ('#'),
++ * then try and parse the line as a device table. If we fail
++ * to parse things, try and help the poor fool to fix their
++ * device table with a useful error msg... */
++ line = NULL;
++ while (getline(&line, &length, file) != -1) {
++ /* First trim off any whitespace */
++ int len = strlen(line);
++
++ /* trim trailing whitespace */
++ while (len > 0 && isspace(line[len - 1]))
++ line[--len] = '\0';
++ /* trim leading whitespace */
++ memmove(line, &line[strspn(line, " \n\r\t\v")], len);
++
++ /* How long are we after trimming? */
++ len = strlen(line);
++
++ /* If this is NOT a comment line, try to interpret it */
++ if (len && *line != '#') {
++ if (interpret_table_entry(root, line))
++ status = 1;
++ }
++
++ free(line);
++ line = NULL;
++ }
++ fclose(file);
++
++ return status;
++}
++
++/*
++Local Variables:
++c-file-style: "linux"
++c-basic-offset: 4
++tab-width: 4
++End:
++*/
++
+ void showhelp(void)
+ {
+ fprintf(stderr, "Usage: %s [options] image\n"
+ "Create an ext2 filesystem image from directories/files\n\n"
+- " -x image Use this image as a starting point\n"
+- " -d directory Add this directory as source\n"
+- " -f file Add nodes (e.g. devices) from this spec file\n"
+- " -b blocks Size in blocks\n"
+- " -i inodes Number of inodes\n"
+- " -r reserved Number of reserved blocks\n"
+- " -g path Generate a block map file for this path\n"
+- " -e value Fill unallocated blocks with value\n"
+- " -z Make files with holes\n"
+- " -v Print resulting filesystem structure\n"
+- " -h Show this help\n\n"
+- "Example of spec file:\n"
+- "drwx /dev\n"
+- "crw- 10,190 /dev/lcd\n"
+- "brw- 1,0 /dev/ram0\n\n"
+- "Report bugs to xavier.bestel@free.fr\n", argv0);
++ " -x image Use this image as a starting point\n"
++ " -d directory Add this directory as source\n"
++ " -b blocks Size in blocks\n"
++ " -i inodes Number of inodes\n"
++ " -r reserved Number of reserved blocks\n"
++ " -g path Generate a block map file for this path\n"
++ " -e value Fill unallocated blocks with value\n"
++ " -z Make files with holes\n"
++ " -D,-f Use the named FILE as a device table file\n"
++ " -q Squash permissions and owners making all files be owned by root\n"
++ " -U Squash owners making all files be owned by root\n"
++ " -P Squash permissions on all files\n"
++ " -v Print resulting filesystem structure\n"
++ " -h Show this help\n\n"
++ "Report bugs to xavier.bestel@free.fr\n", app_name);
+ }
+
+ #define MAX_DOPT 128
+@@ -1521,21 +2126,17 @@
+ filesystem *fs;
+ int i;
+ int c;
++ struct stat sb;
++ FILE *devtable = NULL;
+
+- argv0 = argv[0];
+- if(argc <= 1)
+- {
+- showhelp();
+- exit(1);
+- }
+- while((c = getopt(argc, argv, "x:f:d:b:i:r:g:e:zvh")) != EOF)
++ app_name = argv[0];
++ while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
+ switch(c)
+ {
+ case 'x':
+ fsin = optarg;
+ break;
+ case 'd':
+- case 'f':
+ dopt[didx++] = optarg;
+ break;
+ case 'b':
+@@ -1556,6 +2157,24 @@
+ case 'z':
+ holes = 1;
+ break;
++ case 'f':
++ case 'D':
++ devtable = xfopen(optarg, "r");
++ if (fstat(fileno(devtable), &sb) < 0)
++ perror_msg_and_die(optarg);
++ if (sb.st_size < 10)
++ error_msg_and_die("%s: not a proper device table file", optarg);
++ break;
++ case 'q':
++ squash_uids = 1;
++ squash_perms = 1;
++ break;
++ case 'U':
++ squash_uids = 1;
++ break;
++ case 'P':
++ squash_perms = 1;
++ break;
+ case 'v':
+ verbose = 1;
+ break;
+@@ -1566,16 +2185,14 @@
+ exit(1);
+ }
+ if(optind < (argc - 1))
+- errexit("too many arguments");
++ error_msg_and_die("too many arguments");
+ if(optind == (argc - 1))
+ fsout = argv[optind];
+ if(fsin)
+ {
+ if(strcmp(fsin, "-"))
+ {
+- FILE * fh = fopen(fsin, "r");
+- if(!fh)
+- pexit(fsin);
++ FILE * fh = xfopen(fsin, "r");
+ fs = load_fs(fh, bigendian);
+ fclose(fh);
+ }
+@@ -1585,7 +2202,7 @@
+ else
+ {
+ if(nbblocks == -1)
+- errexit("filesystem size unspecified");
++ error_msg_and_die("filesystem size unspecified");
+ if(nbinodes == -1)
+ nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
+ if(nbresrvd == -1)
+@@ -1595,35 +2212,30 @@
+ for(i = 0; i < didx; i++)
+ {
+ struct stat st;
+- FILE *fh;
+ char *pdir;
+ stat(dopt[i], &st);
+ switch(st.st_mode & S_IFMT)
+ {
+- case S_IFREG:
+- if(!(fh = fopen(dopt[i], "r")))
+- pexit(dopt[i]);
+- add2fs_from_file(fs, EXT2_ROOT_INO, fh);
+- fclose(fh);
+- break;
+ case S_IFDIR:
+ if(!(pdir = getcwd(0, GETCWD_SIZE)))
+- pexit(dopt[i]);
++ perror_msg_and_die(dopt[i]);
+ if(chdir(dopt[i]) < 0)
+- pexit(dopt[i]);
++ perror_msg_and_die(dopt[i]);
+ add2fs_from_dir(fs, EXT2_ROOT_INO);
+ if(chdir(pdir) < 0)
+- pexit(pdir);
++ perror_msg_and_die(pdir);
+ free(pdir);
+ break;
+ default:
+- errexit("%s in neither a file nor a directory", dopt[i]);
++ error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
+ }
+ }
+ if(emptyval)
+ for(i = 1; i < fs->sb.s_blocks_count; i++)
+- if(!allocated(fs->bbm, i))
++ if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i)))
+ memset(get_blk(fs, i), emptyval, BLOCKSIZE);
++ if(devtable)
++ parse_device_table(fs, devtable);
+ if(verbose)
+ print_fs(fs);
+ for(i = 0; i < gidx; i++)
+@@ -1633,21 +2245,18 @@
+ char *p;
+ FILE *fh;
+ if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
+- errexit("path %s not found in filesystem", gopt[i]);
++ error_msg_and_die("path %s not found in filesystem", gopt[i]);
+ while((p = strchr(gopt[i], '/')))
+ *p = '_';
+ snprintf(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
+- if(!(fh = fopen(fname, "w")))
+- pexit(fname);
++ fh = xfopen(fname, "w");
+ fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
+ flist_blocks(fs, nod, fh);
+ fclose(fh);
+ }
+ if(strcmp(fsout, "-"))
+ {
+- FILE * fh = fopen(fsout, "w");
+- if(!fh)
+- pexit(fsout);
++ FILE * fh = xfopen(fsout, "w");
+ dump_fs(fs, fh, bigendian);
+ fclose(fh);
+ }
+diff -urN genext2fs-1.3.orig/test-mount.sh genext2fs-1.3/test-mount.sh
+--- genext2fs-1.3.orig/test-mount.sh 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/test-mount.sh 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,96 @@
++#!/bin/sh
++set -e
++
++cleanup () {
++ set +e
++ umount mnt 2>/dev/null
++ rm -rf mnt ext2.img lsout fout test 2>/dev/null
++}
++
++# dtest - Uses the -d directory option of genext2fs
++# Creates an image with a file of given size and verifies it
++# Usage: dtest file-size number-of-blocks
++dtest () {
++ size=$1; blocks=$2;fname=$size
++ echo "Testing with file of size $size "
++ mkdir -p test
++ cd test
++ dd if=/dev/zero of=file.$1 bs=1 count=$size
++ cd ..
++ ./genext2fs -b $blocks -d test ext2.img
++ md5=`md5sum ext2.img | cut -f1 -d " "`
++ if ! /sbin/e2fsck -fn ext2.img ; then
++ echo "fsck failed"
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ mkdir -p mnt
++ if ! mount -t ext2 -o loop ext2.img mnt; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ if (! [ -f mnt/file.$fname ]) || \
++ [ $fname != "`ls -al mnt | grep file.$fname |awk '{print $5}'`" ] ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ echo PASSED "(md5 checksum for the image: $md5)"
++ cleanup
++}
++
++# ftest - Uses the -f spec-file option of genext2fs
++# Creates an image with the devices mentioned in the given spec
++# file and verifies it
++# Usage: ftest spec-file number-of-blocks
++ftest () {
++ fname=$1; blocks=$2;
++ echo "Testing with devices file $fname"
++ ./genext2fs -b $blocks -f $fname ext2.img
++ md5=`md5sum ext2.img | cut -f 1 -d " "`
++ if ! /sbin/e2fsck -fn ext2.img ; then
++ echo "fsck failed"
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ mkdir -p mnt
++ if ! mount -t ext2 -o loop ext2.img mnt; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ if ! [ -d mnt/dev ] ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ cat dev.txt | grep ^[bc] | \
++ awk '{print $1substr($1,2)substr($1,2),$2,$3}'| \
++ sort -d -k3.6 > fout
++ ls -al mnt/dev | grep ^[bc] | \
++ awk '{ print $1,$5$6,"/dev/"$10}' | \
++ sort -d -k3.6 > lsout
++ if ! diff fout lsout ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ echo PASSED "(md5 checksum for the image: $md5)"
++ cleanup
++}
++
++dtest 0 4096
++dtest 0 8193
++dtest 0 8194
++dtest 1 4096
++dtest 12288 4096
++dtest 274432 4096
++dtest 8388608 9000
++dtest 16777216 20000
++
++ftest dev.txt 4096
++
++exit 0
+diff -urN genext2fs-1.3.orig/test.sh genext2fs-1.3/test.sh
+--- genext2fs-1.3.orig/test.sh 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/test.sh 2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,53 @@
++#!/bin/sh
++set -e
++
++# dtest - Uses the -d directory option of genext2fs
++# Creates an image with a file of given size and verifies it
++# Usage: dtest file-size number-of-blocks correct-checksum
++dtest () {
++ size=$1; blocks=$2; checksum=$3
++ echo "Testing with file of size $size "
++ mkdir -p test
++ cd test
++ dd if=/dev/zero of=file.$1 bs=1 count=$size
++ cd ..
++ ./genext2fs -b $blocks -d test ext2.img
++ md5=`md5sum ext2.img | cut -d" " -f1`
++ rm -rf ext2.img test
++ if [ $md5 == $checksum ] ; then
++ echo PASSED
++ else
++ echo FAILED
++ exit 1
++ fi
++}
++
++# ftest - Uses the -f spec-file option of genext2fs
++# Creates an image with the devices mentioned in the given spec
++# file and verifies it
++# Usage: ftest spec-file number-of-blocks correct-checksum
++ftest () {
++ fname=$1; blocks=$2; checksum=$3
++ echo "Testing with devices file $fname"
++ ./genext2fs -b $blocks -f $fname ext2.img
++ md5=`md5sum ext2.img | cut -d" " -f1`
++ rm -rf ext2.img
++ if [ $md5 == $checksum ] ; then
++ echo PASSED
++ else
++ echo FAILED
++ exit 1
++ fi
++}
++
++dtest 0 4096 491a43ab93c2e5c186c9f1f72d88e5c5
++dtest 0 8193 6289224f0b7f151994479ba156c43505
++dtest 0 8194 3272c43c25e8d0c3768935861a643a65
++dtest 1 4096 5ee24486d33af88c63080b09d8cadfb5
++dtest 12288 4096 494498364defdc27b2770d1f9c1e3387
++dtest 274432 4096 65c4bd8d30bf563fa5434119a12abff1
++dtest 8388608 9000 9a49b0461ee236b7fd7c452fb6a1f2dc
++dtest 16777216 20000 91e16429c901b68d30f783263f0611b7
++
++ftest dev.txt 4096 921ee9343b0759e16ad8d979d7dd16ec
++exit 0
diff --git a/target/jffs2/jffs2root.mk b/target/jffs2/jffs2root.mk
new file mode 100644
index 0000000000..a8c6de68ce
--- /dev/null
+++ b/target/jffs2/jffs2root.mk
@@ -0,0 +1,49 @@
+#############################################################
+#
+# mtd provides us with mkfs.jffs2, to target JFFS2 filesystems
+#
+#############################################################
+
+MTD_DIR:=$(BUILD_DIR)/mtd-20011217
+MTD_SOURCE=mtd_20011217.orig.tar.gz
+MTD_SITE=http://ftp.debian.org/debian/pool/main/m/mtd
+MKFS_JFFS2=$(shell which mkfs.jffs2 2>/dev/null || echo $(MTD_DIR)/util/mkfs.jffs2)
+
+$(DL_DIR)/$(MTD_SOURCE):
+ $(WGET) -P $(DL_DIR) $(MTD_SITE)/$(MTD_SOURCE)
+
+$(MTD_DIR)/.unpacked: $(DL_DIR)/$(MTD_SOURCE)
+ zcat $(DL_DIR)/$(MTD_SOURCE) | tar -C $(BUILD_DIR) -xvf -
+ touch $(MTD_DIR)/.unpacked
+
+$(MTD_DIR)/util/mkfs.jffs2: $(MTD_DIR)/.unpacked
+ CFLAGS=-I$(LINUX_HEADERS_DIR)/include $(MAKE) LINUXDIR=$(LINUX_DIR) -C $(MTD_DIR)/util
+
+mtd: $(MKFS_JFFS2)
+
+
+#############################################################
+#
+# Build the jffs2 root filesystem image
+#
+#############################################################
+
+jffs2root: mtd
+ #-@find $(TARGET_DIR)/lib -type f -name \*.so\* | xargs $(STRIP) --strip-unneeded 2>/dev/null || true;
+ -@find $(TARGET_DIR) -type f -perm +111 | xargs $(STRIP) 2>/dev/null || true;
+ @rm -rf $(TARGET_DIR)/usr/man
+ @rm -rf $(TARGET_DIR)/usr/info
+ $(MKFS_JFFS2) --pad --little-endian --squash -e 0x20000 \
+ -D $(SOURCE_DIR)/device_table.txt -d $(TARGET_DIR) \
+ -o $(IMAGE)
+
+jffs2root-source: $(DL_DIR)/$(MTD_SOURCE)
+
+jffs2root-clean:
+ -$(MAKE) -C $(MTD_DIR) clean
+
+jffs2root-dirclean:
+ rm -rf $(MTD_DIR)
+
+
+
diff --git a/target/squashfs/squashfs.patch b/target/squashfs/squashfs.patch
new file mode 100644
index 0000000000..ea75a7f18a
--- /dev/null
+++ b/target/squashfs/squashfs.patch
@@ -0,0 +1,36 @@
+This is a stupid little patch adding an option to change all uid/gid to
+root/root in the generated filesystem. We really need to teach mksquashfs
+about device tables though...
+
+--- squashfs1.3r3/squashfs-tools/mksquashfs.c-dist 2004-03-29 20:35:37.000000000 -0600
++++ squashfs1.3r3/squashfs-tools/mksquashfs.c 2004-03-29 22:28:51.000000000 -0600
+@@ -136,6 +136,8 @@
+ stotal_bytes, stotal_inode_bytes, stotal_directory_bytes, sinode_count, sfile_count, ssym_count, sdev_count, sdir_count, sdup_files;
+ int restore = 0;
+
++unsigned int root_owned = 0;
++
+ /*flag whether destination file is a block device */
+ int block_device = 0;
+
+@@ -421,6 +423,11 @@
+ return SQUASHFS_INVALID;
+ }
+
++ if (root_owned) {
++ buf.st_uid = 0;
++ buf.st_gid = 0;
++ }
++
+ base->mode = SQUASHFS_MODE(buf.st_mode);
+ base->uid = get_uid(&file_type, (squashfs_uid) buf.st_uid);
+ base->inode_type = file_type;
+@@ -1268,6 +1275,8 @@
+ root_name = argv[i];
+ } else if(strcmp(argv[i], "-version") == 0) {
+ VERSION();
++ } else if (strcmp(argv[i], "-root-owned") == 0) {
++ root_owned = TRUE;
+ } else {
+ ERROR("%s: invalid option\n\n", argv[0]);
+ printOptions:
diff --git a/target/squashfs/squashfsroot.mk b/target/squashfs/squashfsroot.mk
new file mode 100644
index 0000000000..523d5e2a9d
--- /dev/null
+++ b/target/squashfs/squashfsroot.mk
@@ -0,0 +1,51 @@
+#############################################################
+#
+# mksquashfs to build to target squashfs filesystems
+#
+#############################################################
+SQUASHFS_DIR=$(BUILD_DIR)/squashfs1.3r3
+SQUASHFS_SOURCE=squashfs1.3r3.tar.gz
+SQUASHFS_SITE=http://aleron.dl.sourceforge.net/sourceforge/squashfs
+
+$(DL_DIR)/$(SQUASHFS_SOURCE):
+ $(WGET) -P $(DL_DIR) $(SQUASHFS_SITE)/$(SQUASHFS_SOURCE)
+
+$(SQUASHFS_DIR): $(DL_DIR)/$(SQUASHFS_SOURCE) #$(SQUASHFS_PATCH)
+ zcat $(DL_DIR)/$(SQUASHFS_SOURCE) | tar -C $(BUILD_DIR) -xvf -
+ $(SOURCE_DIR)/patch-kernel.sh $(SQUASHFS_DIR) $(SOURCE_DIR) squashfs.patch
+
+$(SQUASHFS_DIR)/squashfs-tools/mksquashfs: $(SQUASHFS_DIR)
+ $(MAKE) -C $(SQUASHFS_DIR)/squashfs-tools;
+
+squashfs: $(SQUASHFS_DIR)/squashfs-tools/mksquashfs
+
+squashfs-source: $(DL_DIR)/$(SQUASHFS_SOURCE)
+
+squashfs-clean:
+ -$(MAKE) -C $(SQUASHFS_DIR)/squashfs-tools clean
+
+squashfs-dirclean:
+ rm -rf $(SQUASHFS_DIR)
+
+#############################################################
+#
+# Build the squashfs root filesystem image
+#
+#############################################################
+
+squashfsroot: squashfs
+ #-@find $(TARGET_DIR)/lib -type f -name \*.so\* | xargs $(STRIP) --strip-unneeded 2>/dev/null || true;
+ -@find $(TARGET_DIR) -type f -perm +111 | xargs $(STRIP) 2>/dev/null || true;
+ @rm -rf $(TARGET_DIR)/usr/man
+ @rm -rf $(TARGET_DIR)/usr/info
+ #$(SQUASHFS_DIR)/squashfs-tools/mksquashfs -q -D $(SOURCE_DIR)/device_table.txt $(TARGET_DIR) $(IMAGE)
+ $(SQUASHFS_DIR)/squashfs-tools/mksquashfs $(TARGET_DIR) $(IMAGE) -noappend -root-owned
+
+squashfsroot-source: squashfs-source
+
+squashfsroot-clean:
+ -$(MAKE) -C $(SQUASHFS_DIR) clean
+
+squashfsroot-dirclean:
+ rm -rf $(SQUASHFS_DIR)
+