xref: /xnu-12377.1.9/tests/vfs/getattrlist_mountextflags.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1 /*
2  * Copyright (c) 2024 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o getattrlist_mountextflags getattrlist_mountextflags.c -g -Weverything */
30 
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <sys/mount.h>
34 #include <sys/stat.h>
35 #include <TargetConditionals.h>
36 
37 #include <darwintest.h>
38 #include <darwintest/utils.h>
39 
40 #if !TARGET_OS_OSX
41 #define FSTYPE_LIFS  "lifs"
42 #endif /* !TARGET_OS_OSX */
43 
44 #define FSTYPE_MSDOS "msdos"
45 #define FSTYPE_APFS  "apfs"
46 
47 /* rdar://137970358: Disable the test for now until the root cause was determined */
48 #if 0
49 #define RUN_TEST     ((TARGET_OS_OSX || TARGET_OS_IOS) && !TARGET_OS_XR)
50 #else
51 #define RUN_TEST     0
52 #endif
53 
54 static char template[MAXPATHLEN];
55 static char *testdir = NULL;
56 static char *output_buffer = NULL;
57 static char image_path[PATH_MAX];
58 static char mount_path[PATH_MAX];
59 static char disk[PATH_MAX];
60 
61 T_GLOBAL_META(
62 	T_META_NAMESPACE("xnu.vfs"),
63 	T_META_RADAR_COMPONENT_NAME("xnu"),
64 	T_META_RADAR_COMPONENT_VERSION("vfs"),
65 	T_META_ENABLED(RUN_TEST),
66 	T_META_ASROOT(false),
67 	T_META_CHECK_LEAKS(false));
68 
69 static void
get_mount_path(const char * diskid,char * path)70 get_mount_path(const char *diskid, char *path)
71 {
72 	int i, mntsize;
73 	struct statfs *mntbuf;
74 	char diskurl[NAME_MAX];
75 
76 	if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
77 		T_FAIL("getmntinfo failure");
78 		return;
79 	}
80 
81 	snprintf(diskurl, sizeof(diskurl), "/%s", diskid);
82 
83 	for (i = 0; i < mntsize; i++) {
84 #if TARGET_OS_OSX
85 		/* check if this mount is one we want */
86 		if (strcmp(mntbuf[i].f_fstypename, FSTYPE_MSDOS)) {
87 			continue;
88 		}
89 #else
90 		/* check if this mount is one we want */
91 		if (strcmp(mntbuf[i].f_fstypename, FSTYPE_LIFS)) {
92 			continue;
93 		}
94 
95 		/* validate fstype */
96 		if (strncmp(mntbuf[i].f_mntfromname, FSTYPE_MSDOS, strlen(FSTYPE_MSDOS))) {
97 			continue;
98 		}
99 #endif /* TARGET_OS_OSX */
100 
101 		/* validate disk */
102 		if (strstr(mntbuf[i].f_mntfromname, diskurl) == NULL) {
103 			continue;
104 		}
105 
106 		strlcpy(path, mntbuf[i].f_mntonname, PATH_MAX);
107 		return;
108 	}
109 
110 	T_FAIL("Cannot find mount path");
111 }
112 
113 /*
114  * run an external program
115  */
116 static int
do_exec(const char * cmd)117 do_exec(const char *cmd)
118 {
119 	FILE *fp;
120 	char *pos;
121 	char *buffer = output_buffer;
122 	int output_len = PATH_MAX;
123 
124 	/* Open the command for reading. */
125 	fp = popen(cmd, "r");
126 	if (fp == NULL) {
127 		T_FAIL("Failed to run command");
128 		return -1;
129 	}
130 
131 	/* Read the output a line at a time - output it. */
132 	while (fgets(buffer, output_len, fp) != NULL) {
133 		size_t bytes = strlen(buffer);
134 
135 		buffer += bytes;
136 		output_len -= bytes;
137 	}
138 
139 	/* replace last '\n' with '\0' */
140 	pos = strrchr(output_buffer, '\n');
141 	*pos = '\0';
142 
143 	/* close */
144 	pclose(fp);
145 	return 0;
146 }
147 
148 static void
cleanup(void)149 cleanup(void)
150 {
151 	char args[PATH_MAX];
152 
153 	if (mount_path[0] != '\0') {
154 		unmount(mount_path, MNT_FORCE);
155 	}
156 	if (disk[0] != '\0') {
157 		snprintf(args, sizeof(args), "diskutil eject %s", disk);
158 		do_exec(args);
159 	}
160 	if (image_path[0] != '\0') {
161 		unlink(image_path);
162 	}
163 	if (testdir) {
164 		rmdir(testdir);
165 	}
166 	if (output_buffer) {
167 		free(output_buffer);
168 	}
169 }
170 
171 static void
test_getattrlist(const char * path,const char * fstypename,uint32_t mount_extflags)172 test_getattrlist(const char *path, const char *fstypename, uint32_t mount_extflags)
173 {
174 	struct myattrbuf {
175 		uint32_t length;
176 		attribute_set_t returned_attrs;
177 		uint32_t mount_extflags;
178 		attrreference_t fstypename_ref;
179 		char fstypename[MFSTYPENAMELEN];
180 	} attrbuf;
181 
182 	struct attrlist attrs = {
183 		.bitmapcount = ATTR_BIT_MAP_COUNT,
184 		.commonattr = ATTR_CMN_RETURNED_ATTRS,
185 		.volattr = ATTR_VOL_MOUNTEXTFLAGS | ATTR_VOL_FSTYPENAME,
186 	};
187 
188 	T_LOG("Testing %s", path);
189 
190 	T_ASSERT_POSIX_SUCCESS(getattrlist(path, &attrs, &attrbuf,
191 	    sizeof(attrbuf), FSOPT_REPORT_FULLSIZE | FSOPT_PACK_INVAL_ATTRS),
192 	    "Calling getattrlist");
193 
194 	T_ASSERT_TRUE(attrbuf.length <= sizeof(attrbuf),
195 	    "Asserting attrbuf.length <= sizeof(attrbuf)");
196 
197 	/* Verifing ATTR_VOL_FSTYPENAME and ATTR_VOL_MOUNTEXTFLAGS enabled */
198 	T_ASSERT_BITS_SET(attrbuf.returned_attrs.volattr, ATTR_VOL_FSTYPENAME | ATTR_VOL_MOUNTEXTFLAGS,
199 	    "Asserting ATTR_VOL_FSTYPENAME and ATTR_VOL_MOUNTEXTFLAGS was returned");
200 
201 	/* Verifing ATTR_VOL_FSTYPENAME content */
202 	T_ASSERT_EQ(strncmp(attrbuf.fstypename, fstypename, strlen(fstypename)), 0,
203 	    "Asserting that fstypename matches");
204 
205 	/* Verifing ATTR_VOL_MOUNTEXTFLAGS content */
206 	T_ASSERT_EQ(attrbuf.mount_extflags, mount_extflags,
207 	    "Asserting that mount_extflags matches");
208 }
209 
210 T_DECL(getattrlist_mountextflags,
211     "test ATTR_VOL_MOUNTEXTFLAGS")
212 {
213 #if (!RUN_TEST)
214 	T_SKIP("Test disabled for this platform");
215 #endif
216 
217 	char *diskp = NULL;
218 	char args[PATH_MAX];
219 
220 	image_path[0] = mount_path[0] = disk[0] = '\0';
221 
222 	T_ATEND(cleanup);
223 	T_SETUPBEGIN;
224 
225 	/* Allocate output buffer */
226 	output_buffer = malloc(PATH_MAX);
227 
228 	/* Create test directory */
229 	snprintf(template, sizeof(template), "%s/getattrlist_mountextflags-XXXXXX", dt_tmpdir());
230 	T_ASSERT_POSIX_NOTNULL((testdir = mkdtemp(template)), "Creating test root dir");
231 
232 	/* Create image path */
233 	snprintf(image_path, sizeof(image_path), "%s/msdos.dmg", testdir);
234 
235 	/* Create disk image */
236 	snprintf(args, sizeof(args), "diskimagetool create -fs none -s 1m %s", image_path);
237 	T_ASSERT_POSIX_SUCCESS(do_exec(args), "Creating disk image %s", image_path);
238 
239 	/* Attach disk image */
240 	snprintf(args, sizeof(args), "diskimagetool attach --external %s", image_path);
241 	T_ASSERT_POSIX_SUCCESS(do_exec(args), "Attaching disk image %s", image_path);
242 
243 	/* Extract device identifier */
244 	T_ASSERT_POSIX_NOTNULL((diskp = strstr(output_buffer, "disk")), "Extracting device identifier: %s", diskp);
245 	strlcpy(disk, diskp, PATH_MAX);
246 
247 	/* Execute newfs_msdos disk image */
248 	snprintf(args, sizeof(args), "newfs_msdos -v MSDOS %s", disk);
249 	T_ASSERT_POSIX_SUCCESS(do_exec(args), "Executing newfs_msdos on disk %s", disk);
250 
251 	/* Mount disk image */
252 	snprintf(args, sizeof(args), "datest --mount --device %s", disk);
253 	T_ASSERT_POSIX_SUCCESS(do_exec(args), "Mounting disk image");
254 
255 	/* Get the mount path */
256 	get_mount_path(disk, mount_path);
257 	T_ASSERT_NE_STR(mount_path, "", "Got msdos filesystem mount path %s", mount_path);
258 
259 	T_SETUPEND;
260 
261 	/* Testing existing directory */
262 	test_getattrlist("/", FSTYPE_APFS, 0);
263 
264 #if TARGET_OS_OSX
265 	/* Testing Data volume directory */
266 	test_getattrlist("/private/var/tmp/", FSTYPE_APFS, MNT_EXT_ROOT_DATA_VOL);
267 #endif /* TARGET_OS_OSX */
268 
269 	/* Testing msdos volume directory */
270 #if TARGET_OS_OSX
271 	test_getattrlist(mount_path, FSTYPE_MSDOS, MNT_EXT_FSKIT);
272 #else
273 	test_getattrlist(mount_path, FSTYPE_LIFS, MNT_EXT_FSKIT);
274 #endif /* TARGET_OS_OSX */
275 }
276