mirror of the now-defunct rocklinux.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

512 lines
10 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <time.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <ctype.h>
  11. #include <limits.h>
  12. /*
  13. * Original work by Jeff Garzik
  14. *
  15. * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
  16. */
  17. #define xstr(s) #s
  18. #define str(s) xstr(s)
  19. static unsigned int offset;
  20. static unsigned int ino = 721;
  21. struct file_handler {
  22. const char *type;
  23. int (*handler)(const char *line);
  24. };
  25. static void push_string(const char *name)
  26. {
  27. unsigned int name_len = strlen(name) + 1;
  28. fputs(name, stdout);
  29. putchar(0);
  30. offset += name_len;
  31. }
  32. static void push_pad (void)
  33. {
  34. while (offset & 3) {
  35. putchar(0);
  36. offset++;
  37. }
  38. }
  39. static void push_rest(const char *name)
  40. {
  41. unsigned int name_len = strlen(name) + 1;
  42. unsigned int tmp_ofs;
  43. fputs(name, stdout);
  44. putchar(0);
  45. offset += name_len;
  46. tmp_ofs = name_len + 110;
  47. while (tmp_ofs & 3) {
  48. putchar(0);
  49. offset++;
  50. tmp_ofs++;
  51. }
  52. }
  53. static void push_hdr(const char *s)
  54. {
  55. fputs(s, stdout);
  56. offset += 110;
  57. }
  58. static void cpio_trailer(void)
  59. {
  60. char s[256];
  61. const char name[] = "TRAILER!!!";
  62. sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
  63. "%08X%08X%08X%08X%08X%08X%08X",
  64. "070701", /* magic */
  65. 0, /* ino */
  66. 0, /* mode */
  67. (long) 0, /* uid */
  68. (long) 0, /* gid */
  69. 1, /* nlink */
  70. (long) 0, /* mtime */
  71. 0, /* filesize */
  72. 0, /* major */
  73. 0, /* minor */
  74. 0, /* rmajor */
  75. 0, /* rminor */
  76. (unsigned)strlen(name)+1, /* namesize */
  77. 0); /* chksum */
  78. push_hdr(s);
  79. push_rest(name);
  80. while (offset % 512) {
  81. putchar(0);
  82. offset++;
  83. }
  84. }
  85. static int cpio_mkslink(const char *name, const char *target,
  86. unsigned int mode, uid_t uid, gid_t gid)
  87. {
  88. char s[256];
  89. time_t mtime = time(NULL);
  90. sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
  91. "%08X%08X%08X%08X%08X%08X%08X",
  92. "070701", /* magic */
  93. ino++, /* ino */
  94. S_IFLNK | mode, /* mode */
  95. (long) uid, /* uid */
  96. (long) gid, /* gid */
  97. 1, /* nlink */
  98. (long) mtime, /* mtime */
  99. (unsigned)strlen(target)+1, /* filesize */
  100. 3, /* major */
  101. 1, /* minor */
  102. 0, /* rmajor */
  103. 0, /* rminor */
  104. (unsigned)strlen(name) + 1,/* namesize */
  105. 0); /* chksum */
  106. push_hdr(s);
  107. push_string(name);
  108. push_pad();
  109. push_string(target);
  110. push_pad();
  111. return 0;
  112. }
  113. static int cpio_mkslink_line(const char *line)
  114. {
  115. char name[PATH_MAX + 1];
  116. char target[PATH_MAX + 1];
  117. unsigned int mode;
  118. int uid;
  119. int gid;
  120. int rc = -1;
  121. if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
  122. fprintf(stderr, "Unrecognized dir format '%s'", line);
  123. goto fail;
  124. }
  125. rc = cpio_mkslink(name, target, mode, uid, gid);
  126. fail:
  127. return rc;
  128. }
  129. static int cpio_mkgeneric(const char *name, unsigned int mode,
  130. uid_t uid, gid_t gid)
  131. {
  132. char s[256];
  133. time_t mtime = time(NULL);
  134. sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
  135. "%08X%08X%08X%08X%08X%08X%08X",
  136. "070701", /* magic */
  137. ino++, /* ino */
  138. mode, /* mode */
  139. (long) uid, /* uid */
  140. (long) gid, /* gid */
  141. 2, /* nlink */
  142. (long) mtime, /* mtime */
  143. 0, /* filesize */
  144. 3, /* major */
  145. 1, /* minor */
  146. 0, /* rmajor */
  147. 0, /* rminor */
  148. (unsigned)strlen(name) + 1,/* namesize */
  149. 0); /* chksum */
  150. push_hdr(s);
  151. push_rest(name);
  152. return 0;
  153. }
  154. enum generic_types {
  155. GT_DIR,
  156. GT_PIPE,
  157. GT_SOCK
  158. };
  159. struct generic_type {
  160. const char *type;
  161. mode_t mode;
  162. };
  163. static struct generic_type generic_type_table[] = {
  164. [GT_DIR] = {
  165. .type = "dir",
  166. .mode = S_IFDIR
  167. },
  168. [GT_PIPE] = {
  169. .type = "pipe",
  170. .mode = S_IFIFO
  171. },
  172. [GT_SOCK] = {
  173. .type = "sock",
  174. .mode = S_IFSOCK
  175. }
  176. };
  177. static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
  178. {
  179. char name[PATH_MAX + 1];
  180. unsigned int mode;
  181. int uid;
  182. int gid;
  183. int rc = -1;
  184. if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
  185. fprintf(stderr, "Unrecognized %s format '%s'",
  186. line, generic_type_table[gt].type);
  187. goto fail;
  188. }
  189. mode |= generic_type_table[gt].mode;
  190. rc = cpio_mkgeneric(name, mode, uid, gid);
  191. fail:
  192. return rc;
  193. }
  194. static int cpio_mkdir_line(const char *line)
  195. {
  196. return cpio_mkgeneric_line(line, GT_DIR);
  197. }
  198. static int cpio_mkpipe_line(const char *line)
  199. {
  200. return cpio_mkgeneric_line(line, GT_PIPE);
  201. }
  202. static int cpio_mksock_line(const char *line)
  203. {
  204. return cpio_mkgeneric_line(line, GT_SOCK);
  205. }
  206. static int cpio_mknod(const char *name, unsigned int mode,
  207. uid_t uid, gid_t gid, char dev_type,
  208. unsigned int maj, unsigned int min)
  209. {
  210. char s[256];
  211. time_t mtime = time(NULL);
  212. if (dev_type == 'b')
  213. mode |= S_IFBLK;
  214. else
  215. mode |= S_IFCHR;
  216. sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
  217. "%08X%08X%08X%08X%08X%08X%08X",
  218. "070701", /* magic */
  219. ino++, /* ino */
  220. mode, /* mode */
  221. (long) uid, /* uid */
  222. (long) gid, /* gid */
  223. 1, /* nlink */
  224. (long) mtime, /* mtime */
  225. 0, /* filesize */
  226. 3, /* major */
  227. 1, /* minor */
  228. maj, /* rmajor */
  229. min, /* rminor */
  230. (unsigned)strlen(name) + 1,/* namesize */
  231. 0); /* chksum */
  232. push_hdr(s);
  233. push_rest(name);
  234. return 0;
  235. }
  236. static int cpio_mknod_line(const char *line)
  237. {
  238. char name[PATH_MAX + 1];
  239. unsigned int mode;
  240. int uid;
  241. int gid;
  242. char dev_type;
  243. unsigned int maj;
  244. unsigned int min;
  245. int rc = -1;
  246. if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
  247. name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
  248. fprintf(stderr, "Unrecognized nod format '%s'", line);
  249. goto fail;
  250. }
  251. rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
  252. fail:
  253. return rc;
  254. }
  255. /* Not marked static to keep the compiler quiet, as no one uses this yet... */
  256. static int cpio_mkfile(const char *name, const char *location,
  257. unsigned int mode, uid_t uid, gid_t gid)
  258. {
  259. char s[256];
  260. char *filebuf = NULL;
  261. struct stat buf;
  262. int file = -1;
  263. int retval;
  264. int rc = -1;
  265. mode |= S_IFREG;
  266. retval = stat (location, &buf);
  267. if (retval) {
  268. fprintf (stderr, "File %s could not be located\n", location);
  269. goto error;
  270. }
  271. file = open (location, O_RDONLY);
  272. if (file < 0) {
  273. fprintf (stderr, "File %s could not be opened for reading\n", location);
  274. goto error;
  275. }
  276. filebuf = malloc(buf.st_size);
  277. if (!filebuf) {
  278. fprintf (stderr, "out of memory\n");
  279. goto error;
  280. }
  281. retval = read (file, filebuf, buf.st_size);
  282. if (retval < 0) {
  283. fprintf (stderr, "Can not read %s file\n", location);
  284. goto error;
  285. }
  286. sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
  287. "%08X%08X%08X%08X%08X%08X%08X",
  288. "070701", /* magic */
  289. ino++, /* ino */
  290. mode, /* mode */
  291. (long) uid, /* uid */
  292. (long) gid, /* gid */
  293. 1, /* nlink */
  294. (long) buf.st_mtime, /* mtime */
  295. (int) buf.st_size, /* filesize */
  296. 3, /* major */
  297. 1, /* minor */
  298. 0, /* rmajor */
  299. 0, /* rminor */
  300. (unsigned)strlen(name) + 1,/* namesize */
  301. 0); /* chksum */
  302. push_hdr(s);
  303. push_string(name);
  304. push_pad();
  305. fwrite(filebuf, buf.st_size, 1, stdout);
  306. offset += buf.st_size;
  307. push_pad();
  308. rc = 0;
  309. error:
  310. if (filebuf) free(filebuf);
  311. if (file >= 0) close(file);
  312. return rc;
  313. }
  314. static int cpio_mkfile_line(const char *line)
  315. {
  316. char name[PATH_MAX + 1];
  317. char location[PATH_MAX + 1];
  318. unsigned int mode;
  319. int uid;
  320. int gid;
  321. int rc = -1;
  322. if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) {
  323. fprintf(stderr, "Unrecognized file format '%s'", line);
  324. goto fail;
  325. }
  326. rc = cpio_mkfile(name, location, mode, uid, gid);
  327. fail:
  328. return rc;
  329. }
  330. void usage(const char *prog)
  331. {
  332. fprintf(stderr, "Usage:\n"
  333. "\t%s <cpio_list>\n"
  334. "\n"
  335. "<cpio_list> is a file containing newline separated entries that\n"
  336. "describe the files to be included in the initramfs archive:\n"
  337. "\n"
  338. "# a comment\n"
  339. "file <name> <location> <mode> <uid> <gid>\n"
  340. "dir <name> <mode> <uid> <gid>\n"
  341. "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
  342. "slink <name> <target> <mode> <uid> <gid>\n"
  343. "pipe <name> <mode> <uid> <gid>\n"
  344. "sock <name> <mode> <uid> <gid>\n"
  345. "\n"
  346. "<name> name of the file/dir/nod/etc in the archive\n"
  347. "<location> location of the file in the current filesystem\n"
  348. "<target> link target\n"
  349. "<mode> mode/permissions of the file\n"
  350. "<uid> user id (0=root)\n"
  351. "<gid> group id (0=root)\n"
  352. "<dev_type> device type (b=block, c=character)\n"
  353. "<maj> major number of nod\n"
  354. "<min> minor number of nod\n"
  355. "\n"
  356. "example:\n"
  357. "# A simple initramfs\n"
  358. "dir /dev 0755 0 0\n"
  359. "nod /dev/console 0600 0 0 c 5 1\n"
  360. "dir /root 0700 0 0\n"
  361. "dir /sbin 0755 0 0\n"
  362. "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
  363. prog);
  364. }
  365. struct file_handler file_handler_table[] = {
  366. {
  367. .type = "file",
  368. .handler = cpio_mkfile_line,
  369. }, {
  370. .type = "nod",
  371. .handler = cpio_mknod_line,
  372. }, {
  373. .type = "dir",
  374. .handler = cpio_mkdir_line,
  375. }, {
  376. .type = "slink",
  377. .handler = cpio_mkslink_line,
  378. }, {
  379. .type = "pipe",
  380. .handler = cpio_mkpipe_line,
  381. }, {
  382. .type = "sock",
  383. .handler = cpio_mksock_line,
  384. }, {
  385. .type = NULL,
  386. .handler = NULL,
  387. }
  388. };
  389. #define LINE_SIZE (2 * PATH_MAX + 50)
  390. int main (int argc, char *argv[])
  391. {
  392. FILE *cpio_list;
  393. char line[LINE_SIZE];
  394. char *args, *type;
  395. int ec = 0;
  396. int line_nr = 0;
  397. if (2 != argc) {
  398. usage(argv[0]);
  399. exit(1);
  400. }
  401. if (! (cpio_list = fopen(argv[1], "r"))) {
  402. fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
  403. argv[1], strerror(errno));
  404. usage(argv[0]);
  405. exit(1);
  406. }
  407. while (fgets(line, LINE_SIZE, cpio_list)) {
  408. int type_idx;
  409. size_t slen = strlen(line);
  410. line_nr++;
  411. if ('#' == *line) {
  412. /* comment - skip to next line */
  413. continue;
  414. }
  415. if (! (type = strtok(line, " \t"))) {
  416. fprintf(stderr,
  417. "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
  418. line_nr, line);
  419. ec = -1;
  420. }
  421. if ('\n' == *type) {
  422. /* a blank line */
  423. continue;
  424. }
  425. if (slen == strlen(type)) {
  426. /* must be an empty line */
  427. continue;
  428. }
  429. if (! (args = strtok(NULL, "\n"))) {
  430. fprintf(stderr,
  431. "ERROR: incorrect format, newline required line %d: '%s'\n",
  432. line_nr, line);
  433. ec = -1;
  434. }
  435. for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
  436. int rc;
  437. if (! strcmp(line, file_handler_table[type_idx].type)) {
  438. if ((rc = file_handler_table[type_idx].handler(args))) {
  439. ec = rc;
  440. fprintf(stderr, " line %d\n", line_nr);
  441. }
  442. break;
  443. }
  444. }
  445. if (NULL == file_handler_table[type_idx].type) {
  446. fprintf(stderr, "unknown file type line %d: '%s'\n",
  447. line_nr, line);
  448. }
  449. }
  450. cpio_trailer();
  451. exit(ec);
  452. }