openssl/openssh updates from below0
[oweals/openwrt.git] / obsolete-buildroot / sources / cramfs.patch
1 --- cramfs-1.1.orig/cramfsck.c  2002-02-22 17:00:42.000000000 -0700
2 +++ cramfs-1.1/cramfsck.c       2002-12-21 01:25:17.000000000 -0700
3 @@ -51,10 +51,11 @@
4  #include <utime.h>
5  #include <sys/ioctl.h>
6  #define _LINUX_STRING_H_
7 -#include <linux/fs.h>
8 -#include <linux/cramfs_fs.h>
9 +#include "linux/cramfs_fs.h"
10  #include <zlib.h>
11  
12 +#define BLKGETSIZE     _IO(0x12,96) /* return device size /512 (long *arg) */
13 +
14  /* Exit codes used by fsck-type programs */
15  #define FSCK_OK          0     /* No errors */
16  #define FSCK_NONDESTRUCT 1     /* File system errors corrected */
17 @@ -75,7 +76,7 @@
18  static int opt_verbose = 0;    /* 1 = verbose (-v), 2+ = very verbose (-vv) */
19  #ifdef INCLUDE_FS_TESTS
20  static int opt_extract = 0;            /* extract cramfs (-x) */
21 -static char *extract_dir = "root";     /* extraction directory (-x) */
22 +static char *extract_dir = "/";        /* extraction directory (-x) */
23  static uid_t euid;                     /* effective UID */
24  
25  /* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */
26 @@ -155,7 +156,7 @@
27         }
28  
29         if (*length < sizeof(struct cramfs_super)) {
30 -               die(FSCK_UNCORRECTED, 0, "file length too short");
31 +               die(FSCK_UNCORRECTED, 0, "filesystem smaller than a cramfs superblock!");
32         }
33  
34         /* find superblock */
35 @@ -190,7 +191,8 @@
36                         die(FSCK_UNCORRECTED, 0, "zero file count");
37                 }
38                 if (*length < super.size) {
39 -                       die(FSCK_UNCORRECTED, 0, "file length too short");
40 +                       die(FSCK_UNCORRECTED, 0, "file length too short, %lu is smaller than %lu",
41 +                               *length, super.size);
42                 }
43                 else if (*length > super.size) {
44                         fprintf(stderr, "warning: file extends past end of filesystem\n");
45 @@ -267,11 +269,11 @@
46  #ifdef INCLUDE_FS_TESTS
47  static void print_node(char type, struct cramfs_inode *i, char *name)
48  {
49 -       char info[10];
50 +       char info[11];
51  
52         if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) {
53                 /* major/minor numbers can be as high as 2^12 or 4096 */
54 -               snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size));
55 +               snprintf(info, 11, "%4d,%4d", major(i->size), minor(i->size));
56         }
57         else {
58                 /* size be as high as 2^24 or 16777216 */
59 @@ -445,8 +447,10 @@
60         }
61         /* TODO: Do we need to check end_dir for empty case? */
62         memcpy(newpath, path, pathlen);
63 -       newpath[pathlen] = '/';
64 -       pathlen++;
65 +       if (pathlen > 1) {
66 +           newpath[pathlen] = '/';
67 +           pathlen++;
68 +       }
69         if (opt_verbose) {
70                 print_node('d', i, path);
71         }
72 --- cramfs-1.1.orig/device_table.txt    1969-12-31 17:00:00.000000000 -0700
73 +++ cramfs-1.1/device_table.txt 2003-01-01 05:13:44.000000000 -0700
74 @@ -0,0 +1,129 @@
75 +# When building a target filesystem, it is desirable to not have to
76 +# become root and then run 'mknod' a thousand times.  Using a device 
77 +# table you can create device nodes and directories "on the fly".
78 +#
79 +# This is a sample device table file for use with mkcramfs.  You can
80 +# do all sorts of interesting things with a device table file.  For
81 +# example, if you want to adjust the permissions on a particular file
82 +# you can just add an entry like:
83 +#   /sbin/foobar       f       2755    0       0       -       -       -       -       -
84 +# and (assuming the file /sbin/foobar exists) it will be made setuid
85 +# root (regardless of what its permissions are on the host filesystem.
86 +# Furthermore, you can use a single table entry to create a many device
87 +# minors.  For example, if I wanted to create /dev/hda and /dev/hda[0-15]
88 +# I could just use the following two table entries:
89 +#   /dev/hda   b       640     0       0       3       0       0       0       -
90 +#   /dev/hda   b       640     0       0       3       1       1       1       15
91 +# 
92 +# Device table entries take the form of:
93 +# <name>    <type>     <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
94 +# where name is the file name,  type can be one of: 
95 +#      f       A regular file
96 +#      d       Directory
97 +#      c       Character special device file
98 +#      b       Block special device file
99 +#      p       Fifo (named pipe)
100 +# uid is the user id for the target file, gid is the group id for the
101 +# target file.  The rest of the entries (major, minor, etc) apply only 
102 +# to device special files.
103 +
104 +# Have fun
105 +# -Erik Andersen <andersen@codepoet.org>
106 +#
107 +
108 +#<name>                <type>  <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
109 +/dev           d       755     0       0       -       -       -       -       -
110 +/dev/mem       c       640     0       0       1       1       0       0       -
111 +/dev/kmem      c       640     0       0       1       2       0       0       -
112 +/dev/null      c       640     0       0       1       3       0       0       -
113 +/dev/zero      c       640     0       0       1       5       0       0       -
114 +/dev/random    c       640     0       0       1       8       0       0       -
115 +/dev/urandom   c       640     0       0       1       9       0       0       -
116 +/dev/tty       c       666     0       0       5       0       0       0       -
117 +/dev/tty       c       666     0       0       4       0       0       1       6
118 +/dev/console   c       640     0       0       5       1       0       0       -
119 +/dev/ram       b       640     0       0       1       1       0       0       -
120 +/dev/ram       b       640     0       0       1       0       0       1       4
121 +/dev/loop      b       640     0       0       7       0       0       1       2
122 +/dev/ptmx      c       666     0       0       5       2       0       0       -
123 +#/dev/ttyS     c       640     0       0       4       64      0       1       4
124 +#/dev/psaux    c       640     0       0       10      1       0       0       -
125 +#/dev/rtc      c       640     0       0       10      135     0       0       -
126 +
127 +# Adjust permissions on some normal files
128 +#/etc/shadow   f       600     0       0       -       -       -       -       -
129 +#/bin/tinylogin        f       4755    0       0       -       -       -       -       -
130 +
131 +# User-mode Linux stuff
132 +/dev/ubda      b       640     0       0       98      0       0       0       -
133 +/dev/ubda      b       640     0       0       98      1       1       1       15
134 +
135 +# IDE Devices
136 +/dev/hda       b       640     0       0       3       0       0       0       -
137 +/dev/hda       b       640     0       0       3       1       1       1       15
138 +/dev/hdb       b       640     0       0       3       64      0       0       -
139 +/dev/hdb       b       640     0       0       3       65      1       1       15
140 +#/dev/hdc      b       640     0       0       22      0       0       0       -
141 +#/dev/hdc      b       640     0       0       22      1       1       1       15
142 +#/dev/hdd      b       640     0       0       22      64      0       0       -
143 +#/dev/hdd      b       640     0       0       22      65      1       1       15
144 +#/dev/hde      b       640     0       0       33      0       0       0       -
145 +#/dev/hde      b       640     0       0       33      1       1       1       15
146 +#/dev/hdf      b       640     0       0       33      64      0       0       -
147 +#/dev/hdf      b       640     0       0       33      65      1       1       15
148 +#/dev/hdg      b       640     0       0       34      0       0       0       -
149 +#/dev/hdg      b       640     0       0       34      1       1       1       15
150 +#/dev/hdh      b       640     0       0       34      64      0       0       -
151 +#/dev/hdh      b       640     0       0       34      65      1       1       15
152 +
153 +# SCSI Devices
154 +#/dev/sda      b       640     0       0       8       0       0       0       -
155 +#/dev/sda      b       640     0       0       8       1       1       1       15
156 +#/dev/sdb      b       640     0       0       8       16      0       0       -
157 +#/dev/sdb      b       640     0       0       8       17      1       1       15
158 +#/dev/sdc      b       640     0       0       8       32      0       0       -
159 +#/dev/sdc      b       640     0       0       8       33      1       1       15
160 +#/dev/sdd      b       640     0       0       8       48      0       0       -
161 +#/dev/sdd      b       640     0       0       8       49      1       1       15
162 +#/dev/sde      b       640     0       0       8       64      0       0       -
163 +#/dev/sde      b       640     0       0       8       65      1       1       15
164 +#/dev/sdf      b       640     0       0       8       80      0       0       -
165 +#/dev/sdf      b       640     0       0       8       81      1       1       15
166 +#/dev/sdg      b       640     0       0       8       96      0       0       -
167 +#/dev/sdg      b       640     0       0       8       97      1       1       15
168 +#/dev/sdh      b       640     0       0       8       112     0       0       -
169 +#/dev/sdh      b       640     0       0       8       113     1       1       15
170 +#/dev/sg               c       640     0       0       21      0       0       1       15
171 +#/dev/scd      b       640     0       0       11      0       0       1       15
172 +#/dev/st               c       640     0       0       9       0       0       1       8
173 +#/dev/nst      c       640     0       0       9       128     0       1       8
174 +#/dev/st       c       640     0       0       9       32      1       1       4
175 +#/dev/st       c       640     0       0       9       64      1       1       4
176 +#/dev/st       c       640     0       0       9       96      1       1       4
177 +
178 +# Floppy disk devices
179 +#/dev/fd               b       640     0       0       2       0       0       1       2
180 +#/dev/fd0d360  b       640     0       0       2       4       0       0       -
181 +#/dev/fd1d360  b       640     0       0       2       5       0       0       -
182 +#/dev/fd0h1200 b       640     0       0       2       8       0       0       -
183 +#/dev/fd1h1200 b       640     0       0       2       9       0       0       -
184 +#/dev/fd0u1440 b       640     0       0       2       28      0       0       -
185 +#/dev/fd1u1440 b       640     0       0       2       29      0       0       -
186 +#/dev/fd0u2880 b       640     0       0       2       32      0       0       -
187 +#/dev/fd1u2880 b       640     0       0       2       33      0       0       -
188 +
189 +# All the proprietary cdrom devices in the world
190 +#/dev/aztcd    b       640     0       0       29      0       0       0       -
191 +#/dev/bpcd     b       640     0       0       41      0       0       0       -
192 +#/dev/capi20   c       640     0       0       68      0       0       1       2
193 +#/dev/cdu31a   b       640     0       0       15      0       0       0       -
194 +#/dev/cdu535   b       640     0       0       24      0       0       0       -
195 +#/dev/cm206cd  b       640     0       0       32      0       0       0       -
196 +#/dev/sjcd     b       640     0       0       18      0       0       0       -
197 +#/dev/sonycd   b       640     0       0       15      0       0       0       -
198 +#/dev/gscd     b       640     0       0       16      0       0       0       -
199 +#/dev/sbpcd    b       640     0       0       25      0       0       0       -
200 +#/dev/sbpcd    b       640     0       0       25      0       0       1       4
201 +#/dev/mcd      b       640     0       0       23      0       0       0       -
202 +#/dev/optcd    b       640     0       0       17      0       0       0       -
203 +
204 --- cramfs-1.1.orig/mkcramfs.c  2002-02-20 01:03:32.000000000 -0700
205 +++ cramfs-1.1/mkcramfs.c       2002-12-21 01:25:17.000000000 -0700
206 @@ -1,3 +1,4 @@
207 +/* vi: set sw=8 ts=8: */
208  /*
209   * mkcramfs - make a cramfs file system
210   *
211 @@ -16,12 +17,21 @@
212   * You should have received a copy of the GNU General Public License
213   * along with this program; if not, write to the Free Software
214   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
215 + *
216 + * Added device table support (code taken from mkfs.jffs2.c, credit to
217 + * Erik Andersen <andersen@codepoet.org>) as well as an option to squash
218 + * permissions. - Russ Dill <Russ.Dill@asu.edu> September 2002
219 + *
220 + * Reworked, cleaned up, and updated for cramfs-1.1, December 2002
221 + *  - Erik Andersen <andersen@codepoet.org>
222 + *
223   */
224  
225  /*
226   * If you change the disk format of cramfs, please update fs/cramfs/README.
227   */
228  
229 +#define _GNU_SOURCE
230  #include <sys/types.h>
231  #include <stdio.h>
232  #include <sys/stat.h>
233 @@ -33,8 +43,15 @@
234  #include <errno.h>
235  #include <string.h>
236  #include <stdarg.h>
237 +#include <libgen.h>
238 +#include <ctype.h>
239 +#include <assert.h>
240 +#include <getopt.h>
241  #include <linux/cramfs_fs.h>
242  #include <zlib.h>
243 +#ifdef DMALLOC
244 +#include <dmalloc.h>
245 +#endif
246  
247  /* Exit codes used by mkfs-type programs */
248  #define MKFS_OK          0     /* No errors */
249 @@ -71,11 +88,17 @@
250                   + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
251                   + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
252  
253 +
254 +/* The kernel assumes PAGE_CACHE_SIZE as block size. */
255 +#define PAGE_CACHE_SIZE (4096)
256 +
257 +
258  static const char *progname = "mkcramfs";
259  static unsigned int blksize = PAGE_CACHE_SIZE;
260  static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
261  static int image_length = 0;
262  
263 +
264  /*
265   * If opt_holes is set, then mkcramfs can create explicit holes in the
266   * data, which saves 26 bytes per hole (which is a lot smaller a
267 @@ -91,10 +114,12 @@
268  static int opt_holes = 0;
269  static int opt_pad = 0;
270  static int opt_verbose = 0;
271 +static int opt_squash = 0;
272  static char *opt_image = NULL;
273  static char *opt_name = NULL;
274  
275  static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
276 +static const char *const memory_exhausted = "memory exhausted";
277  
278  /* In-core version of inode / directory entry. */
279  struct entry {
280 @@ -123,7 +148,7 @@
281  {
282         FILE *stream = status ? stderr : stdout;
283  
284 -       fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
285 +       fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] [-D file] dirname outfile\n"
286                 " -h         print this help\n"
287                 " -E         make all warnings errors (non-zero exit status)\n"
288                 " -e edition set edition number (part of fsid)\n"
289 @@ -133,39 +158,157 @@
290                 " -s         sort directory entries (old option, ignored)\n"
291                 " -v         be more verbose\n"
292                 " -z         make explicit holes (requires >= 2.3.39)\n"
293 -               " dirname    root of the directory tree to be compressed\n"
294 +               " -D         Use the named FILE as a device table file\n"
295 +               " -q         squash permissions (make everything owned by root)\n"
296 +               " dirname    root of the filesystem to be compressed\n"
297                 " outfile    output file\n", progname, PAD_SIZE);
298  
299         exit(status);
300  }
301  
302 -static void die(int status, int syserr, const char *fmt, ...)
303 +static void verror_msg(const char *s, va_list p)
304 +{
305 +       fflush(stdout);
306 +       fprintf(stderr, "mkcramfs: ");
307 +       vfprintf(stderr, s, p);
308 +}
309 +
310 +static void vperror_msg(const char *s, va_list p)
311 +{
312 +       int err = errno;
313 +
314 +       if (s == 0)
315 +               s = "";
316 +       verror_msg(s, p);
317 +       if (*s)
318 +               s = ": ";
319 +       fprintf(stderr, "%s%s\n", s, strerror(err));
320 +}
321 +
322 +static void perror_msg(const char *s, ...)
323 +{
324 +       va_list p;
325 +
326 +       va_start(p, s);
327 +       vperror_msg(s, p);
328 +       va_end(p);
329 +}
330 +
331 +static void error_msg_and_die(const char *s, ...)
332 +{
333 +       va_list p;
334 +
335 +       va_start(p, s);
336 +       verror_msg(s, p);
337 +       va_end(p);
338 +       putc('\n', stderr);
339 +       exit(MKFS_ERROR);
340 +}
341 +
342 +static void perror_msg_and_die(const char *s, ...)
343 +{
344 +       va_list p;
345 +
346 +       va_start(p, s);
347 +       vperror_msg(s, p);
348 +       va_end(p);
349 +       exit(MKFS_ERROR);
350 +}
351 +#ifndef DMALLOC
352 +extern char *xstrdup(const char *s)
353 +{
354 +       char *t;
355 +
356 +       if (s == NULL)
357 +               return NULL;
358 +       t = strdup(s);
359 +       if (t == NULL)
360 +               error_msg_and_die(memory_exhausted);
361 +       return t;
362 +}
363 +
364 +extern void *xmalloc(size_t size)
365 +{
366 +       void *ptr = malloc(size);
367 +
368 +       if (ptr == NULL && size != 0)
369 +               error_msg_and_die(memory_exhausted);
370 +       return ptr;
371 +}
372 +
373 +extern void *xcalloc(size_t nmemb, size_t size)
374 +{
375 +       void *ptr = calloc(nmemb, size);
376 +
377 +       if (ptr == NULL && nmemb != 0 && size != 0)
378 +               error_msg_and_die(memory_exhausted);
379 +       return ptr;
380 +}
381 +
382 +extern void *xrealloc(void *ptr, size_t size)
383 +{
384 +       ptr = realloc(ptr, size);
385 +       if (ptr == NULL && size != 0)
386 +               error_msg_and_die(memory_exhausted);
387 +       return ptr;
388 +}
389 +#endif
390 +
391 +static FILE *xfopen(const char *path, const char *mode)
392  {
393 -       va_list arg_ptr;
394 -       int save = errno;
395 +       FILE *fp;
396 +
397 +       if ((fp = fopen(path, mode)) == NULL)
398 +               perror_msg_and_die("%s", path);
399 +       return fp;
400 +}
401  
402 -       fflush(0);
403 -       va_start(arg_ptr, fmt);
404 -       fprintf(stderr, "%s: ", progname);
405 -       vfprintf(stderr, fmt, arg_ptr);
406 -       if (syserr) {
407 -               fprintf(stderr, ": %s", strerror(save));
408 +extern int xopen(const char *pathname, int flags, mode_t mode)
409 +{
410 +       int ret;
411 +       
412 +       if (flags & O_CREAT)
413 +               ret = open(pathname, flags, mode);
414 +       else
415 +               ret = open(pathname, flags);
416 +       if (ret == -1) {
417 +               perror_msg_and_die("%s", pathname);
418         }
419 -       fprintf(stderr, "\n");
420 -       va_end(arg_ptr);
421 -       exit(status);
422 +       return ret;
423  }
424  
425 +extern char *xreadlink(const char *path)
426 +{                       
427 +       static const int GROWBY = 80; /* how large we will grow strings by */
428 +
429 +       char *buf = NULL;   
430 +       int bufsize = 0, readsize = 0;
431 +
432 +       do {
433 +               buf = xrealloc(buf, bufsize += GROWBY);
434 +               readsize = readlink(path, buf, bufsize); /* 1st try */
435 +               if (readsize == -1) {
436 +                   perror_msg("%s:%s", progname, path);
437 +                   return NULL;
438 +               }
439 +       }           
440 +       while (bufsize < readsize + 1);
441 +
442 +       buf[readsize] = '\0';
443 +
444 +       return buf;
445 +}       
446 +
447  static void map_entry(struct entry *entry)
448  {
449         if (entry->path) {
450                 entry->fd = open(entry->path, O_RDONLY);
451                 if (entry->fd < 0) {
452 -                       die(MKFS_ERROR, 1, "open failed: %s", entry->path);
453 +                       error_msg_and_die("open failed: %s", entry->path);
454                 }
455                 entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, entry->fd, 0);
456                 if (entry->uncompressed == MAP_FAILED) {
457 -                       die(MKFS_ERROR, 1, "mmap failed: %s", entry->path);
458 +                       error_msg_and_die("mmap failed: %s", entry->path);
459                 }
460         }
461  }
462 @@ -174,8 +317,9 @@
463  {
464         if (entry->path) {
465                 if (munmap(entry->uncompressed, entry->size) < 0) {
466 -                       die(MKFS_ERROR, 1, "munmap failed: %s", entry->path);
467 +                       error_msg_and_die("munmap failed: %s", entry->path);
468                 }
469 +               entry->uncompressed=NULL;
470                 close(entry->fd);
471         }
472  }
473 @@ -204,7 +348,8 @@
474                 find_identical_file(orig->next, newfile));
475  }
476  
477 -static void eliminate_doubles(struct entry *root, struct entry *orig) {
478 +static void eliminate_doubles(struct entry *root, struct entry *orig) 
479 +{
480         if (orig) {
481                 if (orig->size && (orig->path || orig->uncompressed))
482                         find_identical_file(root, orig);
483 @@ -232,10 +377,7 @@
484  
485         /* Set up the path. */
486         /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
487 -       path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
488 -       if (!path) {
489 -               die(MKFS_ERROR, 1, "malloc failed");
490 -       }
491 +       path = xmalloc(len + 1 + MAX_INPUT_NAMELEN + 1);
492         memcpy(path, name, len);
493         endpath = path + len;
494         *endpath = '/';
495 @@ -245,7 +387,7 @@
496         dircount = scandir(name, &dirlist, 0, cramsort);
497  
498         if (dircount < 0) {
499 -               die(MKFS_ERROR, 1, "scandir failed: %s", name);
500 +               error_msg_and_die("scandir failed: %s", name);
501         }
502  
503         /* process directory */
504 @@ -269,25 +411,20 @@
505                 }
506                 namelen = strlen(dirent->d_name);
507                 if (namelen > MAX_INPUT_NAMELEN) {
508 -                       die(MKFS_ERROR, 0,
509 -                               "very long (%u bytes) filename found: %s\n"
510 -                               "please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile",
511 +                       error_msg_and_die(
512 +                               "Very long (%u bytes) filename `%s' found.\n"
513 +                               " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
514                                 namelen, dirent->d_name);
515                 }
516                 memcpy(endpath, dirent->d_name, namelen + 1);
517  
518                 if (lstat(path, &st) < 0) {
519 +                       perror(endpath);
520                         warn_skip = 1;
521                         continue;
522                 }
523 -               entry = calloc(1, sizeof(struct entry));
524 -               if (!entry) {
525 -                       die(MKFS_ERROR, 1, "calloc failed");
526 -               }
527 -               entry->name = strdup(dirent->d_name);
528 -               if (!entry->name) {
529 -                       die(MKFS_ERROR, 1, "strdup failed");
530 -               }
531 +               entry = xcalloc(1, sizeof(struct entry));
532 +               entry->name = xstrdup(dirent->d_name);
533                 /* truncate multi-byte UTF-8 filenames on character boundary */
534                 if (namelen > CRAMFS_MAXPATHLEN) {
535                         namelen = CRAMFS_MAXPATHLEN;
536 @@ -297,24 +434,25 @@
537                                 namelen--;
538                                 /* are we reasonably certain it was UTF-8 ? */
539                                 if (entry->name[namelen] < 0x80 || !namelen) {
540 -                                       die(MKFS_ERROR, 0, "cannot truncate filenames not encoded in UTF-8");
541 +                                       error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
542                                 }
543                         }
544                         entry->name[namelen] = '\0';
545                 }
546                 entry->mode = st.st_mode;
547                 entry->size = st.st_size;
548 -               entry->uid = st.st_uid;
549 +               entry->uid = opt_squash ? 0 : st.st_uid;
550                 if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
551                         warn_uid = 1;
552 -               entry->gid = st.st_gid;
553 -               if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
554 +               entry->gid = opt_squash ? 0 : st.st_gid;
555 +               if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
556                         /* TODO: We ought to replace with a default
557                            gid instead of truncating; otherwise there
558                            are security problems.  Maybe mode should
559                            be &= ~070.  Same goes for uid once Linux
560                            supports >16-bit uids. */
561                         warn_gid = 1;
562 +               }
563                 size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
564                 *fslen_ub += size;
565                 if (S_ISDIR(st.st_mode)) {
566 @@ -325,21 +463,15 @@
567                                         warn_skip = 1;
568                                         continue;
569                                 }
570 -                               entry->path = strdup(path);
571 -                               if (!entry->path) {
572 -                                       die(MKFS_ERROR, 1, "strdup failed");
573 -                               }
574 +                               entry->path = xstrdup(path);
575                                 if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
576                                         warn_size = 1;
577                                         entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
578                                 }
579                         }
580                 } else if (S_ISLNK(st.st_mode)) {
581 -                       entry->uncompressed = malloc(entry->size);
582 +                       entry->uncompressed = xreadlink(path);
583                         if (!entry->uncompressed) {
584 -                               die(MKFS_ERROR, 1, "malloc failed");
585 -                       }
586 -                       if (readlink(path, entry->uncompressed, entry->size) < 0) {
587                                 warn_skip = 1;
588                                 continue;
589                         }
590 @@ -351,7 +483,7 @@
591                         if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
592                                 warn_dev = 1;
593                 } else {
594 -                       die(MKFS_ERROR, 0, "bogus file type: %s", entry->name);
595 +                       error_msg_and_die("bogus file type: %s", entry->name);
596                 }
597  
598                 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
599 @@ -378,7 +510,9 @@
600         struct cramfs_super *super = (struct cramfs_super *) base;
601         unsigned int offset = sizeof(struct cramfs_super) + image_length;
602  
603 -       offset += opt_pad;      /* 0 if no padding */
604 +       if (opt_pad) {
605 +               offset += opt_pad;      /* 0 if no padding */
606 +       }
607  
608         super->magic = CRAMFS_MAGIC;
609         super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
610 @@ -414,10 +548,10 @@
611         struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
612  
613         if ((offset & 3) != 0) {
614 -               die(MKFS_ERROR, 0, "illegal offset of %lu bytes", offset);
615 +               error_msg_and_die("illegal offset of %lu bytes", offset);
616         }
617         if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
618 -               die(MKFS_ERROR, 0, "filesystem too big");
619 +               error_msg_and_die("filesystem too big");
620         }
621         inode->offset = (offset >> 2);
622  }
623 @@ -429,7 +563,7 @@
624   */
625  static void print_node(struct entry *e)
626  {
627 -       char info[10];
628 +       char info[12];
629         char type = '?';
630  
631         if (S_ISREG(e->mode)) type = 'f';
632 @@ -442,11 +576,11 @@
633  
634         if (S_ISCHR(e->mode) || (S_ISBLK(e->mode))) {
635                 /* major/minor numbers can be as high as 2^12 or 4096 */
636 -               snprintf(info, 10, "%4d,%4d", major(e->size), minor(e->size));
637 +               snprintf(info, 11, "%4d,%4d", major(e->size), minor(e->size));
638         }
639         else {
640                 /* size be as high as 2^24 or 16777216 */
641 -               snprintf(info, 10, "%9d", e->size);
642 +               snprintf(info, 11, "%9d", e->size);
643         }
644  
645         printf("%c %04o %s %5d:%-3d %s\n",
646 @@ -462,17 +596,9 @@
647  {
648         int stack_entries = 0;
649         int stack_size = 64;
650 -       struct entry **entry_stack;
651 -
652 -       entry_stack = malloc(stack_size * sizeof(struct entry *));
653 -       if (!entry_stack) {
654 -               die(MKFS_ERROR, 1, "malloc failed");
655 -       }
656 -
657 -       if (opt_verbose) {
658 -               printf("root:\n");
659 -       }
660 +       struct entry **entry_stack = NULL;
661  
662 +       entry_stack = xmalloc(stack_size * sizeof(struct entry *));
663         for (;;) {
664                 int dir_start = stack_entries;
665                 while (entry) {
666 @@ -506,10 +632,7 @@
667                         if (entry->child) {
668                                 if (stack_entries >= stack_size) {
669                                         stack_size *= 2;
670 -                                       entry_stack = realloc(entry_stack, stack_size * sizeof(struct entry *));
671 -                                       if (!entry_stack) {
672 -                                               die(MKFS_ERROR, 1, "realloc failed");
673 -                                       }
674 +                                       entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
675                                 }
676                                 entry_stack[stack_entries] = entry;
677                                 stack_entries++;
678 @@ -543,7 +666,7 @@
679  
680                 set_data_offset(entry, base, offset);
681                 if (opt_verbose) {
682 -                       printf("%s:\n", entry->name);
683 +                   printf("'%s':\n", entry->name);
684                 }
685                 entry = entry->child;
686         }
687 @@ -553,16 +676,21 @@
688  
689  static int is_zero(char const *begin, unsigned len)
690  {
691 -       /* Returns non-zero iff the first LEN bytes from BEGIN are all NULs. */
692 -       return (len-- == 0 ||
693 -               (begin[0] == '\0' &&
694 -                (len-- == 0 ||
695 -                 (begin[1] == '\0' &&
696 -                  (len-- == 0 ||
697 -                   (begin[2] == '\0' &&
698 -                    (len-- == 0 ||
699 -                     (begin[3] == '\0' &&
700 -                      memcmp(begin, begin + 4, len) == 0))))))));
701 +       if (opt_holes)
702 +               /* Returns non-zero iff the first LEN bytes from BEGIN are
703 +                  all NULs. */
704 +               return (len-- == 0 ||
705 +                       (begin[0] == '\0' &&
706 +                        (len-- == 0 ||
707 +                         (begin[1] == '\0' &&
708 +                          (len-- == 0 ||
709 +                           (begin[2] == '\0' &&
710 +                            (len-- == 0 ||
711 +                             (begin[3] == '\0' &&
712 +                              memcmp(begin, begin + 4, len) == 0))))))));
713 +       else
714 +               /* Never create holes. */
715 +               return 0;
716  }
717  
718  /*
719 @@ -575,37 +703,34 @@
720   * Note that size > 0, as a zero-sized file wouldn't ever
721   * have gotten here in the first place.
722   */
723 -static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
724 +static unsigned int do_compress(char *base, unsigned int offset, struct entry *entry)
725  {
726 +       unsigned int size = entry->size;
727         unsigned long original_size = size;
728         unsigned long original_offset = offset;
729         unsigned long new_size;
730         unsigned long blocks = (size - 1) / blksize + 1;
731         unsigned long curr = offset + 4 * blocks;
732         int change;
733 +       char *uncompressed = entry->uncompressed;
734  
735 -       total_blocks += blocks;
736 +       total_blocks += blocks; 
737  
738         do {
739                 unsigned long len = 2 * blksize;
740                 unsigned int input = size;
741 -               int err;
742 -
743                 if (input > blksize)
744                         input = blksize;
745                 size -= input;
746 -               if (!(opt_holes && is_zero (uncompressed, input))) {
747 -                       err = compress2(base + curr, &len, uncompressed, input, Z_BEST_COMPRESSION);
748 -                       if (err != Z_OK) {
749 -                               die(MKFS_ERROR, 0, "compression error: %s", zError(err));
750 -                       }
751 +               if (!is_zero (uncompressed, input)) {
752 +                       compress(base + curr, &len, uncompressed, input);
753                         curr += len;
754                 }
755                 uncompressed += input;
756  
757                 if (len > blksize*2) {
758                         /* (I don't think this can happen with zlib.) */
759 -                       die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len);
760 +                       error_msg_and_die("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
761                 }
762  
763                 *(u32 *) (base + offset) = curr;
764 @@ -618,10 +743,12 @@
765            st_blocks * 512.  But if you say that then perhaps
766            administrative data should also be included in both. */
767         change = new_size - original_size;
768 -       if (opt_verbose > 1) {
769 -               printf("%6.2f%% (%+d bytes)\t%s\n",
770 -                      (change * 100) / (double) original_size, change, name);
771 +#if 0
772 +       if (opt_verbose) {
773 +           printf("%6.2f%% (%+d bytes)\t%s\n",
774 +                   (change * 100) / (double) original_size, change, entry->name);
775         }
776 +#endif
777  
778         return curr;
779  }
780 @@ -644,7 +771,7 @@
781                                 set_data_offset(entry, base, offset);
782                                 entry->offset = offset;
783                                 map_entry(entry);
784 -                               offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
785 +                               offset = do_compress(base, offset, entry);
786                                 unmap_entry(entry);
787                         }
788                 }
789 @@ -660,13 +787,10 @@
790         int fd;
791         char *buf;
792  
793 -       fd = open(file, O_RDONLY);
794 -       if (fd < 0) {
795 -               die(MKFS_ERROR, 1, "open failed: %s", file);
796 -       }
797 +       fd = xopen(file, O_RDONLY, 0);
798         buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
799         if (buf == MAP_FAILED) {
800 -               die(MKFS_ERROR, 1, "mmap failed");
801 +               error_msg_and_die("mmap failed");
802         }
803         memcpy(base + offset, buf, image_length);
804         munmap(buf, image_length);
805 @@ -679,6 +803,328 @@
806         return (offset + image_length);
807  }
808  
809 +static struct entry *find_filesystem_entry(struct entry *dir, char *name, mode_t type)
810 +{
811 +       struct entry *e = dir;
812 +
813 +       if (S_ISDIR(dir->mode)) {
814 +               e = dir->child;
815 +       }
816 +       while (e) {
817 +               /* Only bother to do the expensive strcmp on matching file types */
818 +               if (type == (e->mode & S_IFMT) && e->name) {
819 +                       if (S_ISDIR(e->mode)) {
820 +                               int len = strlen(e->name);
821 +
822 +                               /* Check if we are a parent of the correct path */
823 +                               if (strncmp(e->name, name, len) == 0) {
824 +                                       /* Is this an _exact_ match? */
825 +                                       if (strcmp(name, e->name) == 0) {
826 +                                               return (e);
827 +                                       }
828 +                                       /* Looks like we found a parent of the correct path */
829 +                                       if (name[len] == '/') {
830 +                                               if (e->child) {
831 +                                                       return (find_filesystem_entry (e, name + len + 1, type));
832 +                                               } else {
833 +                                                       return NULL;
834 +                                               }
835 +                                       }
836 +                               }
837 +                       } else {
838 +                               if (strcmp(name, e->name) == 0) {
839 +                                       return (e);
840 +                               }
841 +                       }
842 +               }
843 +               e = e->next;
844 +       }
845 +       return (NULL);
846 +}
847 +
848 +void modify_entry(char *full_path, unsigned long uid, unsigned long gid, 
849 +       unsigned long mode, unsigned long rdev, struct entry *root, loff_t *fslen_ub)
850 +{
851 +       char *name, *path, *full;
852 +       struct entry *curr, *parent, *entry, *prev;
853 +       
854 +       full = xstrdup(full_path);
855 +       path = xstrdup(dirname(full));
856 +       name = full_path + strlen(path) + 1;
857 +       free(full);
858 +       if (strcmp(path, "/") == 0) {
859 +               parent = root;
860 +               name = full_path + 1;
861 +       } else {
862 +               if (!(parent = find_filesystem_entry(root, path+1, S_IFDIR)))
863 +                       error_msg_and_die("%s/%s: could not find parent\n", path, name);
864 +       }
865 +       if ((entry = find_filesystem_entry(parent, name, (mode & S_IFMT)))) {
866 +               /* its there, just modify permissions */
867 +               entry->mode = mode;
868 +               entry->uid = uid;
869 +               entry->gid = gid;
870 +       } else { /* make a new entry */
871 +       
872 +               /* code partially replicated from parse_directory() */
873 +               size_t namelen;
874 +               if (S_ISREG(mode)) {
875 +                       error_msg_and_die("%s: regular file from device_table file must exist on disk!", full_path);
876 +               }
877 +
878 +               namelen = strlen(name);
879 +               if (namelen > MAX_INPUT_NAMELEN) {
880 +                       error_msg_and_die(
881 +                               "Very long (%u bytes) filename `%s' found.\n"
882 +                               " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
883 +                               namelen, name);
884 +               }
885 +               entry = xcalloc(1, sizeof(struct entry));
886 +               entry->name = xstrdup(name);
887 +               /* truncate multi-byte UTF-8 filenames on character boundary */
888 +               if (namelen > CRAMFS_MAXPATHLEN) {
889 +                       namelen = CRAMFS_MAXPATHLEN;
890 +                       warn_namelen = 1;
891 +                       /* the first lost byte must not be a trail byte */
892 +                       while ((entry->name[namelen] & 0xc0) == 0x80) {
893 +                               namelen--;
894 +                               /* are we reasonably certain it was UTF-8 ? */
895 +                               if (entry->name[namelen] < 0x80 || !namelen) {
896 +                                       error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
897 +                               }
898 +                       }
899 +                       entry->name[namelen] = '\0';
900 +               }
901 +               entry->mode = mode;
902 +               entry->uid = uid;
903 +               entry->gid = gid;
904 +               entry->size = 0;
905 +               if (S_ISBLK(mode) || S_ISCHR(mode)) {
906 +                       entry->size = rdev;
907 +                       if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
908 +                               warn_dev = 1;
909 +               }
910 +               
911 +               /* ok, now we have to backup and correct the size of all the entries above us */
912 +               *fslen_ub += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
913 +               parent->size += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
914 +
915 +               /* alright, time to link us in */
916 +               curr = parent->child;
917 +               prev = NULL;
918 +               while (curr && strcmp(name, curr->name) > 0) {
919 +                       prev = curr;
920 +                       curr = curr->next;
921 +               }
922 +               if (!prev) parent->child = entry;
923 +               else prev->next = entry;
924 +               entry->next = curr;
925 +               entry->child = NULL;
926 +       }
927 +       if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
928 +               warn_uid = 1;
929 +       if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
930 +               /* TODO: We ought to replace with a default
931 +                  gid instead of truncating; otherwise there
932 +                  are security problems.  Maybe mode should
933 +                  be &= ~070.  Same goes for uid once Linux
934 +                  supports >16-bit uids. */
935 +               warn_gid = 1;
936 +       }
937 +       free(path);
938 +}
939 +
940 +/* the GNU C library has a wonderful scanf("%as", string) which will
941 + allocate the string with the right size, good to avoid buffer overruns. 
942 + the following macros use it if available or use a hacky workaround...
943 + */
944 +
945 +#ifdef __GNUC__
946 +#define SCANF_PREFIX "a"
947 +#define SCANF_STRING(s) (&s)
948 +#define GETCWD_SIZE 0
949 +#else
950 +#define SCANF_PREFIX "511"
951 +#define SCANF_STRING(s) (s = xmalloc(512))
952 +#define GETCWD_SIZE -1
953 +inline int snprintf(char *str, size_t n, const char *fmt, ...)
954 +{
955 +       int ret;
956 +       va_list ap;
957 +
958 +       va_start(ap, fmt);
959 +       ret = vsprintf(str, fmt, ap);
960 +       va_end(ap);
961 +       return ret;
962 +}
963 +#endif
964 +
965 +/*  device table entries take the form of:
966 +    <path>     <type> <mode>   <uid>   <gid>   <major> <minor> <start> <inc>   <count>
967 +    /dev/mem     c    640       0       0         1       1       0     0         -
968 +
969 +    type can be one of: 
970 +       f       A regular file
971 +       d       Directory
972 +       c       Character special device file
973 +       b       Block special device file
974 +       p       Fifo (named pipe)
975 +
976 +    I don't bother with symlinks (permissions are irrelevant), hard
977 +    links (special cases of regular files), or sockets (why bother).
978 +
979 +    Regular files must exist in the target root directory.  If a char,
980 +    block, fifo, or directory does not exist, it will be created.
981 +*/
982 +
983 +static int interpret_table_entry(char *line, struct entry *root, loff_t *fslen_ub)
984 +{
985 +       char type, *name = NULL;
986 +       unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
987 +       unsigned long start = 0, increment = 1, count = 0;
988 +
989 +       if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
990 +                SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
991 +                &start, &increment, &count) < 0) 
992 +       {
993 +               return 1;
994 +       }
995 +
996 +       if (!strcmp(name, "/")) {
997 +               error_msg_and_die("Device table entries require absolute paths");
998 +       }
999 +
1000 +       switch (type) {
1001 +       case 'd':
1002 +               mode |= S_IFDIR;
1003 +               modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
1004 +               break;
1005 +       case 'f':
1006 +               mode |= S_IFREG;
1007 +               modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
1008 +               break;
1009 +       case 'p':
1010 +               mode |= S_IFIFO;
1011 +               modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
1012 +               break;
1013 +       case 'c':
1014 +       case 'b':
1015 +               mode |= (type == 'c') ? S_IFCHR : S_IFBLK;
1016 +               if (count > 0) {
1017 +                       char *buf;
1018 +                       unsigned long i;
1019 +                       dev_t rdev;
1020 +
1021 +                       for (i = start; i < count; i++) {
1022 +                               asprintf(&buf, "%s%lu", name, i);
1023 +                               rdev = makedev(major, minor + (i * increment - start));
1024 +                               modify_entry(buf, uid, gid, mode, rdev, root, fslen_ub);
1025 +                               free(buf);
1026 +                       }
1027 +               } else {
1028 +                       dev_t rdev = makedev(major, minor);
1029 +                       modify_entry(name, uid, gid, mode, rdev, root, fslen_ub);
1030 +               }
1031 +               break;
1032 +       default:
1033 +               error_msg_and_die("Unsupported file type");
1034 +       }
1035 +       free(name);
1036 +       return 0;
1037 +}
1038 +
1039 +static int parse_device_table(FILE *file, struct entry *root, loff_t *fslen_ub)
1040 +{
1041 +       char *line;
1042 +       int status = 0;
1043 +       size_t length = 0;
1044 +
1045 +       /* Turn off squash, since we must ensure that values
1046 +        * entered via the device table are not squashed */
1047 +       opt_squash = 0;
1048 +
1049 +       /* Looks ok so far.  The general plan now is to read in one
1050 +        * line at a time, check for leading comment delimiters ('#'),
1051 +        * then try and parse the line as a device table.  If we fail
1052 +        * to parse things, try and help the poor fool to fix their
1053 +        * device table with a useful error msg... */
1054 +       line = NULL;
1055 +       while (getline(&line, &length, file) != -1) {
1056 +               /* First trim off any whitespace */
1057 +               int len = strlen(line);
1058 +
1059 +               /* trim trailing whitespace */
1060 +               while (len > 0 && isspace(line[len - 1]))
1061 +                       line[--len] = '\0';
1062 +               /* trim leading whitespace */
1063 +               memmove(line, &line[strspn(line, " \n\r\t\v")], len);
1064 +
1065 +               /* How long are we after trimming? */
1066 +               len = strlen(line);
1067 +
1068 +               /* If this is NOT a comment line, try to interpret it */
1069 +               if (len && *line != '#') {
1070 +                       if (interpret_table_entry(line, root, fslen_ub))
1071 +                               status = 1;
1072 +               }
1073 +
1074 +               free(line);
1075 +               line = NULL;
1076 +       }
1077 +       free(line);
1078 +       fclose(file);
1079 +
1080 +       return status;
1081 +}
1082 +
1083 +void traverse(struct entry *entry, int depth)
1084 +{
1085 +       struct entry *curr = entry;
1086 +       int i;
1087 +
1088 +       while (curr) {
1089 +               for (i = 0; i < depth; i++) putchar(' ');
1090 +               printf("%s: size=%d mode=%d same=%p\n",
1091 +                       (curr->name)? (char*)curr->name : "/", 
1092 +                       curr->size, curr->mode, curr->same);
1093 +               if (curr->child) traverse(curr->child, depth + 4);
1094 +               curr = curr->next;
1095 +       }
1096 +}
1097 +
1098 +static void free_filesystem_entry(struct entry *dir)
1099 +{
1100 +       struct entry *e = dir, *last;
1101 +
1102 +       if (S_ISDIR(dir->mode)) {
1103 +               e = dir->child;
1104 +       }
1105 +       while (e) {
1106 +               if (e->name)
1107 +                       free(e->name);
1108 +               if (e->path)
1109 +                       free(e->path);
1110 +               if (e->uncompressed)
1111 +                       free(e->uncompressed);
1112 +               last = e;
1113 +               if (e->child) {
1114 +                       free_filesystem_entry(e);
1115 +               }
1116 +               e = e->next;
1117 +               free(last);
1118 +       }
1119 +}
1120 +
1121 +
1122 +/*
1123 + * Usage:
1124 + *
1125 + *      mkcramfs directory-name outfile
1126 + *
1127 + * where "directory-name" is simply the root of the directory
1128 + * tree that we want to generate a compressed filesystem out
1129 + * of.
1130 + */
1131  int main(int argc, char **argv)
1132  {
1133         struct stat st;         /* used twice... */
1134 @@ -692,6 +1138,7 @@
1135         u32 crc;
1136         int c;                  /* for getopt */
1137         char *ep;               /* for strtoul */
1138 +       FILE *devtable = NULL;
1139  
1140         total_blocks = 0;
1141  
1142 @@ -699,7 +1146,7 @@
1143                 progname = argv[0];
1144  
1145         /* command line options */
1146 -       while ((c = getopt(argc, argv, "hEe:i:n:psvz")) != EOF) {
1147 +       while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) {
1148                 switch (c) {
1149                 case 'h':
1150                         usage(MKFS_OK);
1151 @@ -715,7 +1162,7 @@
1152                 case 'i':
1153                         opt_image = optarg;
1154                         if (lstat(opt_image, &st) < 0) {
1155 -                               die(MKFS_ERROR, 1, "lstat failed: %s", opt_image);
1156 +                               error_msg_and_die("lstat failed: %s", opt_image);
1157                         }
1158                         image_length = st.st_size; /* may be padded later */
1159                         fslen_ub += (image_length + 3); /* 3 is for padding */
1160 @@ -736,6 +1183,16 @@
1161                 case 'z':
1162                         opt_holes = 1;
1163                         break;
1164 +               case 'q':
1165 +                       opt_squash = 1;
1166 +                       break;
1167 +               case 'D':
1168 +                       devtable = xfopen(optarg, "r");
1169 +                       if (fstat(fileno(devtable), &st) < 0)
1170 +                               perror_msg_and_die(optarg);
1171 +                       if (st.st_size < 10)
1172 +                               error_msg_and_die("%s: not a proper device table file\n", optarg);
1173 +                       break;
1174                 }
1175         }
1176  
1177 @@ -745,25 +1202,23 @@
1178         outfile = argv[optind + 1];
1179  
1180         if (stat(dirname, &st) < 0) {
1181 -               die(MKFS_USAGE, 1, "stat failed: %s", dirname);
1182 -       }
1183 -       fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1184 -       if (fd < 0) {
1185 -               die(MKFS_USAGE, 1, "open failed: %s", outfile);
1186 +               error_msg_and_die("stat failed: %s", dirname);
1187         }
1188 +       fd = xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1189  
1190 -       root_entry = calloc(1, sizeof(struct entry));
1191 -       if (!root_entry) {
1192 -               die(MKFS_ERROR, 1, "calloc failed");
1193 -       }
1194 +       root_entry = xcalloc(1, sizeof(struct entry));
1195         root_entry->mode = st.st_mode;
1196         root_entry->uid = st.st_uid;
1197         root_entry->gid = st.st_gid;
1198  
1199         root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
1200  
1201 +       if (devtable) {
1202 +               parse_device_table(devtable, root_entry, &fslen_ub);
1203 +       }
1204 +
1205         /* always allocate a multiple of blksize bytes because that's
1206 -          what we're going to write later on */
1207 +           what we're going to write later on */
1208         fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
1209  
1210         if (fslen_ub > MAXFSLEN) {
1211 @@ -790,7 +1245,7 @@
1212         rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1213  
1214         if (rom_image == MAP_FAILED) {
1215 -               die(MKFS_ERROR, 1, "mmap failed");
1216 +               error_msg_and_die("mmap failed");
1217         }
1218  
1219         /* Skip the first opt_pad bytes for boot loader code */
1220 @@ -807,6 +1262,7 @@
1221         }
1222  
1223         offset = write_directory_structure(root_entry->child, rom_image, offset);
1224 +       if (opt_verbose)
1225         printf("Directory data: %d bytes\n", offset);
1226  
1227         offset = write_data(root_entry, rom_image, offset);
1228 @@ -814,30 +1270,38 @@
1229         /* We always write a multiple of blksize bytes, so that
1230            losetup works. */
1231         offset = ((offset - 1) | (blksize - 1)) + 1;
1232 +       if (opt_verbose)
1233         printf("Everything: %d kilobytes\n", offset >> 10);
1234  
1235         /* Write the superblock now that we can fill in all of the fields. */
1236         write_superblock(root_entry, rom_image+opt_pad, offset);
1237 +       if (opt_verbose)
1238         printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
1239  
1240         /* Put the checksum in. */
1241         crc = crc32(0L, Z_NULL, 0);
1242         crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
1243         ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
1244 +       if (opt_verbose)
1245         printf("CRC: %x\n", crc);
1246  
1247         /* Check to make sure we allocated enough space. */
1248         if (fslen_ub < offset) {
1249 -               die(MKFS_ERROR, 0, "not enough space allocated for ROM image (%Ld allocated, %d used)", fslen_ub, offset);
1250 +               error_msg_and_die("not enough space allocated for ROM "
1251 +                       "image (%Ld allocated, %d used)", fslen_ub, offset);
1252         }
1253  
1254         written = write(fd, rom_image, offset);
1255         if (written < 0) {
1256 -               die(MKFS_ERROR, 1, "write failed");
1257 +               error_msg_and_die("write failed");
1258         }
1259         if (offset != written) {
1260 -               die(MKFS_ERROR, 0, "ROM image write failed (wrote %d of %d bytes)", written, offset);
1261 +               error_msg_and_die("ROM image write failed (wrote %d of %d bytes)", written, offset);
1262         }
1263 +       
1264 +       /* Free up memory */
1265 +       free_filesystem_entry(root_entry);
1266 +       free(root_entry);
1267  
1268         /* (These warnings used to come at the start, but they scroll off the
1269            screen too quickly.) */