2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
33 #include <spawn_private.h>
36 #include "subsystem_test.h"
38 #include <darwintest.h>
39 #include <darwintest_utils.h>
41 #define RANDOM_STRING_LEN 33
43 #define HELPER_PATH "./subsystem_test_helper"
45 /* Create the given file. Doesn't create directories. */
47 _create_file(char * const filepath
)
50 int fd
= open(filepath
, O_CREAT
| O_EXCL
, 0666);
60 /* Fills the given buffer with a random alphanumeric string. */
62 _generate_random_string(char * buf
, size_t buf_len
)
65 static char _alphanumeric
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
72 for (cur_byte
= 0; ((buf_len
- cur_byte
) > 1); cur_byte
++) {
73 buf
[cur_byte
] = _alphanumeric
[rand() % (sizeof(_alphanumeric
) - 1)];
81 /* Compares the contents of the given file with the buffer. */
83 _check_file_contents(char * const filepath
, char * const buf
, size_t buf_len
)
87 char file_buf
[buf_len
];
89 fd
= open(filepath
, O_RDONLY
);
92 read(fd
, file_buf
, buf_len
);
95 result
= memcmp(buf
, file_buf
, buf_len
);
101 /* Spawn with the given args and attributes, and waits for the child. */
103 _spawn_and_wait(char ** args
, posix_spawnattr_t
*attr
)
108 if (posix_spawn(&pid
, args
[0], NULL
, attr
, args
, NULL
)) {
111 if (waitpid(pid
, &status
, 0) < 0) {
115 if (WIFEXITED(status
) && (WEXITSTATUS(status
) == 0)) {
122 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
125 "Test the subsystem-related functions",
126 T_META_CHECK_LEAKS(false))
130 posix_spawnattr_t attr
= NULL
;
132 char file_name
[RANDOM_STRING_LEN
];
133 char overflow_file_name
[PATH_MAX
- RANDOM_STRING_LEN
];
134 char subsystem_name
[RANDOM_STRING_LEN
];
136 char file_path
[PATH_MAX
];
137 char subsystem_path
[PATH_MAX
];
138 char subsystem_tmp_path
[PATH_MAX
];
139 char subsystem_file_path
[PATH_MAX
];
140 char overflow_file_path
[PATH_MAX
];
141 char overflow_subsystem_file_path
[PATH_MAX
];
143 char * args
[] = { HELPER_PATH
, HELPER_BEHAVIOR_NOT_SET
, overflow_file_path
, "", NULL
};
145 /* Seed rand() from /dev/random, and generate our random file names. */
147 _generate_random_string(file_name
, sizeof(file_name
));
148 _generate_random_string(overflow_file_name
, sizeof(overflow_file_name
));
149 _generate_random_string(subsystem_name
, sizeof(subsystem_name
));
151 /* Generate pathnames. */
152 sprintf(file_path
, "/tmp/%s", file_name
);
153 sprintf(overflow_file_path
, "/tmp/%s", overflow_file_name
);
154 sprintf(subsystem_path
, "/tmp/%s", subsystem_name
);
155 sprintf(subsystem_tmp_path
, "%s/tmp", subsystem_path
);
156 sprintf(subsystem_file_path
, "%s/%s", subsystem_path
, file_path
);
159 * Initial setup for the test; we'll need our subsystem
160 * directory and a /tmp/ for it.
162 T_QUIET
; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_path
, 0777), "Create subsystem directory");
163 T_QUIET
; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_tmp_path
, 0777), "Create subsystem /tmp/ directory");
164 T_QUIET
; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_init(&attr
), "posix_spawnattr_init");
166 /* open and stat with no subsystem. */
167 args
[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE
;
168 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), -1, "open_with_subsystem with no subsystem");
170 args
[1] = HELPER_BEHAVIOR_STAT_NONE
;
171 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with no subsystem");
173 T_QUIET
; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_set_subsystem_root_path_np(&attr
, subsystem_path
), "Set subsystem root path");
176 * Test behavior when there is no main file and the subsystem
177 * file path is longer than PATH_MAX.
179 args
[1] = HELPER_BEHAVIOR_OPEN_OVERFLOW
;
181 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "open_with_subsystem with overflow");
183 args
[1] = HELPER_BEHAVIOR_STAT_OVERFLOW
;
185 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with overflow");
187 /* O_CREAT is strictly disallowed; test this. */
188 args
[1] = HELPER_BEHAVIOR_OPEN_O_CREAT
;
191 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "open_with_subsystem with O_CREAT");
194 * Test valid use of open_with_subsystem and
195 * stat_with_subsystem. We've got 4 cases to
196 * test: neither file exists, the subsystem
197 * file exists, both files exist, and the
200 /* Neither file exists. */
201 args
[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE
;
203 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), -1, "open_with_subsystem with no file");
205 args
[1] = HELPER_BEHAVIOR_STAT_NONE
;
207 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with no file");
209 /* Subsystem file exists. */
210 T_QUIET
; T_ASSERT_TRUE(_create_file(subsystem_file_path
), "Create subsystem file");
212 args
[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE
;
213 args
[3] = "with subsystem file";
215 result
= _spawn_and_wait(args
, &attr
);
218 result
= _check_file_contents(subsystem_file_path
, args
[3], strlen(args
[3]));
221 T_ASSERT_EQ_INT(result
, 0, "open_with_subsystem with subsystem file");
223 args
[1] = HELPER_BEHAVIOR_STAT_NOT_MAIN
;
225 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with subsystem file");
227 /* Both files exist. */
228 T_QUIET
; T_ASSERT_TRUE(_create_file(file_path
), "Create main file");
230 args
[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE
;
231 args
[3] = "with both files";
233 result
= _spawn_and_wait(args
, &attr
);
236 result
= _check_file_contents(file_path
, args
[3], strlen(args
[3]));
239 T_ASSERT_EQ_INT(result
, 0, "open_with_subsystem with both files");
241 args
[1] = HELPER_BEHAVIOR_STAT_MAIN
;
243 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with both files");
245 /* Main file exists. */
246 T_QUIET
; T_EXPECT_POSIX_SUCCESS(unlink(subsystem_file_path
), "Delete subsystem file");
248 args
[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE
;
249 args
[3] = "with main file";
251 result
= _spawn_and_wait(args
, &attr
);
254 result
= _check_file_contents(file_path
, args
[3], strlen(args
[3]));
257 T_ASSERT_EQ_INT(result
, 0, "open_with_subsystem with main file");
259 args
[1] = HELPER_BEHAVIOR_STAT_MAIN
;
261 T_ASSERT_EQ_INT(_spawn_and_wait(args
, &attr
), 0, "stat_with_subsystem with main file");
263 /* We're done; clean everything up. */
264 T_QUIET
; T_EXPECT_POSIX_SUCCESS(unlink(file_path
), "Delete main file");
265 T_QUIET
; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_tmp_path
), "Remove subsystem /tmp/ directory");
266 T_QUIET
; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_path
), "Remove subsystem directory");
267 T_QUIET
; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_destroy(&attr
), "posix_spawnattr_destroy");