improve helptext of git
[buildroot.git] / target / cramfs / cramfs-01-devtable.patch
blob884eb8cb83c1d48dbc70f2c7cecf8c9a13d422ae
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>
12 +#define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
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 */
25 /* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */
26 @@ -155,7 +156,7 @@
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!");
34 /* find superblock */
35 @@ -190,7 +191,8 @@
36 die(FSCK_UNCORRECTED, 0, "zero file count");
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);
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)
49 - char info[10];
50 + char info[11];
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));
57 else {
58 /* size be as high as 2^24 or 16777216 */
59 @@ -445,8 +447,10 @@
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);
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".
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.
104 +# Have fun
105 +# -Erik Andersen <andersen@codepoet.org>
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 -
127 +# Adjust permissions on some normal files
128 +#/etc/shadow f 600 0 0 - - - - -
129 +#/bin/tinylogin f 4755 0 0 - - - - -
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
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
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
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 -
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 -
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: */
209 * mkcramfs - make a cramfs file system
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
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
220 + * Reworked, cleaned up, and updated for cramfs-1.1, December 2002
221 + * - Erik Andersen <andersen@codepoet.org>
226 * If you change the disk format of cramfs, please update fs/cramfs/README.
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
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 */ )
254 +/* The kernel assumes PAGE_CACHE_SIZE as block size. */
255 +#define PAGE_CACHE_SIZE (4096)
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;
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;
275 static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
276 +static const char *const memory_exhausted = "memory exhausted";
278 /* In-core version of inode / directory entry. */
279 struct entry {
280 @@ -123,7 +148,7 @@
282 FILE *stream = status ? stderr : stdout;
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);
299 exit(status);
302 -static void die(int status, int syserr, const char *fmt, ...)
303 +static void verror_msg(const char *s, va_list p)
305 + fflush(stdout);
306 + fprintf(stderr, "mkcramfs: ");
307 + vfprintf(stderr, s, p);
310 +static void vperror_msg(const char *s, va_list p)
312 + int err = errno;
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));
322 +static void perror_msg(const char *s, ...)
324 + va_list p;
326 + va_start(p, s);
327 + vperror_msg(s, p);
328 + va_end(p);
331 +static void error_msg_and_die(const char *s, ...)
333 + va_list p;
335 + va_start(p, s);
336 + verror_msg(s, p);
337 + va_end(p);
338 + putc('\n', stderr);
339 + exit(MKFS_ERROR);
342 +static void perror_msg_and_die(const char *s, ...)
344 + va_list p;
346 + va_start(p, s);
347 + vperror_msg(s, p);
348 + va_end(p);
349 + exit(MKFS_ERROR);
351 +#ifndef DMALLOC
352 +extern char *xstrdup(const char *s)
354 + char *t;
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;
364 +extern void *xmalloc(size_t size)
366 + void *ptr = malloc(size);
368 + if (ptr == NULL && size != 0)
369 + error_msg_and_die(memory_exhausted);
370 + return ptr;
373 +extern void *xcalloc(size_t nmemb, size_t size)
375 + void *ptr = calloc(nmemb, size);
377 + if (ptr == NULL && nmemb != 0 && size != 0)
378 + error_msg_and_die(memory_exhausted);
379 + return ptr;
382 +extern void *xrealloc(void *ptr, size_t size)
384 + ptr = realloc(ptr, size);
385 + if (ptr == NULL && size != 0)
386 + error_msg_and_die(memory_exhausted);
387 + return ptr;
389 +#endif
391 +static FILE *xfopen(const char *path, const char *mode)
393 - va_list arg_ptr;
394 - int save = errno;
395 + FILE *fp;
397 + if ((fp = fopen(path, mode)) == NULL)
398 + perror_msg_and_die("%s", path);
399 + return fp;
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)
410 + int ret;
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);
419 - fprintf(stderr, "\n");
420 - va_end(arg_ptr);
421 - exit(status);
422 + return ret;
425 +extern char *xreadlink(const char *path)
427 + static const int GROWBY = 80; /* how large we will grow strings by */
429 + char *buf = NULL;
430 + int bufsize = 0, readsize = 0;
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;
439 + }
440 + while (bufsize < readsize + 1);
442 + buf[readsize] = '\0';
444 + return buf;
447 static void map_entry(struct entry *entry)
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);
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);
462 @@ -174,8 +317,9 @@
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);
469 + entry->uncompressed=NULL;
470 close(entry->fd);
473 @@ -204,7 +348,8 @@
474 find_identical_file(orig->next, newfile));
477 -static void eliminate_doubles(struct entry *root, struct entry *orig) {
478 +static void eliminate_doubles(struct entry *root, struct entry *orig)
480 if (orig) {
481 if (orig->size && (orig->path || orig->uncompressed))
482 find_identical_file(root, orig);
483 @@ -232,10 +377,7 @@
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");
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);
498 if (dircount < 0) {
499 - die(MKFS_ERROR, 1, "scandir failed: %s", name);
500 + error_msg_and_die("scandir failed: %s", name);
503 /* process directory */
504 @@ -269,25 +411,20 @@
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);
516 memcpy(endpath, dirent->d_name, namelen + 1);
518 if (lstat(path, &st) < 0) {
519 + perror(endpath);
520 warn_skip = 1;
521 continue;
523 - entry = calloc(1, sizeof(struct entry));
524 - if (!entry) {
525 - die(MKFS_ERROR, 1, "calloc failed");
527 - entry->name = strdup(dirent->d_name);
528 - if (!entry->name) {
529 - die(MKFS_ERROR, 1, "strdup failed");
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");
544 entry->name[namelen] = '\0';
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;
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;
570 - entry->path = strdup(path);
571 - if (!entry->path) {
572 - die(MKFS_ERROR, 1, "strdup failed");
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;
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");
586 - if (readlink(path, entry->uncompressed, entry->size) < 0) {
587 warn_skip = 1;
588 continue;
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);
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;
603 - offset += opt_pad; /* 0 if no padding */
604 + if (opt_pad) {
605 + offset += opt_pad; /* 0 if no padding */
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);
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);
617 if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
618 - die(MKFS_ERROR, 0, "filesystem too big");
619 + error_msg_and_die("filesystem too big");
621 inode->offset = (offset >> 2);
623 @@ -429,7 +563,7 @@
625 static void print_node(struct entry *e)
627 - char info[10];
628 + char info[12];
629 char type = '?';
631 if (S_ISREG(e->mode)) type = 'f';
632 @@ -442,11 +576,11 @@
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));
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);
645 printf("%c %04o %s %5d:%-3d %s\n",
646 @@ -462,17 +596,9 @@
648 int stack_entries = 0;
649 int stack_size = 64;
650 - struct entry **entry_stack;
652 - entry_stack = malloc(stack_size * sizeof(struct entry *));
653 - if (!entry_stack) {
654 - die(MKFS_ERROR, 1, "malloc failed");
657 - if (opt_verbose) {
658 - printf("root:\n");
660 + struct entry **entry_stack = NULL;
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");
674 + entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
676 entry_stack[stack_entries] = entry;
677 stack_entries++;
678 @@ -543,7 +666,7 @@
680 set_data_offset(entry, base, offset);
681 if (opt_verbose) {
682 - printf("%s:\n", entry->name);
683 + printf("'%s':\n", entry->name);
685 entry = entry->child;
687 @@ -553,16 +676,21 @@
689 static int is_zero(char const *begin, unsigned len)
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;
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.
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)
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;
735 - total_blocks += blocks;
736 + total_blocks += blocks;
738 do {
739 unsigned long len = 2 * blksize;
740 unsigned int input = size;
741 - int err;
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));
751 + if (!is_zero (uncompressed, input)) {
752 + compress(base + curr, &len, uncompressed, input);
753 curr += len;
755 uncompressed += input;
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);
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);
776 +#endif
778 return curr;
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);
789 @@ -660,13 +787,10 @@
790 int fd;
791 char *buf;
793 - fd = open(file, O_RDONLY);
794 - if (fd < 0) {
795 - die(MKFS_ERROR, 1, "open failed: %s", file);
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");
803 memcpy(base + offset, buf, image_length);
804 munmap(buf, image_length);
805 @@ -679,6 +803,328 @@
806 return (offset + image_length);
809 +static struct entry *find_filesystem_entry(struct entry *dir, char *name, mode_t type)
811 + struct entry *e = dir;
813 + if (S_ISDIR(dir->mode)) {
814 + e = dir->child;
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);
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);
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;
837 + } else {
838 + if (strcmp(name, e->name) == 0) {
839 + return (e);
843 + e = e->next;
845 + return (NULL);
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)
851 + char *name, *path, *full;
852 + struct entry *curr, *parent, *entry, *prev;
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);
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 */
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);
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);
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");
899 + entry->name[namelen] = '\0';
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;
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);
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;
922 + if (!prev) parent->child = entry;
923 + else prev->next = entry;
924 + entry->next = curr;
925 + entry->child = NULL;
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;
937 + free(path);
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 + */
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, ...)
955 + int ret;
956 + va_list ap;
958 + va_start(ap, fmt);
959 + ret = vsprintf(str, fmt, ap);
960 + va_end(ap);
961 + return ret;
963 +#endif
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 -
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)
976 + I don't bother with symlinks (permissions are irrelevant), hard
977 + links (special cases of regular files), or sockets (why bother).
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.
983 +static int interpret_table_entry(char *line, struct entry *root, loff_t *fslen_ub)
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;
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)
993 + return 1;
996 + if (!strcmp(name, "/")) {
997 + error_msg_and_die("Device table entries require absolute paths");
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;
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);
1027 + } else {
1028 + dev_t rdev = makedev(major, minor);
1029 + modify_entry(name, uid, gid, mode, rdev, root, fslen_ub);
1031 + break;
1032 + default:
1033 + error_msg_and_die("Unsupported file type");
1035 + free(name);
1036 + return 0;
1039 +static int parse_device_table(FILE *file, struct entry *root, loff_t *fslen_ub)
1041 + char *line;
1042 + int status = 0;
1043 + size_t length = 0;
1045 + /* Turn off squash, since we must ensure that values
1046 + * entered via the device table are not squashed */
1047 + opt_squash = 0;
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);
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);
1065 + /* How long are we after trimming? */
1066 + len = strlen(line);
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;
1074 + free(line);
1075 + line = NULL;
1077 + free(line);
1078 + fclose(file);
1080 + return status;
1083 +void traverse(struct entry *entry, int depth)
1085 + struct entry *curr = entry;
1086 + int i;
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;
1098 +static void free_filesystem_entry(struct entry *dir)
1100 + struct entry *e = dir, *last;
1102 + if (S_ISDIR(dir->mode)) {
1103 + e = dir->child;
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);
1116 + e = e->next;
1117 + free(last);
1123 + * Usage:
1125 + * mkcramfs directory-name outfile
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)
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;
1140 total_blocks = 0;
1142 @@ -699,7 +1146,7 @@
1143 progname = argv[0];
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);
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;
1177 @@ -745,25 +1202,23 @@
1178 outfile = argv[optind + 1];
1180 if (stat(dirname, &st) < 0) {
1181 - die(MKFS_USAGE, 1, "stat failed: %s", dirname);
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);
1188 + fd = xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1190 - root_entry = calloc(1, sizeof(struct entry));
1191 - if (!root_entry) {
1192 - die(MKFS_ERROR, 1, "calloc failed");
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;
1199 root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
1201 + if (devtable) {
1202 + parse_device_table(devtable, root_entry, &fslen_ub);
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;
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);
1214 if (rom_image == MAP_FAILED) {
1215 - die(MKFS_ERROR, 1, "mmap failed");
1216 + error_msg_and_die("mmap failed");
1219 /* Skip the first opt_pad bytes for boot loader code */
1220 @@ -807,6 +1262,7 @@
1223 offset = write_directory_structure(root_entry->child, rom_image, offset);
1224 + if (opt_verbose)
1225 printf("Directory data: %d bytes\n", offset);
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);
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));
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);
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);
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");
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);
1264 + /* Free up memory */
1265 + free_filesystem_entry(root_entry);
1266 + free(root_entry);
1268 /* (These warnings used to come at the start, but they scroll off the
1269 screen too quickly.) */