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
24 static size_t appl_len = 0;
25 static char* g_appl_id = "#appl not initialized";
26 static char* appl_script = NULL;
27
28 /*
29 * This is also planned as an entry point for implementing the
30 * APF mapping, possibly with the chainloader setting envvars
31 * for how the namespace is made, and if not (.apf extension in appl_id)
32 * setup the context and functions required to do data lookups.
33 */
arcan_verifyload_appl(const char * appl_id,const char ** errc)34 bool arcan_verifyload_appl(const char* appl_id, const char** errc)
35 {
36 size_t app_len;
37
38 if (!appl_id || (app_len = strlen(appl_id)) == 0){
39 *errc = "no application specified";
40 return false;
41 }
42
43 /*
44 * NOTE: here is the place to check for .fap extension,
45 * and if found, take a separate route for setting up.
46 */
47 char* base = strdup(appl_id);
48 bool expand = true;
49
50 /*
51 * absolute/relative path? don't define namespaces using SYS_*
52 * will maintain STATE namespace set by paths. Absolute paths
53 * should only be presented from a privileged state (command-line
54 * or in-engine, not Lua->engine).
55 */
56 if (appl_id[0] == '/' || appl_id[0] == '\\' || appl_id[0] == '.'){
57 char* work = strdup(base);
58 char* dir = strdup( dirname( work ) );
59 free(work);
60
61 work = strdup(base);
62 free(base);
63 base = strdup( basename(work) );
64 free(work);
65
66 arcan_override_namespace(appl_id, RESOURCE_APPL);
67
68 arcan_softoverride_namespace(appl_id, RESOURCE_APPL_TEMP);
69 arcan_softoverride_namespace(dir, RESOURCE_SYS_APPLBASE);
70 arcan_softoverride_namespace(dir, RESOURCE_SYS_APPLSTORE);
71
72 free(dir);
73 expand = false;
74 }
75
76 /*
77 * with path stripped, we can make sure to see that we have a proper name
78 */
79 app_len = strlen(base);
80 for (size_t i = 0; i < app_len; i++){
81 if (!isalnum(base[i]) && base[i] != '_'){
82 *errc = "invalid character in appl_id (only a..Z _ 0..9 allowed)\n";
83 return false;
84 }
85 }
86
87 if (expand){
88 char* dir = arcan_expand_resource(base, RESOURCE_SYS_APPLBASE);
89 if (!dir){
90 *errc = "missing application base\n";
91 free(base);
92 return false;
93 }
94 arcan_override_namespace(dir, RESOURCE_APPL);
95 arcan_mem_free(dir);
96
97 dir = arcan_expand_resource(base, RESOURCE_SYS_APPLSTORE);
98 if (!dir){
99 *errc = "missing application temporary store\n";
100 free(base);
101 return false;
102 }
103 arcan_override_namespace(dir, RESOURCE_APPL_TEMP);
104 arcan_mem_free(dir);
105 }
106
107 /* state- storage has specific rules so it is always checked for expansion,
108 * if STATE is a subpath of shared, we have global application state (i.e.
109 * multiple scripts can use the same state storage for virtual machines),
110 * otherwise we expand */
111 char* p_a = arcan_expand_resource("", RESOURCE_APPL_SHARED);
112 char* p_b = arcan_expand_resource("", RESOURCE_SYS_APPLSTATE);
113 if (!p_b)
114 arcan_override_namespace(p_a, RESOURCE_APPL_STATE);
115 else if (strncmp(p_a, p_b, strlen(p_a)) == 0){
116 arcan_override_namespace(p_b, RESOURCE_APPL_STATE);
117 }
118 else {
119 arcan_mem_free(p_b);
120 p_b = arcan_expand_resource(base, RESOURCE_SYS_APPLSTATE);
121 arcan_override_namespace(p_b, RESOURCE_APPL_STATE);
122 }
123 arcan_mem_free(p_a);
124 arcan_mem_free(p_b);
125
126 char wbuf[ app_len + sizeof(".lua")];
127 snprintf(wbuf, sizeof(wbuf), "%s.lua", base);
128
129 char* script_path = arcan_expand_resource(wbuf, RESOURCE_APPL);
130 if (!script_path || !arcan_isfile(script_path)){
131 *errc = "missing script matching appl_id (see appname/appname.lua)";
132 arcan_mem_free(script_path);
133 return false;
134 }
135
136 /*
137 * Switch to appl- suppled fonts if a folder exists to avoid relying on res
138 * namespace pollution. Specific settings can still pin the namespace to
139 * prevent this action.
140 */
141 char* font_path = arcan_expand_resource("/fonts", RESOURCE_APPL);
142 if (font_path){
143 if (arcan_isdir(font_path))
144 arcan_override_namespace(font_path, RESOURCE_SYS_FONT);
145 free(font_path);
146 }
147
148 if (strcmp(g_appl_id, "#appl not initialized") != 0)
149 arcan_mem_free(g_appl_id);
150
151 g_appl_id = base;
152 appl_len = app_len;
153 appl_script = script_path;
154
155 return true;
156 }
157
arcan_appl_basesource(bool * file)158 const char* arcan_appl_basesource(bool* file)
159 {
160 *file = true;
161 return appl_script;
162 }
163
arcan_appl_id()164 const char* arcan_appl_id()
165 {
166 return g_appl_id;
167 }
168
arcan_appl_id_len()169 size_t arcan_appl_id_len()
170 {
171 return appl_len;
172 }
173
174