]>
Commit | Line | Data |
---|---|---|
3d9156a7 A |
1 | /* |
2 | * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_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. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #include <stdbool.h> | |
25 | #include <stdlib.h> | |
26 | #include <stdio.h> | |
27 | #include <fcntl.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/mman.h> | |
30 | #include <sys/stat.h> | |
31 | #include <string.h> | |
32 | #include <pthread.h> | |
33 | ||
34 | static bool def_unix03 = false; | |
35 | /* Catastrophic errors only, including "out of memory" */ | |
36 | static bool parse_error = false; | |
37 | static bool bootstrapping = false; | |
38 | static bool parsed = false; | |
39 | #define UNIX2003_DEFAULT_MODE true | |
40 | static bool unix2003_mode = UNIX2003_DEFAULT_MODE; | |
41 | ||
42 | static pthread_once_t threadsafe = PTHREAD_ONCE_INIT; | |
43 | ||
44 | /* There was once a lot of parsing and the ability to set diffrent commands | |
45 | to diffrent modes. That is gone, but some of the scaffolding remains */ | |
46 | ||
47 | static void check_env_var(void) { | |
48 | char *mode = getenv("COMMAND_MODE"); | |
49 | ||
50 | if (mode) { | |
51 | if (!strcasecmp(mode, "legacy")) { | |
52 | unix2003_mode = false; | |
53 | } else { | |
54 | if (!strcasecmp(mode, "unix2003")) { | |
55 | unix2003_mode = true; | |
56 | } else { | |
57 | parse_error = true; | |
58 | unix2003_mode = UNIX2003_DEFAULT_MODE; | |
59 | } | |
60 | } | |
61 | } | |
62 | } | |
63 | ||
64 | /* Function is expected to be something like libc/malloc for a libc call, | |
65 | or bin/date for command line utilities. Modes are currently: | |
66 | Legacy - pre-tiger behaviour, presumably UNIX2003 incompatable | |
67 | UNIX2003 - Unix 2003 spec compliant | |
68 | Bootstrap - only seen by (parts of) libc. The compat_mode system is | |
69 | still starting up. This will be seen while compat_mode parses it's | |
70 | config file, or reads the cache file, and only by libc functions it calls. | |
71 | Error - the conf file could not be parsed, either due to a severe | |
72 | syntax error, an I/O error, or an out of memory condition | |
73 | ||
74 | mode names are case insensitatave. You can use | ^ & and even ! | |
75 | but no () yet, and that stuff hasn't been tested much yet, nor | |
76 | has it been optimised. | |
77 | */ | |
78 | ||
79 | bool | |
80 | compat_mode(const char *function, const char *mode) { | |
81 | if (!parsed && !bootstrapping) { | |
82 | pthread_once(&threadsafe, check_env_var); | |
83 | parsed = true; | |
84 | } | |
85 | ||
86 | bool want2003 = !strcasecmp("unix2003", mode); | |
87 | ||
88 | if (want2003) { | |
89 | return unix2003_mode; | |
90 | } | |
91 | ||
92 | bool want_legacy = !strcasecmp("legacy", mode); | |
93 | ||
94 | if (want_legacy) { | |
95 | return !unix2003_mode; | |
96 | } | |
97 | ||
98 | bool want_bootstrap = !strcasecmp("bootstrap", mode); | |
99 | ||
100 | if (want_bootstrap) { | |
101 | return bootstrapping; | |
102 | } | |
103 | ||
104 | bool want_error = !strcasecmp("error", mode); | |
105 | ||
106 | if (want_error) { | |
107 | return parse_error; | |
108 | } | |
109 | ||
110 | char *op = NULL; | |
111 | ||
112 | if (op = strpbrk(mode, "!^&|")) { | |
113 | if (*op == '!') { | |
114 | if (op != mode) goto syn_error; | |
115 | return !compat_mode(function, mode +1); | |
116 | } | |
117 | ||
118 | /* XXX char tmp[] would be better for left_arg, but | |
119 | we are not sure what the max size should be... is | |
120 | alloca(3) frowned on? */ | |
121 | int left_sz = 1 + (op - mode); | |
122 | char *left_arg = malloc(left_sz); | |
123 | strlcpy(left_arg, mode, left_sz); | |
124 | bool left = compat_mode(function, left_arg); | |
125 | free(left_arg); | |
126 | bool right = compat_mode(function, op +1); | |
127 | ||
128 | /* XXX check leftOPright syntax errors */ | |
129 | ||
130 | switch(*op) { | |
131 | case '^': | |
132 | return left ^ right; | |
133 | case '&': | |
134 | return left && right; | |
135 | case '|': | |
136 | return left || right; | |
137 | default: | |
138 | goto syn_error; | |
139 | } | |
140 | } | |
141 | ||
142 | syn_error: | |
143 | fprintf(stderr, "invalid mode %s (while checking for %s)\n", | |
144 | mode, function); | |
145 | ||
146 | return false; | |
147 | } | |
148 | ||
149 | #ifdef SELF_TEST_COMPAT_MODE | |
150 | ||
151 | #include <assert.h> | |
152 | ||
153 | #define NEXPECTED 3 | |
154 | ||
155 | typedef struct { | |
156 | char *mode; | |
157 | /* [0] is unix2003 mode, [1] is legacy, [2] is Invalid_Mode */ | |
158 | bool expected[NEXPECTED]; | |
159 | } testcase; | |
160 | ||
161 | testcase cases[] = { | |
162 | { "unix2003", {true, false, true}}, | |
163 | { "legacy", {false, true, false}}, | |
164 | { "bootstrap", {false, false, false}}, | |
165 | { "unix2003|legacy", {true, true, true}}, | |
166 | { "unix2003&legacy", {false, false, false}}, | |
167 | { "unix2003|legacy|bootstrap", {true, true, true}}, | |
168 | { "unix2003&legacy&bootstrap", {false, false, false}}, | |
169 | { "!unix2003", {false, true, false}}, | |
170 | { "!legacy", {true, false, true}}, | |
171 | /* XXX ! with compound statments */ | |
172 | { "unix2003^bootstrap", {true, false, true}}, | |
173 | { "unix2003^legacy", {true, true, true}}, | |
174 | { "&unix2003", {false, false, false}}, | |
175 | { "unix2003&", {false, false, false}}, | |
176 | { "unix2003!legacy", {false, false, false}}, | |
177 | { "unix2003&error", {false, false, true}}, | |
178 | { "error", {false, false, true}}, | |
179 | { "error|unix2003", {true, false, true}}, | |
180 | { "error|legacy", {false, true, true}}, | |
181 | { "error&legacy", {false, false, false}}, | |
182 | }; | |
183 | ||
184 | int ncases = sizeof(cases)/sizeof(testcase); | |
185 | ||
186 | int | |
187 | main(int argc, char *argv[]) { | |
188 | int i, j; | |
189 | int failures = 0; | |
190 | char *settings[] = { "unix2003", "legacy", "Invalid Mode"}; | |
191 | ||
192 | assert(sizeof(settings) / sizeof(char *) == NEXPECTED); | |
193 | ||
194 | for(i = 0; i < NEXPECTED; ++i) { | |
195 | setenv("COMMAND_MODE", settings[i], 1); | |
196 | char *compat_env = getenv("COMMAND_MODE"); | |
197 | printf("$COMMAND_MODE = %s\n", compat_env); | |
198 | if (i != 0) { | |
199 | /* here we force COMMAND_MODE to be checked again, which | |
200 | is normally impossiable because check_env_var() is a static | |
201 | function, but really nothing except the test cases wants to | |
202 | try it anyway... */ | |
203 | check_env_var(); | |
204 | } | |
205 | for(j = 0; j < ncases; ++j) { | |
206 | bool ret = compat_mode("bin/compat_mode", cases[j].mode); | |
207 | bool expect = cases[j].expected[i]; | |
208 | ||
209 | if (expect != ret) { | |
210 | failures++; | |
211 | } | |
212 | ||
213 | printf("Case %s got %d expected %d%s\n", | |
214 | cases[j].mode, ret, expect, (ret == expect) ? "" : " FAILED"); | |
215 | } | |
216 | } | |
217 | ||
218 | /* We have ncases entries in cases[], but each is run multiple | |
219 | times (once per entry in the settings array) thus the multiply */ | |
220 | printf("Passed %d of %d cases\n", | |
221 | NEXPECTED*ncases - failures, NEXPECTED*ncases); | |
222 | ||
223 | return failures ? 1 : 0; | |
224 | } | |
225 | ||
226 | #endif |