mkfs.jffs2.c 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Build a JFFS2 image in a file, from a given directory tree.
  4. *
  5. * Copyright 2001, 2002 Red Hat, Inc.
  6. * 2001 David A. Schleef <ds@lineo.com>
  7. * 2002 Axis Communications AB
  8. * 2001, 2002 Erik Andersen <andersen@codepoet.org>
  9. * 2004 University of Szeged, Hungary
  10. * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. *
  26. * Cross-endian support added by David Schleef <ds@schleef.org>.
  27. *
  28. * Major architectural rewrite by Erik Andersen <andersen@codepoet.org>
  29. * to allow support for making hard links (though hard links support is
  30. * not yet implemented), and for munging file permissions and ownership
  31. * on the fly using --faketime, --squash, --devtable. And I plugged a
  32. * few memory leaks, adjusted the error handling and fixed some little
  33. * nits here and there.
  34. *
  35. * I also added a sample device table file. See device_table.txt
  36. * -Erik, September 2001
  37. *
  38. * Cleanmarkers support added by Axis Communications AB
  39. *
  40. * Rewritten again. Cleanly separated host and target filsystem
  41. * activities (mainly so I can reuse all the host handling stuff as I
  42. * rewrite other mkfs utils). Added a verbose option to list types
  43. * and attributes as files are added to the file system. Major cleanup
  44. * and scrubbing of the code so it can be read, understood, and
  45. * modified by mere mortals.
  46. *
  47. * -Erik, November 2002
  48. */
  49. #define PROGRAM_NAME "mkfs.jffs2"
  50. #include <sys/types.h>
  51. #include <stdio.h>
  52. #include <sys/stat.h>
  53. #include <unistd.h>
  54. #include <sys/mman.h>
  55. #include <fcntl.h>
  56. #include <dirent.h>
  57. #include <stdlib.h>
  58. #include <errno.h>
  59. #include <string.h>
  60. #include <stdarg.h>
  61. #include <stdint.h>
  62. #include <libgen.h>
  63. #include <ctype.h>
  64. #include <time.h>
  65. #include <getopt.h>
  66. #ifndef WITHOUT_XATTR
  67. #include <sys/xattr.h>
  68. #include <sys/acl.h>
  69. #endif
  70. #include <byteswap.h>
  71. #include <crc32.h>
  72. #include <inttypes.h>
  73. #include <limits.h>
  74. #include "rbtree.h"
  75. #include "common.h"
  76. /* Do not use the weird XPG version of basename */
  77. #undef basename
  78. //#define DMALLOC
  79. //#define mkfs_debug_msg errmsg
  80. #define mkfs_debug_msg(a...) { }
  81. #define PAD(x) (((x)+3)&~3)
  82. struct filesystem_entry {
  83. char *name; /* Name of this directory (think basename) */
  84. char *path; /* Path of this directory (think dirname) */
  85. char *fullname; /* Full name of this directory (i.e. path+name) */
  86. char *hostname; /* Full path to this file on the host filesystem */
  87. uint32_t ino; /* Inode number of this file in JFFS2 */
  88. struct stat sb; /* Stores directory permissions and whatnot */
  89. char *link; /* Target a symlink points to. */
  90. struct filesystem_entry *parent; /* Parent directory */
  91. struct filesystem_entry *prev; /* Only relevant to non-directories */
  92. struct filesystem_entry *next; /* Only relevant to non-directories */
  93. struct filesystem_entry *files; /* Only relevant to directories */
  94. struct rb_node hardlink_rb;
  95. };
  96. struct rb_root hardlinks;
  97. static int out_fd = -1;
  98. static int in_fd = -1;
  99. static char default_rootdir[] = ".";
  100. static char *rootdir = default_rootdir;
  101. static int verbose = 0;
  102. static int squash_uids = 0;
  103. static int squash_perms = 0;
  104. static int fake_times = 0;
  105. int target_endian = __BYTE_ORDER;
  106. static uint32_t find_hardlink(struct filesystem_entry *e)
  107. {
  108. struct filesystem_entry *f;
  109. struct rb_node **n = &hardlinks.rb_node;
  110. struct rb_node *parent = NULL;
  111. while (*n) {
  112. parent = *n;
  113. f = rb_entry(parent, struct filesystem_entry, hardlink_rb);
  114. if ((f->sb.st_dev < e->sb.st_dev) ||
  115. (f->sb.st_dev == e->sb.st_dev &&
  116. f->sb.st_ino < e->sb.st_ino))
  117. n = &parent->rb_left;
  118. else if ((f->sb.st_dev > e->sb.st_dev) ||
  119. (f->sb.st_dev == e->sb.st_dev &&
  120. f->sb.st_ino > e->sb.st_ino)) {
  121. n = &parent->rb_right;
  122. } else
  123. return f->ino;
  124. }
  125. rb_link_node(&e->hardlink_rb, parent, n);
  126. rb_insert_color(&e->hardlink_rb, &hardlinks);
  127. return 0;
  128. }
  129. static char *xreadlink(const char *path)
  130. {
  131. static const int GROWBY = 80; /* how large we will grow strings by */
  132. char *buf = NULL;
  133. int bufsize = 0, readsize = 0;
  134. do {
  135. buf = xrealloc(buf, bufsize += GROWBY);
  136. readsize = readlink(path, buf, bufsize); /* 1st try */
  137. if (readsize == -1) {
  138. sys_errmsg("%s:%s", PROGRAM_NAME, path);
  139. free(buf);
  140. return NULL;
  141. }
  142. }
  143. while (bufsize < readsize + 1);
  144. buf[readsize] = '\0';
  145. return buf;
  146. }
  147. static FILE *xfopen(const char *path, const char *mode)
  148. {
  149. FILE *fp;
  150. if ((fp = fopen(path, mode)) == NULL)
  151. sys_errmsg_die("%s", path);
  152. return fp;
  153. }
  154. static struct filesystem_entry *find_filesystem_entry(
  155. struct filesystem_entry *dir, char *fullname, uint32_t type)
  156. {
  157. struct filesystem_entry *e = dir;
  158. if (S_ISDIR(dir->sb.st_mode)) {
  159. /* If this is the first call, and we actually want this
  160. * directory, then return it now */
  161. if (strcmp(fullname, e->fullname) == 0)
  162. return e;
  163. e = dir->files;
  164. }
  165. while (e) {
  166. if (S_ISDIR(e->sb.st_mode)) {
  167. int len = strlen(e->fullname);
  168. /* Check if we are a parent of the correct path */
  169. if (strncmp(e->fullname, fullname, len) == 0) {
  170. /* Is this an _exact_ match? */
  171. if (strcmp(fullname, e->fullname) == 0) {
  172. return (e);
  173. }
  174. /* Looks like we found a parent of the correct path */
  175. if (fullname[len] == '/') {
  176. if (e->files) {
  177. return (find_filesystem_entry (e, fullname, type));
  178. } else {
  179. return NULL;
  180. }
  181. }
  182. }
  183. } else {
  184. if (strcmp(fullname, e->fullname) == 0) {
  185. return (e);
  186. }
  187. }
  188. e = e->next;
  189. }
  190. return (NULL);
  191. }
  192. static struct filesystem_entry *add_host_filesystem_entry(const char *name,
  193. const char *path, unsigned long uid, unsigned long gid,
  194. unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
  195. {
  196. int status;
  197. char *tmp;
  198. struct stat sb;
  199. time_t timestamp = time(NULL);
  200. struct filesystem_entry *entry;
  201. memset(&sb, 0, sizeof(struct stat));
  202. status = lstat(path, &sb);
  203. if (status >= 0) {
  204. /* It is ok for some types of files to not exit on disk (such as
  205. * device nodes), but if they _do_ exist the specified mode had
  206. * better match the actual file or strange things will happen.... */
  207. if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
  208. errmsg_die ("%s: file type does not match specified type!", path);
  209. }
  210. timestamp = sb.st_mtime;
  211. } else {
  212. /* If this is a regular file, it _must_ exist on disk */
  213. if ((mode & S_IFMT) == S_IFREG) {
  214. errmsg_die("%s: does not exist!", path);
  215. }
  216. }
  217. /* Squash all permissions so files are owned by root, all
  218. * timestamps are _right now_, and file permissions
  219. * have group and other write removed */
  220. if (squash_uids) {
  221. uid = gid = 0;
  222. }
  223. if (squash_perms) {
  224. if (!S_ISLNK(mode)) {
  225. mode &= ~(S_IWGRP | S_IWOTH);
  226. mode &= ~(S_ISUID | S_ISGID);
  227. }
  228. }
  229. if (fake_times) {
  230. timestamp = 0;
  231. }
  232. entry = xcalloc(1, sizeof(struct filesystem_entry));
  233. entry->hostname = xstrdup(path);
  234. entry->fullname = xstrdup(name);
  235. tmp = xstrdup(name);
  236. entry->name = xstrdup(basename(tmp));
  237. free(tmp);
  238. tmp = xstrdup(name);
  239. entry->path = xstrdup(dirname(tmp));
  240. free(tmp);
  241. entry->sb.st_ino = sb.st_ino;
  242. entry->sb.st_dev = sb.st_dev;
  243. entry->sb.st_nlink = sb.st_nlink;
  244. entry->sb.st_uid = uid;
  245. entry->sb.st_gid = gid;
  246. entry->sb.st_mode = mode;
  247. entry->sb.st_rdev = rdev;
  248. entry->sb.st_atime = entry->sb.st_ctime =
  249. entry->sb.st_mtime = timestamp;
  250. if (S_ISREG(mode)) {
  251. entry->sb.st_size = sb.st_size;
  252. }
  253. if (S_ISLNK(mode)) {
  254. entry->link = xreadlink(path);
  255. entry->sb.st_size = strlen(entry->link);
  256. }
  257. /* This happens only for root */
  258. if (!parent)
  259. return (entry);
  260. /* Hook the file into the parent directory */
  261. entry->parent = parent;
  262. if (!parent->files) {
  263. parent->files = entry;
  264. } else {
  265. struct filesystem_entry *prev;
  266. for (prev = parent->files; prev->next; prev = prev->next);
  267. prev->next = entry;
  268. entry->prev = prev;
  269. }
  270. return (entry);
  271. }
  272. static struct filesystem_entry *recursive_add_host_directory(
  273. struct filesystem_entry *parent, const char *targetpath,
  274. const char *hostpath)
  275. {
  276. int i, n;
  277. struct stat sb;
  278. char *hpath, *tpath;
  279. struct dirent *dp, **namelist;
  280. struct filesystem_entry *entry;
  281. if (lstat(hostpath, &sb)) {
  282. sys_errmsg_die("%s", hostpath);
  283. }
  284. entry = add_host_filesystem_entry(targetpath, hostpath,
  285. sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
  286. n = scandir(hostpath, &namelist, 0, alphasort);
  287. if (n < 0) {
  288. sys_errmsg_die("opening directory %s", hostpath);
  289. }
  290. for (i=0; i<n; i++)
  291. {
  292. dp = namelist[i];
  293. if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
  294. (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
  295. {
  296. free(dp);
  297. continue;
  298. }
  299. xasprintf(&hpath, "%s/%s", hostpath, dp->d_name);
  300. if (lstat(hpath, &sb)) {
  301. sys_errmsg_die("%s", hpath);
  302. }
  303. if (strcmp(targetpath, "/") == 0) {
  304. xasprintf(&tpath, "%s%s", targetpath, dp->d_name);
  305. } else {
  306. xasprintf(&tpath, "%s/%s", targetpath, dp->d_name);
  307. }
  308. switch (sb.st_mode & S_IFMT) {
  309. case S_IFDIR:
  310. recursive_add_host_directory(entry, tpath, hpath);
  311. break;
  312. case S_IFREG:
  313. case S_IFSOCK:
  314. case S_IFIFO:
  315. case S_IFLNK:
  316. case S_IFCHR:
  317. case S_IFBLK:
  318. add_host_filesystem_entry(tpath, hpath, sb.st_uid,
  319. sb.st_gid, sb.st_mode, sb.st_rdev, entry);
  320. break;
  321. default:
  322. errmsg("Unknown file type %o for %s", sb.st_mode, hpath);
  323. break;
  324. }
  325. free(dp);
  326. free(hpath);
  327. free(tpath);
  328. }
  329. free(namelist);
  330. return (entry);
  331. }
  332. /* the GNU C library has a wonderful scanf("%as", string) which will
  333. allocate the string with the right size, good to avoid buffer overruns.
  334. the following macros use it if available or use a hacky workaround...
  335. */
  336. #ifdef __GNUC__
  337. #if __STDC_VERSION__ >= 199901L
  338. #define SCANF_PREFIX "m"
  339. #else
  340. #define SCANF_PREFIX "a"
  341. #endif
  342. #define SCANF_STRING(s) (&s)
  343. #define GETCWD_SIZE 0
  344. #else
  345. #define SCANF_PREFIX "511"
  346. #define SCANF_STRING(s) (s = xmalloc(512))
  347. #define GETCWD_SIZE -1
  348. inline int snprintf(char *str, size_t n, const char *fmt, ...)
  349. {
  350. int ret;
  351. va_list ap;
  352. va_start(ap, fmt);
  353. ret = vsprintf(str, fmt, ap);
  354. va_end(ap);
  355. return ret;
  356. }
  357. #endif
  358. /* device table entries take the form of:
  359. <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
  360. /dev/mem c 640 0 0 1 1 0 0 -
  361. type can be one of:
  362. f A regular file
  363. d Directory
  364. c Character special device file
  365. b Block special device file
  366. p Fifo (named pipe)
  367. I don't bother with symlinks (permissions are irrelevant), hard
  368. links (special cases of regular files), or sockets (why bother).
  369. Regular files must exist in the target root directory. If a char,
  370. block, fifo, or directory does not exist, it will be created.
  371. */
  372. static int interpret_table_entry(struct filesystem_entry *root, char *line)
  373. {
  374. char *hostpath;
  375. char type, *name = NULL, *tmp, *dir;
  376. unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
  377. unsigned long start = 0, increment = 1, count = 0;
  378. struct filesystem_entry *parent, *entry;
  379. if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
  380. SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
  381. &start, &increment, &count) < 0)
  382. {
  383. return 1;
  384. }
  385. if (!strcmp(name, "/")) {
  386. errmsg_die("Device table entries require absolute paths");
  387. }
  388. xasprintf(&hostpath, "%s%s", rootdir, name);
  389. /* Check if this file already exists... */
  390. switch (type) {
  391. case 'd':
  392. mode |= S_IFDIR;
  393. break;
  394. case 'f':
  395. mode |= S_IFREG;
  396. break;
  397. case 'p':
  398. mode |= S_IFIFO;
  399. break;
  400. case 'c':
  401. mode |= S_IFCHR;
  402. break;
  403. case 'b':
  404. mode |= S_IFBLK;
  405. break;
  406. case 'l':
  407. mode |= S_IFLNK;
  408. break;
  409. default:
  410. errmsg_die("Unsupported file type '%c'", type);
  411. }
  412. entry = find_filesystem_entry(root, name, mode);
  413. if (entry && !(count > 0 && (type == 'c' || type == 'b'))) {
  414. /* Ok, we just need to fixup the existing entry
  415. * and we will be all done... */
  416. entry->sb.st_uid = uid;
  417. entry->sb.st_gid = gid;
  418. entry->sb.st_mode = mode;
  419. if (major && minor) {
  420. entry->sb.st_rdev = makedev(major, minor);
  421. }
  422. } else {
  423. /* If parent is NULL (happens with device table entries),
  424. * try and find our parent now) */
  425. tmp = xstrdup(name);
  426. dir = dirname(tmp);
  427. parent = find_filesystem_entry(root, dir, S_IFDIR);
  428. free(tmp);
  429. if (parent == NULL) {
  430. errmsg ("skipping device_table entry '%s': no parent directory!", name);
  431. free(name);
  432. free(hostpath);
  433. return 1;
  434. }
  435. switch (type) {
  436. case 'd':
  437. add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
  438. break;
  439. case 'f':
  440. add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
  441. break;
  442. case 'p':
  443. add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
  444. break;
  445. case 'c':
  446. case 'b':
  447. if (count > 0) {
  448. dev_t rdev;
  449. unsigned long i;
  450. char *dname, *hpath;
  451. for (i = start; i < (start + count); i++) {
  452. xasprintf(&dname, "%s%lu", name, i);
  453. xasprintf(&hpath, "%s/%s%lu", rootdir, name, i);
  454. rdev = makedev(major, minor + (i - start) * increment);
  455. add_host_filesystem_entry(dname, hpath, uid, gid,
  456. mode, rdev, parent);
  457. free(dname);
  458. free(hpath);
  459. }
  460. } else {
  461. dev_t rdev = makedev(major, minor);
  462. add_host_filesystem_entry(name, hostpath, uid, gid,
  463. mode, rdev, parent);
  464. }
  465. break;
  466. default:
  467. errmsg_die("Unsupported file type '%c'", type);
  468. }
  469. }
  470. free(name);
  471. free(hostpath);
  472. return 0;
  473. }
  474. static int parse_device_table(struct filesystem_entry *root, FILE * file)
  475. {
  476. char *line;
  477. int status = 0;
  478. size_t length = 0;
  479. /* Turn off squash, since we must ensure that values
  480. * entered via the device table are not squashed */
  481. squash_uids = 0;
  482. squash_perms = 0;
  483. /* Looks ok so far. The general plan now is to read in one
  484. * line at a time, check for leading comment delimiters ('#'),
  485. * then try and parse the line as a device table. If we fail
  486. * to parse things, try and help the poor fool to fix their
  487. * device table with a useful error msg... */
  488. line = NULL;
  489. while (getline(&line, &length, file) != -1) {
  490. /* First trim off any whitespace */
  491. int len = strlen(line);
  492. /* trim trailing whitespace */
  493. while (len > 0 && isspace(line[len - 1]))
  494. line[--len] = '\0';
  495. /* trim leading whitespace */
  496. memmove(line, &line[strspn(line, " \n\r\t\v")], len);
  497. /* How long are we after trimming? */
  498. len = strlen(line);
  499. /* If this is NOT a comment line, try to interpret it */
  500. if (len && *line != '#') {
  501. if (interpret_table_entry(root, line))
  502. status = 1;
  503. }
  504. free(line);
  505. line = NULL;
  506. }
  507. fclose(file);
  508. return status;
  509. }
  510. static void cleanup(struct filesystem_entry *dir)
  511. {
  512. struct filesystem_entry *e, *prev;
  513. e = dir->files;
  514. while (e) {
  515. if (e->name)
  516. free(e->name);
  517. if (e->path)
  518. free(e->path);
  519. if (e->fullname)
  520. free(e->fullname);
  521. e->next = NULL;
  522. e->name = NULL;
  523. e->path = NULL;
  524. e->fullname = NULL;
  525. e->prev = NULL;
  526. prev = e;
  527. if (S_ISDIR(e->sb.st_mode)) {
  528. cleanup(e);
  529. }
  530. e = e->next;
  531. free(prev);
  532. }
  533. }
  534. /* Here is where we do the actual creation of the file system */
  535. #include "mtd/jffs2-user.h"
  536. #define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
  537. #ifndef JFFS2_MAX_SYMLINK_LEN
  538. #define JFFS2_MAX_SYMLINK_LEN 254
  539. #endif
  540. static uint32_t ino = 0;
  541. static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
  542. static int out_ofs = 0;
  543. static int erase_block_size = 65536;
  544. static int pad_fs_size = 0;
  545. static int add_cleanmarkers = 1;
  546. static struct jffs2_unknown_node cleanmarker;
  547. static int cleanmarker_size = sizeof(cleanmarker);
  548. static unsigned char ffbuf[16] =
  549. { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  550. 0xff, 0xff, 0xff, 0xff, 0xff
  551. };
  552. /* We set this at start of main() using sysconf(), -1 means we don't know */
  553. /* When building an fs for non-native systems, use --pagesize=SIZE option */
  554. int page_size = -1;
  555. #include "compr.h"
  556. static void full_write(int fd, const void *buf, int len)
  557. {
  558. int ret;
  559. while (len > 0) {
  560. ret = write(fd, buf, len);
  561. if (ret < 0)
  562. sys_errmsg_die("write");
  563. if (ret == 0)
  564. sys_errmsg_die("write returned zero");
  565. len -= ret;
  566. buf += ret;
  567. out_ofs += ret;
  568. }
  569. }
  570. static void padblock(void)
  571. {
  572. while (out_ofs % erase_block_size) {
  573. full_write(out_fd, ffbuf, min(sizeof(ffbuf),
  574. erase_block_size - (out_ofs % erase_block_size)));
  575. }
  576. }
  577. static void pad(int req)
  578. {
  579. while (req) {
  580. if (req > sizeof(ffbuf)) {
  581. full_write(out_fd, ffbuf, sizeof(ffbuf));
  582. req -= sizeof(ffbuf);
  583. } else {
  584. full_write(out_fd, ffbuf, req);
  585. req = 0;
  586. }
  587. }
  588. }
  589. static inline void padword(void)
  590. {
  591. if (out_ofs % 4) {
  592. full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
  593. }
  594. }
  595. static inline void pad_block_if_less_than(int req)
  596. {
  597. if (add_cleanmarkers) {
  598. if ((out_ofs % erase_block_size) == 0) {
  599. full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
  600. pad(cleanmarker_size - sizeof(cleanmarker));
  601. padword();
  602. }
  603. }
  604. if ((out_ofs % erase_block_size) + req > erase_block_size) {
  605. padblock();
  606. }
  607. if (add_cleanmarkers) {
  608. if ((out_ofs % erase_block_size) == 0) {
  609. full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
  610. pad(cleanmarker_size - sizeof(cleanmarker));
  611. padword();
  612. }
  613. }
  614. }
  615. static void write_dirent(struct filesystem_entry *e)
  616. {
  617. char *name = e->name;
  618. struct jffs2_raw_dirent rd;
  619. struct stat *statbuf = &(e->sb);
  620. static uint32_t version = 0;
  621. memset(&rd, 0, sizeof(rd));
  622. rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  623. rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
  624. rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
  625. rd.hdr_crc = cpu_to_je32(mtd_crc32(0, &rd,
  626. sizeof(struct jffs2_unknown_node) - 4));
  627. rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1);
  628. rd.version = cpu_to_je32(version++);
  629. rd.ino = cpu_to_je32(e->ino);
  630. rd.mctime = cpu_to_je32(statbuf->st_mtime);
  631. rd.nsize = strlen(name);
  632. rd.type = IFTODT(statbuf->st_mode);
  633. //rd.unused[0] = 0;
  634. //rd.unused[1] = 0;
  635. rd.node_crc = cpu_to_je32(mtd_crc32(0, &rd, sizeof(rd) - 8));
  636. rd.name_crc = cpu_to_je32(mtd_crc32(0, name, strlen(name)));
  637. pad_block_if_less_than(sizeof(rd) + rd.nsize);
  638. full_write(out_fd, &rd, sizeof(rd));
  639. full_write(out_fd, name, rd.nsize);
  640. padword();
  641. }
  642. static unsigned int write_regular_file(struct filesystem_entry *e)
  643. {
  644. int fd, len;
  645. uint32_t ver;
  646. unsigned int offset;
  647. unsigned char *buf, *cbuf, *wbuf;
  648. struct jffs2_raw_inode ri;
  649. struct stat *statbuf;
  650. unsigned int totcomp = 0;
  651. statbuf = &(e->sb);
  652. if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
  653. errmsg("Skipping file \"%s\" too large.", e->path);
  654. return -1;
  655. }
  656. fd = open(e->hostname, O_RDONLY);
  657. if (fd == -1) {
  658. sys_errmsg_die("%s: open file", e->hostname);
  659. }
  660. e->ino = ++ino;
  661. mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu",
  662. e->name, (unsigned long) e->ino,
  663. (unsigned long) e->parent->ino);
  664. write_dirent(e);
  665. buf = xmalloc(page_size);
  666. cbuf = NULL;
  667. ver = 0;
  668. offset = 0;
  669. memset(&ri, 0, sizeof(ri));
  670. ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  671. ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
  672. ri.ino = cpu_to_je32(e->ino);
  673. ri.mode = cpu_to_jemode(statbuf->st_mode);
  674. ri.uid = cpu_to_je16(statbuf->st_uid);
  675. ri.gid = cpu_to_je16(statbuf->st_gid);
  676. ri.atime = cpu_to_je32(statbuf->st_atime);
  677. ri.ctime = cpu_to_je32(statbuf->st_ctime);
  678. ri.mtime = cpu_to_je32(statbuf->st_mtime);
  679. ri.isize = cpu_to_je32(statbuf->st_size);
  680. while ((len = read(fd, buf, page_size))) {
  681. unsigned char *tbuf = buf;
  682. if (len < 0) {
  683. sys_errmsg_die("read");
  684. }
  685. while (len) {
  686. uint32_t dsize, space;
  687. uint16_t compression;
  688. pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
  689. dsize = len;
  690. space =
  691. erase_block_size - (out_ofs % erase_block_size) -
  692. sizeof(ri);
  693. if (space > dsize)
  694. space = dsize;
  695. compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
  696. ri.compr = compression & 0xff;
  697. ri.usercompr = (compression >> 8) & 0xff;
  698. if (ri.compr) {
  699. wbuf = cbuf;
  700. } else {
  701. wbuf = tbuf;
  702. dsize = space;
  703. }
  704. ri.totlen = cpu_to_je32(sizeof(ri) + space);
  705. ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
  706. &ri, sizeof(struct jffs2_unknown_node) - 4));
  707. ri.version = cpu_to_je32(++ver);
  708. ri.offset = cpu_to_je32(offset);
  709. ri.csize = cpu_to_je32(space);
  710. ri.dsize = cpu_to_je32(dsize);
  711. ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
  712. ri.data_crc = cpu_to_je32(mtd_crc32(0, wbuf, space));
  713. full_write(out_fd, &ri, sizeof(ri));
  714. totcomp += sizeof(ri);
  715. full_write(out_fd, wbuf, space);
  716. totcomp += space;
  717. padword();
  718. if (tbuf != cbuf) {
  719. free(cbuf);
  720. cbuf = NULL;
  721. }
  722. tbuf += dsize;
  723. len -= dsize;
  724. offset += dsize;
  725. }
  726. }
  727. if (!je32_to_cpu(ri.version)) {
  728. /* Was empty file */
  729. pad_block_if_less_than(sizeof(ri));
  730. ri.version = cpu_to_je32(++ver);
  731. ri.totlen = cpu_to_je32(sizeof(ri));
  732. ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
  733. &ri, sizeof(struct jffs2_unknown_node) - 4));
  734. ri.csize = cpu_to_je32(0);
  735. ri.dsize = cpu_to_je32(0);
  736. ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
  737. full_write(out_fd, &ri, sizeof(ri));
  738. padword();
  739. }
  740. free(buf);
  741. close(fd);
  742. return totcomp;
  743. }
  744. static void write_symlink(struct filesystem_entry *e)
  745. {
  746. int len;
  747. struct stat *statbuf;
  748. struct jffs2_raw_inode ri;
  749. statbuf = &(e->sb);
  750. e->ino = ++ino;
  751. mkfs_debug_msg("writing symlink '%s' ino=%lu parent_ino=%lu",
  752. e->name, (unsigned long) e->ino,
  753. (unsigned long) e->parent->ino);
  754. write_dirent(e);
  755. len = strlen(e->link);
  756. if (len > JFFS2_MAX_SYMLINK_LEN) {
  757. errmsg("symlink too large. Truncated to %d chars.",
  758. JFFS2_MAX_SYMLINK_LEN);
  759. len = JFFS2_MAX_SYMLINK_LEN;
  760. }
  761. memset(&ri, 0, sizeof(ri));
  762. ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  763. ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
  764. ri.totlen = cpu_to_je32(sizeof(ri) + len);
  765. ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
  766. &ri, sizeof(struct jffs2_unknown_node) - 4));
  767. ri.ino = cpu_to_je32(e->ino);
  768. ri.mode = cpu_to_jemode(statbuf->st_mode);
  769. ri.uid = cpu_to_je16(statbuf->st_uid);
  770. ri.gid = cpu_to_je16(statbuf->st_gid);
  771. ri.atime = cpu_to_je32(statbuf->st_atime);
  772. ri.ctime = cpu_to_je32(statbuf->st_ctime);
  773. ri.mtime = cpu_to_je32(statbuf->st_mtime);
  774. ri.isize = cpu_to_je32(statbuf->st_size);
  775. ri.version = cpu_to_je32(1);
  776. ri.csize = cpu_to_je32(len);
  777. ri.dsize = cpu_to_je32(len);
  778. ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
  779. ri.data_crc = cpu_to_je32(mtd_crc32(0, e->link, len));
  780. pad_block_if_less_than(sizeof(ri) + len);
  781. full_write(out_fd, &ri, sizeof(ri));
  782. full_write(out_fd, e->link, len);
  783. padword();
  784. }
  785. static void write_pipe(struct filesystem_entry *e)
  786. {
  787. struct stat *statbuf;
  788. struct jffs2_raw_inode ri;
  789. statbuf = &(e->sb);
  790. e->ino = ++ino;
  791. if (S_ISDIR(statbuf->st_mode)) {
  792. mkfs_debug_msg("writing dir '%s' ino=%lu parent_ino=%lu",
  793. e->name, (unsigned long) e->ino,
  794. (unsigned long) (e->parent) ? e->parent->ino : 1);
  795. }
  796. write_dirent(e);
  797. memset(&ri, 0, sizeof(ri));
  798. ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  799. ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
  800. ri.totlen = cpu_to_je32(sizeof(ri));
  801. ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
  802. &ri, sizeof(struct jffs2_unknown_node) - 4));
  803. ri.ino = cpu_to_je32(e->ino);
  804. ri.mode = cpu_to_jemode(statbuf->st_mode);
  805. ri.uid = cpu_to_je16(statbuf->st_uid);
  806. ri.gid = cpu_to_je16(statbuf->st_gid);
  807. ri.atime = cpu_to_je32(statbuf->st_atime);
  808. ri.ctime = cpu_to_je32(statbuf->st_ctime);
  809. ri.mtime = cpu_to_je32(statbuf->st_mtime);
  810. ri.isize = cpu_to_je32(0);
  811. ri.version = cpu_to_je32(1);
  812. ri.csize = cpu_to_je32(0);
  813. ri.dsize = cpu_to_je32(0);
  814. ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
  815. ri.data_crc = cpu_to_je32(0);
  816. pad_block_if_less_than(sizeof(ri));
  817. full_write(out_fd, &ri, sizeof(ri));
  818. padword();
  819. }
  820. static void write_special_file(struct filesystem_entry *e)
  821. {
  822. jint16_t kdev;
  823. struct stat *statbuf;
  824. struct jffs2_raw_inode ri;
  825. statbuf = &(e->sb);
  826. e->ino = ++ino;
  827. write_dirent(e);
  828. kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
  829. minor(statbuf->st_rdev));
  830. memset(&ri, 0, sizeof(ri));
  831. ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  832. ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
  833. ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
  834. ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
  835. &ri, sizeof(struct jffs2_unknown_node) - 4));
  836. ri.ino = cpu_to_je32(e->ino);
  837. ri.mode = cpu_to_jemode(statbuf->st_mode);
  838. ri.uid = cpu_to_je16(statbuf->st_uid);
  839. ri.gid = cpu_to_je16(statbuf->st_gid);
  840. ri.atime = cpu_to_je32(statbuf->st_atime);
  841. ri.ctime = cpu_to_je32(statbuf->st_ctime);
  842. ri.mtime = cpu_to_je32(statbuf->st_mtime);
  843. ri.isize = cpu_to_je32(statbuf->st_size);
  844. ri.version = cpu_to_je32(1);
  845. ri.csize = cpu_to_je32(sizeof(kdev));
  846. ri.dsize = cpu_to_je32(sizeof(kdev));
  847. ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
  848. ri.data_crc = cpu_to_je32(mtd_crc32(0, &kdev, sizeof(kdev)));
  849. pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
  850. full_write(out_fd, &ri, sizeof(ri));
  851. full_write(out_fd, &kdev, sizeof(kdev));
  852. padword();
  853. }
  854. #ifndef WITHOUT_XATTR
  855. typedef struct xattr_entry {
  856. struct xattr_entry *next;
  857. uint32_t xid;
  858. int xprefix;
  859. char *xname;
  860. char *xvalue;
  861. int name_len;
  862. int value_len;
  863. } xattr_entry_t;
  864. #define XATTR_BUFFER_SIZE (64 * 1024) /* 64KB */
  865. static uint32_t enable_xattr = 0;
  866. static uint32_t highest_xid = 0;
  867. static uint32_t highest_xseqno = 0;
  868. static struct {
  869. int xprefix;
  870. const char *string;
  871. int length;
  872. } xprefix_tbl[] = {
  873. { JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
  874. { JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
  875. { JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
  876. { JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
  877. { JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
  878. { 0, NULL, 0 }
  879. };
  880. static void formalize_posix_acl(void *xvalue, int *value_len)
  881. {
  882. struct posix_acl_xattr_header *pacl_header;
  883. struct posix_acl_xattr_entry *pent, *plim;
  884. struct jffs2_acl_header *jacl_header;
  885. struct jffs2_acl_entry *jent;
  886. struct jffs2_acl_entry_short *jent_s;
  887. char buffer[XATTR_BUFFER_SIZE];
  888. int offset = 0;
  889. pacl_header = xvalue;;
  890. pent = pacl_header->a_entries;
  891. plim = xvalue + *value_len;
  892. jacl_header = (struct jffs2_acl_header *)buffer;
  893. offset += sizeof(struct jffs2_acl_header);
  894. jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
  895. while (pent < plim) {
  896. switch(le16_to_cpu(pent->e_tag)) {
  897. case ACL_USER_OBJ:
  898. case ACL_GROUP_OBJ:
  899. case ACL_MASK:
  900. case ACL_OTHER:
  901. jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
  902. offset += sizeof(struct jffs2_acl_entry_short);
  903. jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
  904. jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
  905. break;
  906. case ACL_USER:
  907. case ACL_GROUP:
  908. jent = (struct jffs2_acl_entry *)(buffer + offset);
  909. offset += sizeof(struct jffs2_acl_entry);
  910. jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
  911. jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
  912. jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
  913. break;
  914. default:
  915. printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
  916. exit(1);
  917. }
  918. pent++;
  919. }
  920. if (offset > *value_len) {
  921. printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
  922. offset, *value_len);
  923. exit(EXIT_FAILURE);
  924. }
  925. memcpy(xvalue, buffer, offset);
  926. *value_len = offset;
  927. }
  928. static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
  929. {
  930. xattr_entry_t *xe;
  931. struct jffs2_raw_xattr rx;
  932. int name_len;
  933. /* create xattr entry */
  934. name_len = strlen(xname);
  935. xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
  936. xe->next = NULL;
  937. xe->xid = ++highest_xid;
  938. xe->xprefix = xprefix;
  939. xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
  940. xe->xvalue = xe->xname + name_len + 1;
  941. xe->name_len = name_len;
  942. xe->value_len = value_len;
  943. strcpy(xe->xname, xname);
  944. memcpy(xe->xvalue, xvalue, value_len);
  945. /* write xattr node */
  946. memset(&rx, 0, sizeof(rx));
  947. rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  948. rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
  949. rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
  950. rx.hdr_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
  951. rx.xid = cpu_to_je32(xe->xid);
  952. rx.version = cpu_to_je32(1); /* initial version */
  953. rx.xprefix = xprefix;
  954. rx.name_len = xe->name_len;
  955. rx.value_len = cpu_to_je16(xe->value_len);
  956. rx.data_crc = cpu_to_je32(mtd_crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
  957. rx.node_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(rx) - 4));
  958. pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
  959. full_write(out_fd, &rx, sizeof(rx));
  960. full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
  961. padword();
  962. return xe;
  963. }
  964. #define XATTRENTRY_HASHSIZE 57
  965. static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
  966. {
  967. static xattr_entry_t **xentry_hash = NULL;
  968. xattr_entry_t *xe;
  969. int index, name_len;
  970. /* create hash table */
  971. if (!xentry_hash)
  972. xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
  973. if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
  974. || xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
  975. formalize_posix_acl(xvalue, &value_len);
  976. name_len = strlen(xname);
  977. index = (mtd_crc32(0, xname, name_len) ^ mtd_crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
  978. for (xe = xentry_hash[index]; xe; xe = xe->next) {
  979. if (xe->xprefix == xprefix
  980. && xe->value_len == value_len
  981. && !strcmp(xe->xname, xname)
  982. && !memcmp(xe->xvalue, xvalue, value_len))
  983. break;
  984. }
  985. if (!xe) {
  986. xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
  987. xe->next = xentry_hash[index];
  988. xentry_hash[index] = xe;
  989. }
  990. return xe;
  991. }
  992. static void write_xattr_entry(struct filesystem_entry *e)
  993. {
  994. struct jffs2_raw_xref ref;
  995. struct xattr_entry *xe;
  996. char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
  997. char *xname;
  998. const char *prefix_str;
  999. int i, xprefix, prefix_len;
  1000. int list_sz, offset, name_len, value_len;
  1001. if (!enable_xattr)
  1002. return;
  1003. list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
  1004. if (list_sz < 0) {
  1005. if (verbose)
  1006. printf("llistxattr('%s') = %d : %s\n",
  1007. e->hostname, errno, strerror(errno));
  1008. return;
  1009. }
  1010. for (offset = 0; offset < list_sz; offset += name_len) {
  1011. xname = xlist + offset;
  1012. name_len = strlen(xname) + 1;
  1013. for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
  1014. prefix_str = xprefix_tbl[i].string;
  1015. prefix_len = xprefix_tbl[i].length;
  1016. if (prefix_str[prefix_len - 1] == '.') {
  1017. if (!strncmp(xname, prefix_str, prefix_len - 1))
  1018. break;
  1019. } else {
  1020. if (!strcmp(xname, prefix_str))
  1021. break;
  1022. }
  1023. }
  1024. if (!xprefix) {
  1025. if (verbose)
  1026. printf("%s: xattr '%s' is not supported.\n",
  1027. e->hostname, xname);
  1028. continue;
  1029. }
  1030. if ((enable_xattr & (1 << xprefix)) == 0)
  1031. continue;
  1032. value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
  1033. if (value_len < 0) {
  1034. if (verbose)
  1035. printf("lgetxattr('%s', '%s') = %d : %s\n",
  1036. e->hostname, xname, errno, strerror(errno));
  1037. continue;
  1038. }
  1039. xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
  1040. if (!xe) {
  1041. if (verbose)
  1042. printf("%s : xattr '%s' was ignored.\n",
  1043. e->hostname, xname);
  1044. continue;
  1045. }
  1046. memset(&ref, 0, sizeof(ref));
  1047. ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  1048. ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
  1049. ref.totlen = cpu_to_je32(sizeof(ref));
  1050. ref.hdr_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
  1051. ref.ino = cpu_to_je32(e->ino);
  1052. ref.xid = cpu_to_je32(xe->xid);
  1053. ref.xseqno = cpu_to_je32(highest_xseqno += 2);
  1054. ref.node_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(ref) - 4));
  1055. pad_block_if_less_than(sizeof(ref));
  1056. full_write(out_fd, &ref, sizeof(ref));
  1057. padword();
  1058. }
  1059. }
  1060. #else /* WITHOUT_XATTR */
  1061. #define write_xattr_entry(x)
  1062. #endif
  1063. static void recursive_populate_directory(struct filesystem_entry *dir)
  1064. {
  1065. struct filesystem_entry *e;
  1066. unsigned int wrote;
  1067. if (verbose) {
  1068. printf("%s\n", dir->fullname);
  1069. }
  1070. write_xattr_entry(dir); /* for '/' */
  1071. e = dir->files;
  1072. while (e) {
  1073. if (e->sb.st_nlink >= 1 &&
  1074. (e->ino = find_hardlink(e))) {
  1075. write_dirent(e);
  1076. if (verbose) {
  1077. printf("\tL %04o %9lu %5d:%-3d %s\n",
  1078. e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino,
  1079. (int) (e->sb.st_uid), (int) (e->sb.st_gid),
  1080. e->name);
  1081. }
  1082. } else switch (e->sb.st_mode & S_IFMT) {
  1083. case S_IFDIR:
  1084. if (verbose) {
  1085. printf("\td %04o %9lld %5d:%-3d %s\n",
  1086. e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
  1087. (int) (e->sb.st_uid), (int) (e->sb.st_gid),
  1088. e->name);
  1089. }
  1090. write_pipe(e);
  1091. write_xattr_entry(e);
  1092. break;
  1093. case S_IFSOCK:
  1094. if (verbose) {
  1095. printf("\ts %04o %9lld %5d:%-3d %s\n",
  1096. e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
  1097. (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
  1098. }
  1099. write_pipe(e);
  1100. write_xattr_entry(e);
  1101. break;
  1102. case S_IFIFO:
  1103. if (verbose) {
  1104. printf("\tp %04o %9lld %5d:%-3d %s\n",
  1105. e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
  1106. (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
  1107. }
  1108. write_pipe(e);
  1109. write_xattr_entry(e);
  1110. break;
  1111. case S_IFCHR:
  1112. if (verbose) {
  1113. printf("\tc %04o %4d,%4d %5d:%-3d %s\n",
  1114. e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
  1115. minor(e->sb.st_rdev), (int) e->sb.st_uid,
  1116. (int) e->sb.st_gid, e->name);
  1117. }
  1118. write_special_file(e);
  1119. write_xattr_entry(e);
  1120. break;
  1121. case S_IFBLK:
  1122. if (verbose) {
  1123. printf("\tb %04o %4d,%4d %5d:%-3d %s\n",
  1124. e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
  1125. minor(e->sb.st_rdev), (int) e->sb.st_uid,
  1126. (int) e->sb.st_gid, e->name);
  1127. }
  1128. write_special_file(e);
  1129. write_xattr_entry(e);
  1130. break;
  1131. case S_IFLNK:
  1132. if (verbose) {
  1133. printf("\tl %04o %9lld %5d:%-3d %s -> %s\n",
  1134. e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
  1135. (int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
  1136. e->link);
  1137. }
  1138. write_symlink(e);
  1139. write_xattr_entry(e);
  1140. break;
  1141. case S_IFREG:
  1142. wrote = write_regular_file(e);
  1143. write_xattr_entry(e);
  1144. if (verbose) {
  1145. printf("\tf %04o %9lld (%9u) %5d:%-3d %s\n",
  1146. e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size, wrote,
  1147. (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
  1148. }
  1149. break;
  1150. default:
  1151. errmsg("Unknown mode %o for %s", e->sb.st_mode,
  1152. e->fullname);
  1153. break;
  1154. }
  1155. e = e->next;
  1156. }
  1157. e = dir->files;
  1158. while (e) {
  1159. if (S_ISDIR(e->sb.st_mode)) {
  1160. if (e->files) {
  1161. recursive_populate_directory(e);
  1162. } else if (verbose) {
  1163. printf("%s\n", e->fullname);
  1164. }
  1165. }
  1166. e = e->next;
  1167. }
  1168. }
  1169. static void create_target_filesystem(struct filesystem_entry *root)
  1170. {
  1171. cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  1172. cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
  1173. cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
  1174. cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
  1175. if (ino == 0)
  1176. ino = 1;
  1177. root->ino = 1;
  1178. recursive_populate_directory(root);
  1179. if (pad_fs_size == -1) {
  1180. padblock();
  1181. } else {
  1182. if (pad_fs_size && add_cleanmarkers){
  1183. padblock();
  1184. while (out_ofs < pad_fs_size) {
  1185. full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
  1186. pad(cleanmarker_size - sizeof(cleanmarker));
  1187. padblock();
  1188. }
  1189. } else {
  1190. while (out_ofs < pad_fs_size) {
  1191. full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
  1192. }
  1193. }
  1194. }
  1195. }
  1196. static struct option long_options[] = {
  1197. {"pad", 2, NULL, 'p'},
  1198. {"root", 1, NULL, 'r'},
  1199. {"pagesize", 1, NULL, 's'},
  1200. {"eraseblock", 1, NULL, 'e'},
  1201. {"output", 1, NULL, 'o'},
  1202. {"help", 0, NULL, 'h'},
  1203. {"verbose", 0, NULL, 'v'},
  1204. {"version", 0, NULL, 'V'},
  1205. {"big-endian", 0, NULL, 'b'},
  1206. {"little-endian", 0, NULL, 'l'},
  1207. {"no-cleanmarkers", 0, NULL, 'n'},
  1208. {"cleanmarker", 1, NULL, 'c'},
  1209. {"squash", 0, NULL, 'q'},
  1210. {"squash-uids", 0, NULL, 'U'},
  1211. {"squash-perms", 0, NULL, 'P'},
  1212. {"faketime", 0, NULL, 'f'},
  1213. {"devtable", 1, NULL, 'D'},
  1214. {"compression-mode", 1, NULL, 'm'},
  1215. {"disable-compressor", 1, NULL, 'x'},
  1216. {"enable-compressor", 1, NULL, 'X'},
  1217. {"test-compression", 0, NULL, 't'},
  1218. {"compressor-priority", 1, NULL, 'y'},
  1219. {"incremental", 1, NULL, 'i'},
  1220. #ifndef WITHOUT_XATTR
  1221. {"with-xattr", 0, NULL, 1000 },
  1222. {"with-selinux", 0, NULL, 1001 },
  1223. {"with-posix-acl", 0, NULL, 1002 },
  1224. #endif
  1225. {NULL, 0, NULL, 0}
  1226. };
  1227. static const char helptext[] =
  1228. "Usage: mkfs.jffs2 [OPTIONS]\n"
  1229. "Make a JFFS2 file system image from an existing directory tree\n\n"
  1230. "Options:\n"
  1231. " -p, --pad[=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is\n"
  1232. " not specified, the output is padded to the end of\n"
  1233. " the final erase block\n"
  1234. " -r, -d, --root=DIR Build file system from directory DIR (default: cwd)\n"
  1235. " -s, --pagesize=SIZE Use page size (max data node size) SIZE.\n"
  1236. " Set according to target system's memory management\n"
  1237. " page size (default: 4KiB)\n"
  1238. " -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
  1239. " -c, --cleanmarker=SIZE Size of cleanmarker (default 12)\n"
  1240. " -m, --compr-mode=MODE Select compression mode (default: priority)\n"
  1241. " -x, --disable-compressor=COMPRESSOR_NAME\n"
  1242. " Disable a compressor\n"
  1243. " -X, --enable-compressor=COMPRESSOR_NAME\n"
  1244. " Enable a compressor\n"
  1245. " -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
  1246. " Set the priority of a compressor\n"
  1247. " -L, --list-compressors Show the list of the available compressors\n"
  1248. " -t, --test-compression Call decompress and compare with the original (for test)\n"
  1249. " -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
  1250. " -o, --output=FILE Output to FILE (default: stdout)\n"
  1251. " -l, --little-endian Create a little-endian filesystem\n"
  1252. " -b, --big-endian Create a big-endian filesystem\n"
  1253. " -D, --devtable=FILE Use the named FILE as a device table file\n"
  1254. " -f, --faketime Change all file times to '0' for regression testing\n"
  1255. " -q, --squash Squash permissions and owners making all files be owned by root\n"
  1256. " -U, --squash-uids Squash owners making all files be owned by root\n"
  1257. " -P, --squash-perms Squash permissions on all files\n"
  1258. #ifndef WITHOUT_XATTR
  1259. " --with-xattr stuff all xattr entries into image\n"
  1260. " --with-selinux stuff only SELinux Labels into jffs2 image\n"
  1261. " --with-posix-acl stuff only POSIX ACL entries into jffs2 image\n"
  1262. #endif
  1263. " -h, --help Display this help text\n"
  1264. " -v, --verbose Verbose operation\n"
  1265. " -V, --version Display version information\n"
  1266. " -i, --incremental=FILE Parse FILE and generate appendage output for it\n\n";
  1267. static int load_next_block(void) {
  1268. int ret;
  1269. ret = read(in_fd, file_buffer, erase_block_size);
  1270. if(verbose)
  1271. printf("Load next block : %d bytes read\n",ret);
  1272. return ret;
  1273. }
  1274. static void process_buffer(int inp_size) {
  1275. uint8_t *p = file_buffer;
  1276. union jffs2_node_union *node;
  1277. uint16_t type;
  1278. int bitchbitmask = 0;
  1279. int obsolete;
  1280. char name[256];
  1281. while ( p < (file_buffer + inp_size)) {
  1282. node = (union jffs2_node_union *) p;
  1283. /* Skip empty space */
  1284. if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
  1285. p += 4;
  1286. continue;
  1287. }
  1288. if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
  1289. if (!bitchbitmask++)
  1290. printf ("Wrong bitmask at 0x%08zx, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
  1291. p += 4;
  1292. continue;
  1293. }
  1294. bitchbitmask = 0;
  1295. type = je16_to_cpu(node->u.nodetype);
  1296. if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
  1297. obsolete = 1;
  1298. type |= JFFS2_NODE_ACCURATE;
  1299. } else
  1300. obsolete = 0;
  1301. node->u.nodetype = cpu_to_je16(type);
  1302. switch(je16_to_cpu(node->u.nodetype)) {
  1303. case JFFS2_NODETYPE_INODE:
  1304. if(verbose)
  1305. printf ("%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
  1306. obsolete ? "Obsolete" : "",
  1307. p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
  1308. je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
  1309. je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
  1310. if ( je32_to_cpu (node->i.ino) > ino )
  1311. ino = je32_to_cpu (node->i.ino);
  1312. p += PAD(je32_to_cpu (node->i.totlen));
  1313. break;
  1314. case JFFS2_NODETYPE_DIRENT:
  1315. memcpy (name, node->d.name, node->d.nsize);
  1316. name [node->d.nsize] = 0x0;
  1317. if(verbose)
  1318. printf ("%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
  1319. obsolete ? "Obsolete" : "",
  1320. p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
  1321. je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
  1322. node->d.nsize, name);
  1323. p += PAD(je32_to_cpu (node->d.totlen));
  1324. break;
  1325. case JFFS2_NODETYPE_CLEANMARKER:
  1326. if (verbose) {
  1327. printf ("%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
  1328. obsolete ? "Obsolete" : "",
  1329. p - file_buffer, je32_to_cpu (node->u.totlen));
  1330. }
  1331. p += PAD(je32_to_cpu (node->u.totlen));
  1332. break;
  1333. case JFFS2_NODETYPE_PADDING:
  1334. if (verbose) {
  1335. printf ("%8s Padding node at 0x%08zx, totlen 0x%08x\n",
  1336. obsolete ? "Obsolete" : "",
  1337. p - file_buffer, je32_to_cpu (node->u.totlen));
  1338. }
  1339. p += PAD(je32_to_cpu (node->u.totlen));
  1340. break;
  1341. case 0xffff:
  1342. p += 4;
  1343. break;
  1344. default:
  1345. if (verbose) {
  1346. printf ("%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
  1347. obsolete ? "Obsolete" : "",
  1348. p - file_buffer, je32_to_cpu (node->u.totlen));
  1349. }
  1350. p += PAD(je32_to_cpu (node->u.totlen));
  1351. }
  1352. }
  1353. }
  1354. static void parse_image(void){
  1355. int ret;
  1356. file_buffer = xmalloc(erase_block_size);
  1357. while ((ret = load_next_block())) {
  1358. process_buffer(ret);
  1359. }
  1360. if (file_buffer)
  1361. free(file_buffer);
  1362. close(in_fd);
  1363. }
  1364. int main(int argc, char **argv)
  1365. {
  1366. int c, opt;
  1367. char *cwd;
  1368. struct stat sb;
  1369. FILE *devtable = NULL;
  1370. struct filesystem_entry *root;
  1371. char *compr_name = NULL;
  1372. int compr_prior = -1;
  1373. int warn_page_size = 0;
  1374. page_size = sysconf(_SC_PAGESIZE);
  1375. if (page_size < 0) /* System doesn't know so ... */
  1376. page_size = 4096; /* ... we make an educated guess */
  1377. if (page_size != 4096)
  1378. warn_page_size = 1; /* warn user if page size not 4096 */
  1379. jffs2_compressors_init();
  1380. while ((opt = getopt_long(argc, argv,
  1381. "D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
  1382. {
  1383. switch (opt) {
  1384. case 'D':
  1385. devtable = xfopen(optarg, "r");
  1386. if (fstat(fileno(devtable), &sb) < 0)
  1387. sys_errmsg_die("%s", optarg);
  1388. if (sb.st_size < 10)
  1389. errmsg_die("%s: not a proper device table file", optarg);
  1390. break;
  1391. case 'r':
  1392. case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */
  1393. if (rootdir != default_rootdir) {
  1394. errmsg_die("root directory specified more than once");
  1395. }
  1396. rootdir = xstrdup(optarg);
  1397. break;
  1398. case 's':
  1399. page_size = strtol(optarg, NULL, 0);
  1400. warn_page_size = 0; /* set by user, so don't need to warn */
  1401. break;
  1402. case 'o':
  1403. if (out_fd != -1) {
  1404. errmsg_die("output filename specified more than once");
  1405. }
  1406. out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
  1407. if (out_fd == -1) {
  1408. sys_errmsg_die("open output file");
  1409. }
  1410. break;
  1411. case 'q':
  1412. squash_uids = 1;
  1413. squash_perms = 1;
  1414. break;
  1415. case 'U':
  1416. squash_uids = 1;
  1417. break;
  1418. case 'P':
  1419. squash_perms = 1;
  1420. break;
  1421. case 'f':
  1422. fake_times = 1;
  1423. break;
  1424. case 'h':
  1425. puts(helptext);
  1426. exit(EXIT_SUCCESS);
  1427. case '?':
  1428. puts(helptext);
  1429. exit(EXIT_FAILURE);
  1430. case 'v':
  1431. verbose = 1;
  1432. break;
  1433. case 'V':
  1434. common_print_version();
  1435. exit(EXIT_SUCCESS);
  1436. case 'e': {
  1437. char *next;
  1438. unsigned units = 0;
  1439. erase_block_size = strtol(optarg, &next, 0);
  1440. if (!erase_block_size)
  1441. errmsg_die("Unrecognisable erase size\n");
  1442. if (*next) {
  1443. if (!strcmp(next, "KiB")) {
  1444. units = 1024;
  1445. } else if (!strcmp(next, "MiB")) {
  1446. units = 1024 * 1024;
  1447. } else {
  1448. errmsg_die("Unknown units in erasesize\n");
  1449. }
  1450. } else {
  1451. if (erase_block_size < 0x1000)
  1452. units = 1024;
  1453. else
  1454. units = 1;
  1455. }
  1456. erase_block_size *= units;
  1457. /* If it's less than 8KiB, they're not allowed */
  1458. if (erase_block_size < 0x2000) {
  1459. fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
  1460. erase_block_size);
  1461. erase_block_size = 0x2000;
  1462. }
  1463. break;
  1464. }
  1465. case 'l':
  1466. target_endian = __LITTLE_ENDIAN;
  1467. break;
  1468. case 'b':
  1469. target_endian = __BIG_ENDIAN;
  1470. break;
  1471. case 'p':
  1472. if (optarg)
  1473. pad_fs_size = strtol(optarg, NULL, 0);
  1474. else
  1475. pad_fs_size = -1;
  1476. break;
  1477. case 'n':
  1478. add_cleanmarkers = 0;
  1479. break;
  1480. case 'c':
  1481. cleanmarker_size = strtol(optarg, NULL, 0);
  1482. if (cleanmarker_size < sizeof(cleanmarker)) {
  1483. errmsg_die("cleanmarker size must be >= 12");
  1484. }
  1485. if (cleanmarker_size >= erase_block_size) {
  1486. errmsg_die("cleanmarker size must be < eraseblock size");
  1487. }
  1488. break;
  1489. case 'm':
  1490. if (jffs2_set_compression_mode_name(optarg)) {
  1491. errmsg_die("Unknown compression mode %s", optarg);
  1492. }
  1493. break;
  1494. case 'x':
  1495. if (jffs2_disable_compressor_name(optarg)) {
  1496. errmsg_die("Unknown compressor name %s",optarg);
  1497. }
  1498. break;
  1499. case 'X':
  1500. if (jffs2_enable_compressor_name(optarg)) {
  1501. errmsg_die("Unknown compressor name %s",optarg);
  1502. }
  1503. break;
  1504. case 'L':
  1505. errmsg_die("\n%s",jffs2_list_compressors());
  1506. break;
  1507. case 't':
  1508. jffs2_compression_check_set(1);
  1509. break;
  1510. case 'y':
  1511. compr_name = xmalloc(strlen(optarg));
  1512. sscanf(optarg,"%d:%s",&compr_prior,compr_name);
  1513. if ((compr_prior>=0)&&(compr_name)) {
  1514. if (jffs2_set_compressor_priority(compr_name, compr_prior))
  1515. exit(EXIT_FAILURE);
  1516. }
  1517. else {
  1518. errmsg_die("Cannot parse %s",optarg);
  1519. }
  1520. free(compr_name);
  1521. break;
  1522. case 'i':
  1523. if (in_fd != -1) {
  1524. errmsg_die("(incremental) filename specified more than once");
  1525. }
  1526. in_fd = open(optarg, O_RDONLY);
  1527. if (in_fd == -1) {
  1528. sys_errmsg_die("cannot open (incremental) file");
  1529. }
  1530. break;
  1531. #ifndef WITHOUT_XATTR
  1532. case 1000: /* --with-xattr */
  1533. enable_xattr |= (1 << JFFS2_XPREFIX_USER)
  1534. | (1 << JFFS2_XPREFIX_SECURITY)
  1535. | (1 << JFFS2_XPREFIX_ACL_ACCESS)
  1536. | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
  1537. | (1 << JFFS2_XPREFIX_TRUSTED);
  1538. break;
  1539. case 1001: /* --with-selinux */
  1540. enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
  1541. break;
  1542. case 1002: /* --with-posix-acl */
  1543. enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
  1544. | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
  1545. break;
  1546. #endif
  1547. }
  1548. }
  1549. if (warn_page_size) {
  1550. errmsg("Page size for this system is by default %d", page_size);
  1551. errmsg("Use the --pagesize=SIZE option if this is not what you want");
  1552. }
  1553. if (out_fd == -1) {
  1554. if (isatty(1)) {
  1555. errmsg_die("%s", helptext);
  1556. }
  1557. out_fd = 1;
  1558. }
  1559. if (chdir(rootdir))
  1560. sys_errmsg_die("%s", rootdir);
  1561. if (!(cwd = getcwd(0, GETCWD_SIZE)))
  1562. sys_errmsg_die("getcwd failed");
  1563. if(in_fd != -1)
  1564. parse_image();
  1565. root = recursive_add_host_directory(NULL, "/", cwd);
  1566. if (devtable)
  1567. parse_device_table(root, devtable);
  1568. create_target_filesystem(root);
  1569. cleanup(root);
  1570. if (rootdir != default_rootdir)
  1571. free(rootdir);
  1572. close(out_fd);
  1573. if (verbose) {
  1574. char *s = jffs2_stats();
  1575. fprintf(stderr,"\n\n%s",s);
  1576. free(s);
  1577. }
  1578. if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
  1579. fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
  1580. }
  1581. jffs2_compressors_exit();
  1582. return 0;
  1583. }