PageRenderTime 172ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/config.c

https://bitbucket.org/ifcaro/open-ps2-loader/
C | 548 lines | 414 code | 105 blank | 29 comment | 93 complexity | 66932e82fc2813ba3838480dbe0d5590 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0
  1. /*
  2. Copyright 2009, Ifcaro & volca
  3. Licenced under Academic Free License version 3.0
  4. Review OpenUsbLd README & LICENSE files for further details.
  5. */
  6. #include "include/opl.h"
  7. #include "include/util.h"
  8. #include "include/ioman.h"
  9. #include <string.h>
  10. static u32 currentUID = 0;
  11. static config_set_t configFiles[CONFIG_INDEX_COUNT];
  12. static char legacyNetConfigPath[256] = "mc?:SYS-CONF/IPCONFIG.DAT";
  13. static int strToColor(const char *string, unsigned char *color) {
  14. int cnt=0, n=0;
  15. color[0]=0;
  16. color[1]=0;
  17. color[2]=0;
  18. if (!string || !*string) return 0;
  19. if (string[0]!='#') return 0;
  20. string++;
  21. while (*string) {
  22. int fh = fromHex(*string);
  23. if (fh >= 0) {
  24. color[n] = color[n] * 16 + fh;
  25. } else {
  26. break;
  27. }
  28. // Two characters per color
  29. if(cnt==1) {
  30. cnt=0;
  31. n++;
  32. }else{
  33. cnt++;
  34. }
  35. string++;
  36. }
  37. return 1;
  38. }
  39. /// true if given a whitespace character
  40. int isWS(char c) {
  41. return c == ' ' || c == '\t';
  42. }
  43. static int splitAssignment(char* line, char* key, size_t keymax, char* val, size_t valmax) {
  44. // skip whitespace
  45. for (;isWS(*line); ++line);
  46. // find "=".
  47. // If found, the text before is key, after is val.
  48. // Otherwise malformed string is encountered
  49. char* eqpos = strchr(line, '=');
  50. if (eqpos) {
  51. // copy the name and the value
  52. size_t keylen = min(keymax, eqpos - line);
  53. strncpy(key, line, keylen);
  54. eqpos++;
  55. size_t vallen = min(valmax, strlen(line) - (eqpos - line));
  56. strncpy(val, eqpos, vallen);
  57. }
  58. return (int) eqpos;
  59. }
  60. static int parsePrefix(char* line, char* prefix) {
  61. // find "=".
  62. // If found, the text before is key, after is val.
  63. // Otherwise malformed string is encountered
  64. char* colpos = strchr(line, ':');
  65. if (colpos && colpos != line) {
  66. // copy the name and the value
  67. strncpy(prefix, line, colpos - line);
  68. return 1;
  69. } else {
  70. return 0;
  71. }
  72. }
  73. static int configKeyValidate(const char* key) {
  74. if (strlen(key) == 0)
  75. return 0;
  76. return !strchr(key, '=');
  77. }
  78. static struct config_value_t* allocConfigItem(const char* key, const char* val) {
  79. struct config_value_t* it = (struct config_value_t*) malloc(sizeof(struct config_value_t));
  80. strncpy(it->key, key, sizeof(it->key));
  81. it->key[sizeof(it->key)-1] = '\0';
  82. strncpy(it->val, val, sizeof(it->val));
  83. it->val[sizeof(it->val)-1] = '\0';
  84. it->next = NULL;
  85. return it;
  86. }
  87. /// Low level key addition. Does not check for uniqueness.
  88. static void addConfigValue(config_set_t* configSet, const char* key, const char* val) {
  89. if (!configSet->tail) {
  90. configSet->head = allocConfigItem(key, val);
  91. configSet->tail = configSet->head;
  92. } else {
  93. configSet->tail->next = allocConfigItem(key, val);
  94. configSet->tail = configSet->tail->next;
  95. }
  96. }
  97. static struct config_value_t* getConfigItemForName(config_set_t* configSet, const char* name) {
  98. struct config_value_t* val = configSet->head;
  99. while (val) {
  100. if (strncmp(val->key, name, sizeof(val->key)) == 0)
  101. break;
  102. val = val->next;
  103. }
  104. return val;
  105. }
  106. void configInit(char *prefix) {
  107. char path[256];
  108. if (prefix)
  109. snprintf(legacyNetConfigPath, sizeof(legacyNetConfigPath), "%s/IPCONFIG.DAT", prefix);
  110. else
  111. prefix = gBaseMCDir;
  112. snprintf(path, sizeof(path), "%s/conf_opl.cfg", prefix);
  113. configAlloc(CONFIG_OPL, &configFiles[CONFIG_INDEX_OPL], path);
  114. snprintf(path, sizeof(path), "%s/conf_last.cfg", prefix);
  115. configAlloc(CONFIG_LAST, &configFiles[CONFIG_INDEX_LAST], path);
  116. snprintf(path, sizeof(path), "%s/conf_apps.cfg", prefix);
  117. configAlloc(CONFIG_APPS, &configFiles[CONFIG_INDEX_APPS], path);
  118. snprintf(path, sizeof(path), "%s/conf_network.cfg", prefix);
  119. configAlloc(CONFIG_NETWORK, &configFiles[CONFIG_INDEX_NETWORK], path);
  120. }
  121. void configEnd() {
  122. int index = 0;
  123. while(index < CONFIG_INDEX_COUNT) {
  124. config_set_t *configSet = &configFiles[index];
  125. configClear(configSet);
  126. free(configSet->filename);
  127. configSet->filename = NULL;
  128. index++;
  129. }
  130. }
  131. config_set_t *configAlloc(int type, config_set_t *configSet, char *fileName) {
  132. if (!configSet)
  133. configSet = (config_set_t*) malloc(sizeof(config_set_t));
  134. configSet->uid = ++currentUID;
  135. configSet->type = type;
  136. configSet->head = NULL;
  137. configSet->tail = NULL;
  138. if (fileName) {
  139. int length = strlen(fileName) + 1;
  140. configSet->filename = (char*) malloc(length * sizeof(char));
  141. memcpy(configSet->filename, fileName, length);
  142. } else
  143. configSet->filename = NULL;
  144. configSet->modified = 0;
  145. return configSet;
  146. }
  147. void configFree(config_set_t *configSet) {
  148. configClear(configSet);
  149. free(configSet->filename);
  150. free(configSet);
  151. }
  152. config_set_t *configGetByType(int type) {
  153. int index = 0;
  154. while(index < CONFIG_INDEX_COUNT) {
  155. config_set_t *configSet = &configFiles[index];
  156. if (configSet->type == type)
  157. return configSet;
  158. index++;
  159. }
  160. return NULL;
  161. }
  162. int configSetStr(config_set_t* configSet, const char* key, const char* value) {
  163. if (!configKeyValidate(key))
  164. return 0;
  165. struct config_value_t *it = getConfigItemForName(configSet, key);
  166. if (it) {
  167. if (strncmp(it->val, value, sizeof(it->val)) != 0) {
  168. strncpy(it->val, value, sizeof(it->val));
  169. it->val[sizeof(it->val)-1] = '\0';
  170. if (it->key[0] != '#')
  171. configSet->modified = 1;
  172. }
  173. } else {
  174. addConfigValue(configSet, key, value);
  175. if (key[0] != '#')
  176. configSet->modified = 1;
  177. }
  178. return 1;
  179. }
  180. // sets the value to point to the value str in the config. Do not overwrite - it will overwrite the string in config
  181. int configGetStr(config_set_t* configSet, const char* key, const char** value) {
  182. if (!configKeyValidate(key))
  183. return 0;
  184. struct config_value_t *it = getConfigItemForName(configSet, key);
  185. if (it) {
  186. *value = it->val;
  187. return 1;
  188. } else
  189. return 0;
  190. }
  191. int configGetStrCopy(config_set_t* configSet, const char* key, char* value, int length) {
  192. const char *valref = NULL;
  193. if (configGetStr(configSet, key, &valref)) {
  194. strncpy(value, valref, length);
  195. value[length - 1] = '\0';
  196. return 1;
  197. } else {
  198. value[0] = '\0';
  199. return 0;
  200. }
  201. }
  202. int configSetInt(config_set_t* configSet, const char* key, const int value) {
  203. char tmp[12];
  204. snprintf(tmp, sizeof(tmp), "%d", value);
  205. return configSetStr(configSet, key, tmp);
  206. }
  207. int configGetInt(config_set_t* configSet, const char* key, int* value) {
  208. const char *valref = NULL;
  209. if (configGetStr(configSet, key, &valref)) {
  210. *value = atoi(valref);
  211. return 1;
  212. } else {
  213. return 0;
  214. }
  215. }
  216. int configSetColor(config_set_t* configSet, const char* key, unsigned char* color) {
  217. char tmp[8];
  218. snprintf(tmp, sizeof(tmp), "#%02X%02X%02X", color[0], color[1], color[2]);
  219. return configSetStr(configSet, key, tmp);
  220. }
  221. int configGetColor(config_set_t* configSet, const char* key, unsigned char* color) {
  222. const char *valref = NULL;
  223. if (configGetStr(configSet, key, &valref)) {
  224. strToColor(valref, color);
  225. return 1;
  226. } else {
  227. return 0;
  228. }
  229. }
  230. int configRemoveKey(config_set_t* configSet, const char* key) {
  231. if (!configKeyValidate(key))
  232. return 0;
  233. struct config_value_t* val = configSet->head;
  234. struct config_value_t* prev = NULL;
  235. while (val) {
  236. if (strncmp(val->key, key, sizeof(val->key)) == 0) {
  237. if (key[0] != '#')
  238. configSet->modified = 1;
  239. if (val == configSet->tail)
  240. configSet->tail = prev;
  241. val = val->next;
  242. if (prev) {
  243. free(prev->next);
  244. prev->next = val;
  245. }
  246. else {
  247. free(configSet->head);
  248. configSet->head = val;
  249. }
  250. } else {
  251. prev = val;
  252. val = val->next;
  253. }
  254. }
  255. return 1;
  256. }
  257. void configMerge(config_set_t* dest, const config_set_t *source) {
  258. struct config_value_t* val;
  259. for (val = source->head; val != NULL; val = val->next) {
  260. configSetStr(dest, val->key, val->val);
  261. }
  262. }
  263. int configReadLegacyIP(void) {
  264. config_set_t *configSet;
  265. char temp[16];
  266. int fd = openFile(legacyNetConfigPath, O_RDONLY);
  267. if (fd >= 0) {
  268. char ipconfig[256];
  269. int size = getFileSize(fd);
  270. fileXioRead(fd, &ipconfig, size);
  271. fileXioClose(fd);
  272. sscanf(ipconfig, "%d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d", &ps2_ip[0], &ps2_ip[1], &ps2_ip[2], &ps2_ip[3],
  273. &ps2_netmask[0], &ps2_netmask[1], &ps2_netmask[2], &ps2_netmask[3],
  274. &ps2_gateway[0], &ps2_gateway[1], &ps2_gateway[2], &ps2_gateway[3]);
  275. configSet = &configFiles[CONFIG_NETWORK];
  276. snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3]);
  277. configSetStr(configSet, CONFIG_NET_PS2_IP, temp);
  278. snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3]);
  279. configSetStr(configSet, CONFIG_NET_PS2_NETM, temp);
  280. snprintf(temp, sizeof(temp), "%d.%d.%d.%d", ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
  281. configSetStr(configSet, CONFIG_NET_PS2_GATEW, temp);
  282. //The legacy format has no setting for the DNS server, so duplicate the gateway address.
  283. configSetStr(configSet, CONFIG_NET_PS2_DNS, temp);
  284. return CONFIG_NETWORK;
  285. }
  286. return 0;
  287. }
  288. // dst has to have 5 bytes space
  289. void configGetDiscIDBinary(config_set_t* configSet, void* dst) {
  290. memset(dst, 0, 5);
  291. const char *gid = NULL;
  292. if (configGetStr(configSet, CONFIG_ITEM_DNAS, &gid)) {
  293. // convert from hex to binary
  294. char* cdst = dst;
  295. int p = 0;
  296. while (*gid && p < 10) {
  297. int dv = -1;
  298. while (dv < 0 && *gid) // skip spaces, etc
  299. dv = fromHex(*(gid++));
  300. if (dv < 0)
  301. break;
  302. *cdst = *cdst * 16 + dv;
  303. if ((++p & 1) == 0)
  304. cdst++;
  305. }
  306. }
  307. }
  308. static int configReadFileBuffer(file_buffer_t* fileBuffer, config_set_t* configSet) {
  309. char* line;
  310. unsigned int lineno = 0;
  311. char prefix[CONFIG_KEY_NAME_LEN];
  312. memset(prefix, 0, sizeof(prefix));
  313. while (readFileBuffer(fileBuffer, &line)) {
  314. lineno++;
  315. char key[CONFIG_KEY_NAME_LEN], val[CONFIG_KEY_VALUE_LEN];
  316. memset(key, 0, sizeof(key));
  317. memset(val, 0, sizeof(val));
  318. if (splitAssignment(line, key, sizeof(key), val, sizeof(val))) {
  319. /* if the line does not start with whitespace,
  320. * the prefix ends and we have to reset it
  321. */
  322. if (!isWS(line[0]))
  323. memset(prefix, 0, sizeof(prefix));
  324. // insert config value
  325. if (prefix[0]) {
  326. // we have a prefix
  327. char composedKey[CONFIG_KEY_NAME_LEN];
  328. snprintf(composedKey, sizeof(composedKey), "%s_%s", prefix, key);
  329. configSetStr(configSet, composedKey, val);
  330. } else {
  331. configSetStr(configSet, key, val);
  332. }
  333. } else if (parsePrefix(line, prefix)) {
  334. // prefix is set, that's about it
  335. } else {
  336. LOG("CONFIG Malformed file '%s' line %d: '%s'\n", configSet->filename, lineno, line);
  337. }
  338. }
  339. configSet->modified = 0;
  340. return configSet->type;
  341. }
  342. int configReadBuffer(config_set_t* configSet, const void *buffer, int size) {
  343. int ret;
  344. file_buffer_t* fileBuffer = openFileBufferBuffer(0, buffer, size);
  345. if (!fileBuffer) {
  346. configSet->modified = 0;
  347. return 0;
  348. }
  349. ret = configReadFileBuffer(fileBuffer, configSet);
  350. closeFileBuffer(fileBuffer);
  351. return ret;
  352. }
  353. int configRead(config_set_t* configSet) {
  354. int ret;
  355. file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_RDONLY, 0, 4096);
  356. if (!fileBuffer) {
  357. LOG("CONFIG No file %s.\n", configSet->filename);
  358. configSet->modified = 0;
  359. return 0;
  360. }
  361. ret = configReadFileBuffer(fileBuffer, configSet);
  362. closeFileBuffer(fileBuffer);
  363. return ret;
  364. }
  365. int configWrite(config_set_t* configSet) {
  366. if (configSet->modified) {
  367. file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_WRONLY | O_CREAT | O_TRUNC, 0, 4096);
  368. if (fileBuffer) {
  369. char line[512];
  370. struct config_value_t* cur = configSet->head;
  371. while (cur) {
  372. if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
  373. snprintf(line, sizeof(line), "%s=%s\r\n", cur->key, cur->val); // add windows CR+LF (0x0D 0x0A)
  374. writeFileBuffer(fileBuffer, line, strlen(line));
  375. }
  376. // and advance
  377. cur = cur->next;
  378. }
  379. closeFileBuffer(fileBuffer);
  380. configSet->modified = 0;
  381. return 1;
  382. }
  383. return 0;
  384. }
  385. return 1;
  386. }
  387. int configGetStat(config_set_t* configSet, iox_stat_t *stat) {
  388. return(fileXioGetStat(configSet->filename, stat) >= 0 ? 1 : 0);
  389. }
  390. void configClear(config_set_t* configSet) {
  391. while (configSet->head) {
  392. struct config_value_t* cur = configSet->head;
  393. configSet->head = cur->next;
  394. free(cur);
  395. }
  396. configSet->head = NULL;
  397. configSet->tail = NULL;
  398. configSet->modified = 1;
  399. }
  400. int configReadMulti(int types) {
  401. int result = 0, index;
  402. for (index = 0; index < CONFIG_INDEX_COUNT; index++) {
  403. config_set_t *configSet = &configFiles[index];
  404. if (configSet->type & types) {
  405. configClear(configSet);
  406. result |= configRead(configSet);
  407. }
  408. }
  409. //If the network configuration is to be loaded and one cannot be loaded, attempt to load from the legacy network config file.
  410. if ((types & CONFIG_NETWORK) && !(result & CONFIG_NETWORK))
  411. result |= configReadLegacyIP();
  412. return result;
  413. }
  414. int configWriteMulti(int types) {
  415. int result = 0, index;
  416. for (index = 0; index < CONFIG_INDEX_COUNT; index++) {
  417. config_set_t *configSet = &configFiles[index];
  418. if (configSet->type & types)
  419. result += configWrite(configSet);
  420. }
  421. return result;
  422. }
  423. #ifdef VMC
  424. void configGetVMC(config_set_t* configSet, char* vmc, int length, int slot) {
  425. char gkey[CONFIG_KEY_NAME_LEN];
  426. snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
  427. configGetStrCopy(configSet, gkey, vmc, length);
  428. }
  429. void configSetVMC(config_set_t* configSet, const char* vmc, int slot) {
  430. char gkey[CONFIG_KEY_NAME_LEN];
  431. if(vmc[0] == '\0') {
  432. configRemoveVMC(configSet, slot);
  433. return;
  434. }
  435. snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
  436. configSetStr(configSet, gkey, vmc);
  437. }
  438. void configRemoveVMC(config_set_t* configSet, int slot) {
  439. char gkey[CONFIG_KEY_NAME_LEN];
  440. snprintf(gkey, sizeof(gkey), "%s_%d", CONFIG_ITEM_VMC, slot);
  441. configRemoveKey(configSet, gkey);
  442. }
  443. #endif