1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, 9 * copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom 11 * the Software is furnished to do so, subject to the following 12 * conditions: 13 * 14 * The above copyright notice and this permission notice shall 15 * be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * ----------------------------------------------------------------------- */ 27 28 /* 29 * initramfs_file.c 30 * 31 * Utility functions to add arbitrary files including cpio header 32 */ 33 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <sys/stat.h> 38 #include <syslinux/linux.h> 39 40 #define CPIO_MAGIC "070701" 41 struct cpio_header { 42 char c_magic[6]; /* 070701 */ 43 char c_ino[8]; /* Inode number */ 44 char c_mode[8]; /* File mode and permissions */ 45 char c_uid[8]; /* uid */ 46 char c_gid[8]; /* gid */ 47 char c_nlink[8]; /* Number of links */ 48 char c_mtime[8]; /* Modification time */ 49 char c_filesize[8]; /* Size of data field */ 50 char c_maj[8]; /* File device major number */ 51 char c_min[8]; /* File device minor number */ 52 char c_rmaj[8]; /* Device node reference major number */ 53 char c_rmin[8]; /* Device node reference minor number */ 54 char c_namesize[8]; /* Length of filename including final \0 */ 55 char c_chksum[8]; /* Checksum if c_magic ends in 2 */ 56 }; 57 58 static uint32_t next_ino = 1; 59 60 /* Create cpio headers for the directory entries leading up to a file. 61 Returns the number of bytes; doesn't touch the buffer if too small. */ 62 static size_t initramfs_mkdirs(const char *filename, void *buffer, 63 size_t buflen) 64 { 65 const char *p = filename; 66 char *bp = buffer; 67 int len; 68 size_t bytes = 0, hdr_sz; 69 int pad; 70 71 while ((p = strchr(p, '/'))) { 72 if (p != filename && p[-1] != '/') { 73 len = p - filename; 74 bytes += ((sizeof(struct cpio_header) + len + 1) + 3) & ~3; 75 } 76 p++; 77 } 78 79 if (buflen >= bytes) { 80 p = filename; 81 while ((p = strchr(p, '/'))) { 82 if (p != filename && p[-1] != '/') { 83 len = p - filename; 84 hdr_sz = ((sizeof(struct cpio_header) + len + 1) + 3) & ~3; 85 bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x" 86 "%08x%08x%08x%08x", next_ino++, S_IFDIR | 0755, 87 0, 0, 1, 0, 0, 0, 1, 0, 1, len + 1, 0); 88 memcpy(bp, filename, len); 89 bp += len; 90 pad = hdr_sz - (sizeof(struct cpio_header) + len); 91 memset(bp, 0, pad); 92 bp += pad; 93 } 94 p++; 95 } 96 } 97 98 return bytes; 99 } 100 101 /* 102 * Create a file header (with optional parent directory entries) 103 * and add it to an initramfs chain 104 */ 105 int initramfs_mknod(struct initramfs *ihead, const char *filename, 106 int do_mkdir, 107 uint16_t mode, size_t len, uint32_t major, uint32_t minor) 108 { 109 size_t bytes, hdr_sz; 110 int namelen = strlen(filename); 111 int pad; 112 char *buffer, *bp; 113 114 if (do_mkdir) 115 bytes = initramfs_mkdirs(filename, NULL, 0); 116 else 117 bytes = 0; 118 119 hdr_sz = ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3; 120 bytes += hdr_sz; 121 122 bp = buffer = malloc(bytes); 123 if (!buffer) 124 return -1; 125 126 if (do_mkdir) 127 bp += initramfs_mkdirs(filename, bp, bytes); 128 129 bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x" 130 "%08x%08x%08x%08x", next_ino++, mode, 131 0, 0, 1, 0, len, 0, 1, major, minor, namelen + 1, 0); 132 memcpy(bp, filename, namelen); 133 bp += namelen; 134 pad = hdr_sz - (sizeof(struct cpio_header) + namelen); 135 memset(bp, 0, pad); 136 137 if (initramfs_add_data(ihead, buffer, bytes, bytes, 4)) { 138 free(buffer); 139 return -1; 140 } 141 142 return 0; 143 } 144 145 /* 146 * Add a file given data in memory to an initramfs chain. This 147 * can be used to create nonfiles like symlinks by specifying an 148 * appropriate mode. 149 */ 150 int initramfs_add_file(struct initramfs *ihead, const void *data, 151 size_t data_len, size_t len, 152 const char *filename, int do_mkdir, uint32_t mode) 153 { 154 if (initramfs_mknod(ihead, filename, do_mkdir, 155 (mode & S_IFMT) ? mode : mode | S_IFREG, len, 0, 1)) 156 return -1; 157 158 return initramfs_add_data(ihead, data, data_len, len, 4); 159 } 160 161 int initramfs_add_trailer(struct initramfs *ihead) 162 { 163 return initramfs_mknod(ihead, "TRAILER!!!", 0, 0, 0, 0, 0); 164 } 165