1 /*
2 * Copyright 2014-2016, Björn Ståhl
3 * License: 3-Clause BSD, see COPYING file in arcan source repository.
4 * Reference: http://arcan-fe.com
5 */
6
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <libgen.h>
12 #include <string.h>
13 #include <math.h>
14 #include <assert.h>
15 #include <ctype.h>
16
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #include <arcan_math.h>
22 #include <arcan_general.h>
23
arcan_isdir(const char * fn)24 bool arcan_isdir(const char* fn)
25 {
26 struct stat buf;
27 bool rv = false;
28
29 if (fn == NULL)
30 return false;
31
32 if (stat(fn, &buf) == 0)
33 rv = S_ISDIR(buf.st_mode);
34
35 return rv;
36 }
37
arcan_isfile(const char * fn)38 bool arcan_isfile(const char* fn)
39 {
40 struct stat buf;
41 bool rv = false;
42
43 if (fn == NULL)
44 return false;
45
46 if (stat(fn, &buf) == 0)
47 rv = S_ISREG(buf.st_mode) || S_ISFIFO(buf.st_mode) || S_ISSOCK(buf.st_mode);
48
49 return rv;
50 }
51
52 static char* pathks[] = {
53 "path_appl",
54 "path_resource",
55 "path_appltemp",
56 "path_state",
57 "path_applbase",
58 "path_applstore",
59 "path_statebase",
60 "path_font",
61 "path_bin",
62 "path_lib",
63 "path_log",
64 "path_script"
65 };
66
67 static char* pinks[] = {
68 "pin_appl",
69 "pin_resource",
70 "pin_appltemp",
71 "pin_state",
72 "pin_applbase",
73 "pin_applstore",
74 "pin_statebase",
75 "pin_font",
76 "pin_bin",
77 "pin_lib",
78 "pin_log",
79 "pin_script"
80 };
81
82 static char* envvs[] = {
83 "ARCAN_APPLPATH",
84 "ARCAN_RESOURCEPATH",
85 "ARCAN_APPLTEMPPATH",
86 "ARCAN_STATEPATH", /* will be ignored */
87 "ARCAN_APPLBASEPATH",
88 "ARCAN_APPLSTOREPATH",
89 "ARCAN_STATEBASEPATH",
90 "ARCAN_FONTPATH",
91 "ARCAN_BINPATH",
92 "ARCAN_LIBPATH",
93 "ARCAN_LOGPATH",
94 "ARCAN_SCRIPTPATH",
95 };
96
97 static char* pinvs[] = {
98 "ARCAN_APPLPIN",
99 "ARCAN_RESOURCEPIN",
100 "ARCAN_APPLTEMPPIN",
101 "ARCAN_STATEPIN", /* will be ignored */
102 "ARCAN_APPLBASEPIN",
103 "ARCAN_APPLSTOREPIN",
104 "ARCAN_STATEBASEPIN",
105 "ARCAN_FONTPIN",
106 "ARCAN_BINPIN",
107 "ARCAN_LIBPIN",
108 "ARCAN_LOGPIN",
109 "ARCAN_SCRIPTPIN"
110 };
111
alloc_cat(char * a,char * b)112 static char* alloc_cat(char* a, char* b)
113 {
114 size_t a_sz = strlen(a);
115 size_t b_sz = strlen(b);
116 char* newstr = malloc(a_sz + b_sz + 1);
117 newstr[a_sz + b_sz] = '\0';
118 memcpy(newstr, a, a_sz);
119 memcpy(newstr + a_sz, b, b_sz);
120 return newstr;
121 }
122
123 /*
124 * handle:
125 * abc [DEF] ghj [ARCAN_APPLPATH] klm [!.bla =>
126 * abc [DEF] ghj /usr/whatever klm [!.bla
127 * abc => abc
128 * [ARCAN_APPLPATH] apa [ARCAN_APPLPATH] => /usr/whatever apa /usr/whatever
129 * [ARCAN_APPLPATH => [ARCAN_APPLPATH
130 */
rep_str(char * instr)131 static char* rep_str(char* instr)
132 {
133 char* pos = instr;
134 char* beg;
135
136 while(1){
137 rep:
138 beg = strchr(pos, '[');
139 if (!beg)
140 return instr;
141
142 char* end = strchr(beg+1, ']');
143 if (!end)
144 return instr;
145
146 /* counter abc [ [ARCAN_APPLPATH] */
147 char* step;
148 while ((step = strchr(beg+1, '[')) && step < end)
149 beg = step;
150
151 *end = '\0';
152
153 for (size_t i = 0; i < sizeof(envvs)/sizeof(envvs[0]); i++){
154 if (strcmp(envvs[i], beg+1) == 0){
155 char* exp = arcan_expand_resource("", 1 << i);
156 if (exp){
157 *beg = '\0';
158 char* newstr = alloc_cat(instr, exp);
159 char* resstr = alloc_cat(newstr, end+1);
160 free(instr);
161 free(newstr);
162 pos = instr = resstr;
163 }
164 arcan_mem_free(exp);
165 goto rep; /* continue 2; */
166 }
167 }
168
169 *end = ']';
170 pos = end;
171 }
172 }
173
arcan_expand_namespaces(char ** inargs)174 char** arcan_expand_namespaces(char** inargs)
175 {
176 char** work = inargs;
177
178 while(*work){
179 *work = rep_str(*work);
180 work++;
181 }
182
183 return inargs;
184 }
185
binpath_unix()186 static char* binpath_unix()
187 {
188 char* binpath = NULL;
189
190 if (arcan_isfile( "./arcan_frameserver") )
191 binpath = strdup("./arcan_frameserver" );
192 else if (arcan_isfile( "/usr/local/bin/arcan_frameserver"))
193 binpath = strdup("/usr/local/bin/arcan_frameserver");
194 else if (arcan_isfile( "/usr/bin/arcan_frameserver" ))
195 binpath = strdup("/usr/bin/arcan_frameserver");
196 else ;
197
198 return binpath;
199 }
200
scriptpath_unix()201 static char* scriptpath_unix()
202 {
203 char* scrpath = NULL;
204
205 if (arcan_isdir("/usr/local/share/arcan/scripts"))
206 scrpath = "/usr/local/share/arcan/scripts";
207 else if (arcan_isdir("/usr/share/arcan/scripts"))
208 scrpath = "/usr/share/arcan/scripts";
209 else
210 ;
211 return scrpath;
212 }
213
unix_find(const char * fname)214 static char* unix_find(const char* fname)
215 {
216 char* res = NULL;
217 char* pathtbl[] = {
218 ".",
219 NULL, /* fill in with HOME */
220 "/usr/local/share/arcan",
221 "/usr/share/arcan",
222 NULL /* NULL terminates */
223 };
224
225 if (getenv("HOME")){
226 size_t len = strlen( getenv("HOME") ) + 9;
227 pathtbl[1] = malloc(len);
228 snprintf(pathtbl[1], len, "%s/.arcan", getenv("HOME") );
229 }
230 else
231 pathtbl[1] = strdup("");
232
233 size_t fn_l = strlen(fname);
234 for (char** base = pathtbl; *base != NULL; base++){
235 char buf[ fn_l + strlen(*base) + 2 ];
236 snprintf(buf, sizeof(buf), "%s/%s", *base, fname);
237
238 if (arcan_isdir(buf)){
239 res = strdup(buf);
240 break;
241 }
242 }
243
244 free(pathtbl[1]);
245 return res;
246 }
247
248 /*
249 * This is set-up to mimic the behavior of previous arcan
250 * version as much as possible. For other, more controlled settings,
251 * this is a good function to replace.
252 */
arcan_set_namespace_defaults()253 void arcan_set_namespace_defaults()
254 {
255 char* tmp = NULL;
256 uintptr_t tag;
257 cfg_lookup_fun get_config = platform_config_lookup(&tag);
258
259 /*
260 * use environment variables as hard overrides
261 */
262 for (int i = 0; i < sizeof( envvs ) / sizeof( envvs[0] ); i++){
263 char* tmp;
264 if (get_config(pathks[i], 0, &tmp, tag) && tmp){
265 arcan_override_namespace(tmp, 1 << i);
266 free(tmp);
267 }
268
269 tmp = getenv(envvs[i]);
270 if (tmp)
271 arcan_override_namespace(tmp, 1 << i);
272
273 if (getenv(pinvs[i]) || get_config(pinks[i], 0, NULL, tag))
274 arcan_pin_namespace(1 << i);
275 }
276
277 arcan_softoverride_namespace(tmp = scriptpath_unix(), RESOURCE_SYS_SCRIPTS);
278
279 /*
280 * legacy mapping from the < 0.5 days
281 */
282
283 arcan_softoverride_namespace(tmp = binpath_unix(), RESOURCE_SYS_BINS);
284 free(tmp);
285
286 char* respath = unix_find("resources");
287
288 if (!respath)
289 respath = arcan_expand_resource("", RESOURCE_APPL_SHARED);
290
291 if (respath){
292 size_t len = strlen(respath);
293 char debug_dir[ len + sizeof("/logs") ];
294 char font_dir[ len + sizeof("/fonts") ];
295
296 snprintf(debug_dir, sizeof(debug_dir), "%s/logs", respath);
297 snprintf(font_dir, sizeof(font_dir), "%s/fonts", respath);
298
299 arcan_softoverride_namespace(respath, RESOURCE_APPL_SHARED);
300 arcan_softoverride_namespace(debug_dir, RESOURCE_SYS_DEBUG);
301 arcan_softoverride_namespace(respath, RESOURCE_APPL_STATE);
302 arcan_softoverride_namespace(font_dir, RESOURCE_SYS_FONT);
303 arcan_mem_free(respath);
304 }
305
306 char* scrpath = unix_find("appl");
307
308 if (scrpath){
309 arcan_softoverride_namespace(scrpath, RESOURCE_SYS_APPLBASE);
310 arcan_softoverride_namespace(scrpath, RESOURCE_SYS_APPLSTORE);
311 arcan_mem_free(scrpath);
312 }
313
314 tmp = arcan_expand_resource("", RESOURCE_SYS_APPLSTATE);
315 if (!tmp){
316 tmp = arcan_expand_resource("savestates", RESOURCE_APPL_SHARED);
317 if (tmp)
318 arcan_override_namespace(tmp, RESOURCE_SYS_APPLSTATE);
319 }
320
321 arcan_mem_free(tmp);
322 }
323