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 
24 FILE_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 */
41 struct 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 */
49  const uint8_t *expected;
50  /** Length of expected CPIO headers */
51  size_t expected_len;
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  */
94 static void cpio_okx ( struct cpio_test *test, const char *file,
95  unsigned int line ) {
96  struct cpio_header cpio;
97  struct image *image;
98  uint8_t *data;
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 */
165 CPIO_TEST ( no_cmdline, 42, NULL, 0, "" );
166 
167 /* Image with empty command line */
168 CPIO_TEST ( empty_cmdline, 154, "", 0, "" );
169 
170 /* All slashes */
171 CPIO_TEST ( all_slashes, 64, "////", 0, "" );
172 
173 /* Simple filename */
174 CPIO_TEST ( simple, 0x69, "wimboot", 1,
175  CPIO_HEADER ( "000081a4", "00000069", "00000008",
176  "wimboot" PAD3 ) );
177 
178 /* Initial slash */
179 CPIO_TEST ( init_slash, 0x273, "/wimboot", 1,
180  CPIO_HEADER ( "000081a4", "00000273", "00000009",
181  "/wimboot" PAD2 ) );
182 
183 /* Initial slashes */
184 CPIO_TEST ( init_slashes, 0x94, "///initscript", 1,
185  CPIO_HEADER ( "000081a4", "00000094", "0000000e",
186  "///initscript" PAD1 ) );
187 
188 /* Full path */
189 CPIO_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 */
194 CPIO_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 */
199 CPIO_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 */
206 CPIO_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 */
215 CPIO_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 */
226 CPIO_TEST ( dir, 0, "/opt/", 1,
227  CPIO_HEADER ( "000041ed", "00000000", "00000005",
228  "/opt" PAD2 ) );
229 
230 /* Directory tree */
231 CPIO_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 */
240 CPIO_TEST ( mode, 39, "/sbin/init mode=755", 1,
241  CPIO_HEADER ( "000081ed", "00000027", "0000000b",
242  "/sbin/init" PAD4 ) );
243 
244 /* Chaos */
245 CPIO_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  */
257 static 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 };
size_t len
Image length.
Definition: cpio_test.c:45
size_t expected_len
Length of expected CPIO headers.
Definition: cpio_test.c:51
A CPIO archive header.
Definition: cpio.h:20
A CPIO test.
Definition: cpio_test.c:41
unsigned int expected_count
Expected number of CPIO headers.
Definition: cpio_test.c:53
const uint8_t * expected
Expected CPIO headers.
Definition: cpio_test.c:49
uint16_t mode
Acceleration mode.
Definition: ena.h:26
#define DBGC(...)
Definition: compiler.h:505
#define CPIO_ALIGN
CPIO header length alignment.
Definition: cpio.h:61
#define PAD3
Define a three-byte padding.
Definition: cpio_test.c:69
Self-test infrastructure.
const char * name
Test set name.
Definition: test.h:17
An executable image.
Definition: image.h:23
A self-test set.
Definition: test.h:15
static size_t cpio_pad_len(size_t len)
Get CPIO header zero-padding length.
Definition: cpio.h:81
CPIO archives.
#define PAD2
Define a two-byte padding.
Definition: cpio_test.c:66
void * memcpy(void *dest, const void *src, size_t len) __nonnull
size_t cpio_header(struct image *image, unsigned int index, struct cpio_header *cpio)
Construct CPIO header for image, if applicable.
Definition: cpio.c:155
#define cpio_ok(test)
Definition: cpio_test.c:162
static void cpio_test_exec(void)
Perform CPIO self-test.
Definition: cpio_test.c:257
#define okx(success, file, line)
Report test result.
Definition: test.h:44
#define PAD4
Define four-byte padding.
Definition: cpio_test.c:72
ring len
Length.
Definition: dwmac.h:231
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static void cpio_okx(struct cpio_test *test, const char *file, unsigned int line)
Report a CPIO test result.
Definition: cpio_test.c:94
const char * cmdline
Image command line.
Definition: cpio_test.c:47
#define DBGC2_HDA(...)
Definition: compiler.h:523
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:661
int image_set_name(struct image *image, const char *name)
Set image name.
Definition: image.c:180
static void image_put(struct image *image)
Decrement reference count on an image.
Definition: image.h:249
unsigned char uint8_t
Definition: stdint.h:10
#define CPIO_HEADER(mode, filesize, namesize, pname)
Define an expected CPIO header.
Definition: cpio_test.c:57
int image_set_len(struct image *image, size_t len)
Set image length.
Definition: image.c:244
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define CPIO_TEST(NAME, LEN, CMDLINE, COUNT, EXPECTED)
Define a CPIO test.
Definition: cpio_test.c:75
int image_set_cmdline(struct image *image, const char *cmdline)
Set image command line.
Definition: image.c:225
#define PAD1
Define a one-byte padding.
Definition: cpio_test.c:63
struct image * alloc_image(struct uri *uri)
Allocate executable image.
Definition: image.c:123
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
const char * name
Test name.
Definition: cpio_test.c:43
static int test
Definition: epic100.c:73
struct self_test cpio_test __self_test
CPIO self-test.
Definition: cpio_test.c:277
static const char * cpio_name(struct image *image)
Get CPIO image name.
Definition: cpio.h:70