iPXE
cpio_test.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * CPIO self-tests
29 *
30 */
31
32/* Forcibly enable assertions */
33#undef NDEBUG
34
35#include <stdlib.h>
36#include <string.h>
37#include <ipxe/cpio.h>
38#include <ipxe/test.h>
39
40/** A CPIO test */
41struct cpio_test {
42 /** Test name */
43 const char *name;
44 /** Image length */
45 size_t len;
46 /** Image command line */
47 const char *cmdline;
48 /** Expected CPIO headers */
50 /** Length of expected CPIO headers */
52 /** Expected number of CPIO headers */
53 unsigned int expected_count;
54};
55
56/** Define an expected CPIO header */
57#define CPIO_HEADER( mode, filesize, namesize, pname ) \
58 "070701" "00000000" mode "00000000" "00000000" "00000001" \
59 "00000000" filesize "00000000" "00000000" "00000000" "00000000" \
60 namesize "00000000" pname
61
62/** Define a one-byte padding */
63#define PAD1 "\0"
64
65/** Define a two-byte padding */
66#define PAD2 "\0\0"
67
68/** Define a three-byte padding */
69#define PAD3 "\0\0\0"
70
71/** Define four-byte padding */
72#define PAD4 "\0\0\0\0"
73
74/** Define a CPIO test */
75#define CPIO_TEST( NAME, LEN, CMDLINE, COUNT, EXPECTED ) \
76 static const uint8_t NAME ## _expected[] = EXPECTED; \
77 static struct cpio_test NAME = { \
78 .name = #NAME, \
79 .len = LEN, \
80 .cmdline = CMDLINE, \
81 .expected = NAME ## _expected, \
82 .expected_len = ( sizeof ( NAME ## _expected ) \
83 - 1 /* NUL */ ), \
84 .expected_count = COUNT, \
85 };
86
87/**
88 * Report a CPIO test result
89 *
90 * @v test CPIO test
91 * @v file Test code file
92 * @v line Test code line
93 */
94static void cpio_okx ( struct cpio_test *test, const char *file,
95 unsigned int line ) {
96 struct cpio_header cpio;
97 struct image *image;
99 size_t len;
100 size_t cpio_len;
101 unsigned int i;
102 unsigned int j;
103
104 DBGC ( test, "CPIO len %#zx cmdline \"%s\"\n",
105 test->len, test->cmdline );
106 DBGC2_HDA ( test, 0, test->expected, test->expected_len );
107
108 /* Sanity check */
109 okx ( ( test->expected_len % CPIO_ALIGN ) == 0, file, line );
110
111 /* Construct dummy image */
112 image = alloc_image ( NULL );
113 okx ( image != NULL, file, line );
114 okx ( image_set_name ( image, test->name ) == 0, file, line );
115 okx ( image_set_len ( image, test->len ) == 0, file, line );
116 okx ( image_set_cmdline ( image, test->cmdline ) == 0, file, line );
117
118 /* Calculate length of CPIO headers */
119 len = 0;
120 for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) ) ; i++ ) {
121 okx ( cpio_len >= sizeof ( cpio ), file, line );
122 len += ( cpio_len + cpio_pad_len ( cpio_len ) );
123 okx ( cpio_pad_len ( cpio_len ) > 0, file, line );
124 okx ( ( len % CPIO_ALIGN ) == 0, file, line );
125 }
126 okx ( i == test->expected_count, file, line );
127 okx ( len == test->expected_len, file, line );
128
129 /* Allocate space for CPIO headers */
130 data = zalloc ( len );
131 okx ( data != NULL, file, line );
132
133 /* Construct CPIO headers */
134 len = 0;
135 for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) ) ; i++ ) {
136 memcpy ( ( data + len ), &cpio, sizeof ( cpio ) );
137 memcpy ( ( data + len + sizeof ( cpio ) ), cpio_name ( image ),
138 ( cpio_len - sizeof ( cpio ) ) );
139 DBGC ( test, "CPIO hdr %d: ", i );
140 for ( j = 0 ; j < cpio_len ; j++ ) {
141 if ( ( j <= sizeof ( cpio ) && ! ( ( j + 2 ) % 8 ) ) )
142 DBGC ( test, " " );
143 DBGC ( test, "%c", data[ len + j ] );
144 }
145 DBGC ( test, "\n" );
146 len += ( cpio_len + cpio_pad_len ( cpio_len ) );
147 }
148 okx ( i == test->expected_count, file, line );
149 okx ( len == test->expected_len, file, line );
150
151 /* Verify constructed CPIO headers */
152 DBGC2_HDA ( test, 0, data, len );
153 okx ( memcmp ( data, test->expected, test->expected_len ) == 0,
154 file, line );
155
156 /* Free constructed headers */
157 free ( data );
158
159 /* Drop reference to dummy image */
160 image_put ( image );
161}
162#define cpio_ok( test ) cpio_okx ( test, __FILE__, __LINE__ )
163
164/* Image with no command line */
165CPIO_TEST ( no_cmdline, 42, NULL, 0, "" );
166
167/* Image with empty command line */
168CPIO_TEST ( empty_cmdline, 154, "", 0, "" );
169
170/* All slashes */
171CPIO_TEST ( all_slashes, 64, "////", 0, "" );
172
173/* Simple filename */
174CPIO_TEST ( simple, 0x69, "wimboot", 1,
175 CPIO_HEADER ( "000081a4", "00000069", "00000008",
176 "wimboot" PAD3 ) );
177
178/* Initial slash */
179CPIO_TEST ( init_slash, 0x273, "/wimboot", 1,
180 CPIO_HEADER ( "000081a4", "00000273", "00000009",
181 "/wimboot" PAD2 ) );
182
183/* Initial slashes */
184CPIO_TEST ( init_slashes, 0x94, "///initscript", 1,
185 CPIO_HEADER ( "000081a4", "00000094", "0000000e",
186 "///initscript" PAD1 ) );
187
188/* Full path */
189CPIO_TEST ( path, 0x341, "/usr/share/oem/config.ign", 1,
190 CPIO_HEADER ( "000081a4", "00000341", "0000001a",
191 "/usr/share/oem/config.ign" PAD1 ) );
192
193/* Full path, mkdir=0 */
194CPIO_TEST ( path_mkdir_0, 0x341, "/usr/share/oem/config.ign mkdir=0", 1,
195 CPIO_HEADER ( "000081a4", "00000341", "0000001a",
196 "/usr/share/oem/config.ign" PAD1 ) );
197
198/* Full path, mkdir=1 */
199CPIO_TEST ( path_mkdir_1, 0x341, "/usr/share/oem/config.ign mkdir=1", 2,
200 CPIO_HEADER ( "000041ed", "00000000", "0000000f",
201 "/usr/share/oem" PAD4 )
202 CPIO_HEADER ( "000081a4", "00000341", "0000001a",
203 "/usr/share/oem/config.ign" PAD1 ) );
204
205/* Full path, mkdir=2 */
206CPIO_TEST ( path_mkdir_2, 0x341, "/usr/share/oem/config.ign mkdir=2", 3,
207 CPIO_HEADER ( "000041ed", "00000000", "0000000b",
208 "/usr/share" PAD4 )
209 CPIO_HEADER ( "000041ed", "00000000", "0000000f",
210 "/usr/share/oem" PAD4 )
211 CPIO_HEADER ( "000081a4", "00000341", "0000001a",
212 "/usr/share/oem/config.ign" PAD1 ) );
213
214/* Full path, mkdir=-1 */
215CPIO_TEST ( path_mkdir_all, 0x341, "/usr/share/oem/config.ign mkdir=-1", 4,
216 CPIO_HEADER ( "000041ed", "00000000", "00000005",
217 "/usr" PAD2 )
218 CPIO_HEADER ( "000041ed", "00000000", "0000000b",
219 "/usr/share" PAD4 )
220 CPIO_HEADER ( "000041ed", "00000000", "0000000f",
221 "/usr/share/oem" PAD4 )
222 CPIO_HEADER ( "000081a4", "00000341", "0000001a",
223 "/usr/share/oem/config.ign" PAD1 ) );
224
225/* Simple directory */
226CPIO_TEST ( dir, 0, "/opt/", 1,
227 CPIO_HEADER ( "000041ed", "00000000", "00000005",
228 "/opt" PAD2 ) );
229
230/* Directory tree */
231CPIO_TEST ( tree, 0, "/opt/oem/scripts/ mkdir=-1", 3,
232 CPIO_HEADER ( "000041ed", "00000000", "00000005",
233 "/opt" PAD2 )
234 CPIO_HEADER ( "000041ed", "00000000", "00000009",
235 "/opt/oem" PAD2 )
236 CPIO_HEADER ( "000041ed", "00000000", "00000011",
237 "/opt/oem/scripts" PAD2 ) );
238
239/* Custom mode */
240CPIO_TEST ( mode, 39, "/sbin/init mode=755", 1,
241 CPIO_HEADER ( "000081ed", "00000027", "0000000b",
242 "/sbin/init" PAD4 ) );
243
244/* Chaos */
245CPIO_TEST ( chaos, 73, "///etc//init.d///runthings mode=700 mkdir=99", 3,
246 CPIO_HEADER ( "000041ed", "00000000", "00000007",
247 "///etc" PAD4 )
248 CPIO_HEADER ( "000041ed", "00000000", "0000000f",
249 "///etc//init.d" PAD4 )
250 CPIO_HEADER ( "000081c0", "00000049", "0000001b",
251 "///etc//init.d///runthings" PAD4 ) );
252
253/**
254 * Perform CPIO self-test
255 *
256 */
257static void cpio_test_exec ( void ) {
258
259 cpio_ok ( &no_cmdline );
260 cpio_ok ( &empty_cmdline );
261 cpio_ok ( &all_slashes );
262 cpio_ok ( &simple );
263 cpio_ok ( &init_slash );
264 cpio_ok ( &init_slashes );
265 cpio_ok ( &path );
266 cpio_ok ( &path_mkdir_0 );
267 cpio_ok ( &path_mkdir_1 );
268 cpio_ok ( &path_mkdir_2 );
269 cpio_ok ( &path_mkdir_all );
270 cpio_ok ( &dir );
271 cpio_ok ( &tree );
272 cpio_ok ( &mode );
273 cpio_ok ( &chaos );
274}
275
276/** CPIO self-test */
278 .name = "cpio",
279 .exec = cpio_test_exec,
280};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
unsigned char uint8_t
Definition stdint.h:10
size_t cpio_header(struct image *image, unsigned int index, struct cpio_header *cpio)
Construct CPIO header for image, if applicable.
Definition cpio.c:156
CPIO archives.
#define CPIO_ALIGN
CPIO header length alignment.
Definition cpio.h:62
static size_t cpio_pad_len(size_t len)
Get CPIO header zero-padding length.
Definition cpio.h:82
static const char * cpio_name(struct image *image)
Get CPIO image name.
Definition cpio.h:71
#define PAD1
Define a one-byte padding.
Definition cpio_test.c:63
static void cpio_test_exec(void)
Perform CPIO self-test.
Definition cpio_test.c:257
#define PAD4
Define four-byte padding.
Definition cpio_test.c:72
#define cpio_ok(test)
Definition cpio_test.c:162
#define PAD2
Define a two-byte padding.
Definition cpio_test.c:66
static void cpio_okx(struct cpio_test *test, const char *file, unsigned int line)
Report a CPIO test result.
Definition cpio_test.c:94
#define PAD3
Define a three-byte padding.
Definition cpio_test.c:69
#define CPIO_TEST(NAME, LEN, CMDLINE, COUNT, EXPECTED)
Define a CPIO test.
Definition cpio_test.c:75
#define CPIO_HEADER(mode, filesize, namesize, pname)
Define an expected CPIO header.
Definition cpio_test.c:57
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint16_t mode
Acceleration mode.
Definition ena.h:15
static int test
Definition epic100.c:73
#define DBGC2_HDA(...)
Definition compiler.h:523
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
struct image * alloc_image(struct uri *uri)
Allocate executable image.
Definition image.c:124
int image_set_cmdline(struct image *image, const char *cmdline)
Set image command line.
Definition image.c:226
int image_set_name(struct image *image, const char *name)
Set image name.
Definition image.c:181
int image_set_len(struct image *image, size_t len)
Set image length.
Definition image.c:245
static void image_put(struct image *image)
Decrement reference count on an image.
Definition image.h:250
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A CPIO archive header.
Definition cpio.h:21
A CPIO test.
Definition cpio_test.c:41
unsigned int expected_count
Expected number of CPIO headers.
Definition cpio_test.c:53
const char * cmdline
Image command line.
Definition cpio_test.c:47
const uint8_t * expected
Expected CPIO headers.
Definition cpio_test.c:49
const char * name
Test name.
Definition cpio_test.c:43
size_t expected_len
Length of expected CPIO headers.
Definition cpio_test.c:51
size_t len
Image length.
Definition cpio_test.c:45
An executable image.
Definition image.h:24
A self-test set.
Definition test.h:15
Self-test infrastructure.
#define okx(success, file, line)
Report test result.
Definition test.h:44
#define __self_test
Declare a self-test.
Definition test.h:32