]> git.ipfire.org Git - thirdparty/dracut.git/blob - skipcpio/skipcpio.c
chore(tree): move tools into their own directory
[thirdparty/dracut.git] / skipcpio / skipcpio.c
1 /* dracut-install.c -- install files and executables
2
3 Copyright (C) 2012 Harald Hoyer
4 Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5
6 This program is free software: you can redistribute it and/or modify
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define PROGRAM_VERSION_STRING "1"
21
22 #ifndef _GNU_SOURCE
23 #define _GNU_SOURCE
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #define CPIO_MAGIC "070701"
31 #define CPIO_END "TRAILER!!!"
32 #define CPIO_ENDLEN (sizeof(CPIO_END) - 1)
33
34 #define CPIO_ALIGNMENT 4
35
36 struct cpio_header {
37 char c_magic[6];
38 char c_ino[8];
39 char c_mode[8];
40 char c_uid[8];
41 char c_gid[8];
42 char c_nlink[8];
43 char c_mtime[8];
44 char c_filesize[8];
45 char c_dev_maj[8];
46 char c_dev_min[8];
47 char c_rdev_maj[8];
48 char c_rdev_min[8];
49 char c_namesize[8];
50 char c_chksum[8];
51 } __attribute__((packed));
52
53 struct buf_struct {
54 struct cpio_header h;
55 char filename[CPIO_ENDLEN];
56 } __attribute__((packed));
57
58 union buf_union {
59 struct buf_struct cpio;
60 char copy_buffer[2048];
61 };
62
63 static union buf_union buf;
64
65 #define ALIGN_UP(n, a) (((n) + (a) - 1) & (~((a) - 1)))
66
67 int main(int argc, char **argv)
68 {
69 FILE *f;
70 size_t s;
71
72 if (argc != 2) {
73 fprintf(stderr, "Usage: %s <file>\n", argv[0]);
74 exit(1);
75 }
76
77 f = fopen(argv[1], "r");
78
79 if (f == NULL) {
80 fprintf(stderr, "Cannot open file '%s'\n", argv[1]);
81 exit(1);
82 }
83
84 s = fread(&buf.cpio, sizeof(buf.cpio), 1, f);
85 if (s <= 0) {
86 fprintf(stderr, "Read error from file '%s'\n", argv[1]);
87 fclose(f);
88 exit(1);
89 }
90 fseek(f, 0, SEEK_SET);
91
92 /* check, if this is a cpio archive */
93 if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6) == 0) {
94
95 long pos = 0;
96
97 unsigned long filesize;
98 unsigned long filename_length;
99
100 do {
101 // zero string, spilling into next unused field, to use strtol
102 buf.cpio.h.c_chksum[0] = 0;
103 filename_length = strtoul(buf.cpio.h.c_namesize, NULL, 16);
104 pos = ALIGN_UP(pos + sizeof(struct cpio_header) + filename_length, CPIO_ALIGNMENT);
105
106 // zero string, spilling into next unused field, to use strtol
107 buf.cpio.h.c_dev_maj[0] = 0;
108 filesize = strtoul(buf.cpio.h.c_filesize, NULL, 16);
109 pos = ALIGN_UP(pos + filesize, CPIO_ALIGNMENT);
110
111 if (filename_length == (CPIO_ENDLEN + 1)
112 && strncmp(buf.cpio.filename, CPIO_END, CPIO_ENDLEN) == 0) {
113 fseek(f, pos, SEEK_SET);
114 break;
115 }
116
117 if (fseek(f, pos, SEEK_SET) != 0) {
118 perror("fseek");
119 exit(1);
120 }
121
122 if (fread(&buf.cpio, sizeof(buf.cpio), 1, f) != 1) {
123 perror("fread");
124 exit(1);
125 }
126
127 if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6) != 0) {
128 fprintf(stderr, "Corrupt CPIO archive!\n");
129 exit(1);
130 }
131 } while (!feof(f));
132
133 if (feof(f)) {
134 /* CPIO_END not found, just cat the whole file */
135 fseek(f, 0, SEEK_SET);
136 } else {
137 /* skip zeros */
138 do {
139 size_t i;
140
141 s = fread(buf.copy_buffer, 1, sizeof(buf.copy_buffer) - 1, f);
142 if (s <= 0)
143 break;
144
145 for (i = 0; (i < s) && (buf.copy_buffer[i] == 0); i++) ;
146
147 if (buf.copy_buffer[i] != 0) {
148 pos += i;
149
150 fseek(f, pos, SEEK_SET);
151 break;
152 }
153
154 pos += s;
155 } while (!feof(f));
156 }
157 }
158 /* cat out the rest */
159 while (!feof(f)) {
160 s = fread(buf.copy_buffer, 1, sizeof(buf.copy_buffer), f);
161 if (s <= 0)
162 break;
163
164 s = fwrite(buf.copy_buffer, 1, s, stdout);
165 if (s <= 0)
166 break;
167 }
168 fclose(f);
169
170 return EXIT_SUCCESS;
171 }