Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/i386/libsaio/stringTable.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29#include "bootstruct.h"
30#include "libsaio.h"
31#include "boot.h"
32#include "xml.h"
33
34extern char *Language;
35extern char *LoadableFamilies;
36
37bool sysConfigValid;
38
39#if UNUSED
40
41/*
42 * Compare a string to a key with quoted characters
43 */
44static inline int
45keyncmp(const char *str, const char *key, int n)
46{
47 int c;
48 while (n--) {
49c = *key++;
50if (c == '\\') {
51 switch(c = *key++) {
52 case 'n':
53c = '\n';
54break;
55 case 'r':
56c = '\r';
57break;
58 case 't':
59c = '\t';
60break;
61 default:
62break;
63 }
64} else if (c == '\"') {
65 // Premature end of key
66 return 1;
67}
68if (c != *str++) {
69 return 1;
70}
71 }
72 return 0;
73}
74
75static void eatThru(char val, const char **table_p)
76{
77register const char *table = *table_p;
78register bool found = false;
79
80while (*table && !found)
81{
82if (*table == '\\') table += 2;
83else
84{
85if (*table == val) found = true;
86table++;
87}
88}
89*table_p = table;
90}
91
92/* Remove key and its associated value from the table. */
93
94bool
95removeKeyFromTable(const char *key, char *table)
96{
97 register int len;
98 register char *tab;
99 char *buf;
100
101 len = strlen(key);
102 tab = (char *)table;
103 buf = (char *)malloc(len + 3);
104
105 sprintf(buf, "\"%s\"", key);
106 len = strlen(buf);
107
108 while(*tab) {
109 if(strncmp(buf, tab, len) == 0) {
110 char c;
111
112 while((c = *(tab + len)) != ';') {
113 if(c == 0) {
114 len = -1;
115 goto out;
116 }
117 len++;
118 }
119 len++;
120 if(*(tab + len) == '\n') len++;
121 goto out;
122 }
123 tab++;
124 }
125 len = -1;
126out:
127 free(buf);
128
129 if(len == -1) return false;
130
131 while((*tab = *(tab + len))) {
132 tab++;
133 }
134
135 return true;
136}
137
138char *newStringFromList(char **list, int *size)
139{
140char *begin = *list, *end;
141char *newstr;
142int newsize = *size;
143int bufsize;
144
145while (*begin && newsize && isspace(*begin)) {
146begin++;
147newsize--;
148}
149end = begin;
150while (*end && newsize && !isspace(*end)) {
151end++;
152newsize--;
153}
154if (begin == end) {
155return 0;
156}
157bufsize = end - begin + 1;
158newstr = malloc(bufsize);
159strlcpy(newstr, begin, bufsize);
160*list = end;
161*size = newsize;
162return newstr;
163}
164
165#endif
166
167/*
168 * compress == compress escaped characters to one character
169 */
170int stringLength(const char *table, int compress)
171{
172int ret = 0;
173
174while (*table) {
175if (*table == '\\') {
176table += 2;
177ret += 1 + (compress ? 0 : 1);
178} else {
179if (*table == '\"') {
180return ret;
181}
182ret++;
183table++;
184}
185}
186return ret;
187}
188
189
190bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)
191{
192if (config->dictionary != 0 ) {
193// Look up key in XML dictionary
194//TagPtr value;
195TagPtr value = XMLGetProperty(config->dictionary, key);
196if (value != 0) {
197if (value->type != kTagTypeString) {
198error("Non-string tag '%s' found in config file\n", key);
199return false;
200}
201*val = value->string;
202*size = strlen(value->string);
203return true;
204}
205} else {
206
207// Legacy plist-style table
208
209}
210
211return false;
212}
213
214#if UNUSED
215
216/*
217 * Returns a new malloc'ed string if one is found
218 * in the string table matching 'key'. Also translates
219 * \n escapes in the string.
220 */
221char *newStringForStringTableKey(char *table, char *key, config_file_t *config)
222{
223const char *val;
224char *newstr, *p;
225int size;
226
227if (getValueForConfigTableKey(config, key, &val, &size)) {
228newstr = (char *)malloc(size+1);
229for (p = newstr; size; size--, p++, val++) {
230if ((*p = *val) == '\\') {
231switch (*++val) {
232case 'r':
233*p = '\r';
234break;
235case 'n':
236*p = '\n';
237break;
238case 't':
239*p = '\t';
240break;
241default:
242*p = *val;
243break;
244}
245size--;
246}
247}
248*p = '\0';
249return newstr;
250} else {
251return 0;
252}
253}
254
255#endif
256
257char *
258newStringForKey(char *key, config_file_t *config)
259{
260const char *val;
261char *newstr;
262int size;
263
264if (getValueForKey(key, &val, &size, config) && size) {
265newstr = (char *)malloc(size + 1);
266strlcpy(newstr, val, size + 1);
267return newstr;
268} else {
269return 0;
270}
271}
272
273/* parse a command line
274 * in the form: [<argument> ...] [<option>=<value> ...]
275 * both <option> and <value> must be either composed of
276 * non-whitespace characters, or enclosed in quotes.
277 */
278
279static const char *getToken(const char *line, const char **begin, int *len)
280{
281if (*line == '\"') {
282*begin = ++line;
283while (*line && *line != '\"') {
284line++;
285}
286*len = line++ - *begin;
287} else {
288*begin = line;
289while (*line && !isspace(*line) && *line != '=') {
290line++;
291}
292*len = line - *begin;
293}
294return line;
295}
296
297bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
298{
299const char *key, *value;
300int key_len, value_len;
301bool retval = false;
302
303while (*line) {
304/* look for keyword or argument */
305while (isspace(*line)) {
306line++;
307}
308
309/* now look for '=' or whitespace */
310line = getToken(line, &key, &key_len);
311/* line now points to '=' or space */
312if (*line && !isspace(*line)) {
313line = getToken(++line, &value, &value_len);
314} else {
315value = line;
316value_len = 0;
317}
318if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0) {
319// create a new string
320char* newstr = malloc(value_len + 1);
321strncpy(newstr, value, value_len);
322newstr[value_len] = 0;
323
324*matchval = newstr;
325*len = value_len;
326retval = true;
327/* Continue to look for this key; last one wins. */
328}
329}
330
331return retval;
332}
333
334/* Return NULL if no option has been successfully retrieved, or the string otherwise */
335const char *getStringForKey(const char *key, config_file_t *config)
336{
337static const char *value = 0;
338int len = 0;
339if (!getValueForKey(key, &value, &len, config))
340{
341value = 0;
342}
343return value;
344}
345
346
347/* Returns TRUE if a value was found, FALSE otherwise.
348 * The boolean value of the key is stored in 'val'.
349 */
350
351bool getBoolForKey(const char *key, bool *result_val, config_file_t *config)
352{
353 const char *key_val;
354 int size;
355
356if (getValueForKey(key, &key_val, &size, config))
357{
358if ((size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y'))
359{
360*result_val = true;
361}
362else
363{
364*result_val = false;
365}
366return true;
367}
368return false;
369}
370
371bool getIntForKey(const char *key, int *value, config_file_t *config)
372{
373const char *val;
374int size, sum;
375bool negative = false;
376
377if (getValueForKey(key, &val, &size, config)) {
378if (size) {
379if (*val == '-') {
380negative = true;
381val++;
382size--;
383}
384
385for (sum = 0; size > 0; size--) {
386if (*val < '0' || *val > '9') {
387return false;
388}
389
390sum = (sum * 10) + (*val++ - '0');
391}
392
393if (negative) {
394sum = -sum;
395}
396*value = sum;
397return true;
398}
399}
400return false;
401}
402
403/*
404 *
405 */
406
407bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
408{
409const char *val;
410
411int size = 0;
412int sum = 0;
413
414bool negative = false;
415bool percentage = false;
416
417if (getValueForKey(key, &val, &size, config)) {
418if ( size ) {
419if (*val == '-') {
420negative = true;
421val++;
422size--;
423}
424
425if (val[size-1] == '%') {
426percentage = true;
427size--;
428}
429
430// convert string to integer
431for (sum = 0; size > 0; size--) {
432if (*val < '0' || *val > '9') {
433return false;
434}
435
436sum = (sum * 10) + (*val++ - '0');
437}
438
439if (percentage) {
440sum = ( dimension_max * sum ) / 100;
441}
442
443// calculate offset from opposite origin
444if (negative) {
445sum = ( ( dimension_max - object_size ) - sum );
446}
447
448} else {
449
450// null value calculate center
451sum = ( dimension_max - object_size ) / 2;
452
453}
454
455*value = (uint16_t) sum;
456return true;
457}
458
459// key not found
460return false;
461}
462
463/*
464 *get color value from plist format #RRGGBB
465 */
466
467bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
468{
469const char *val;
470int size;
471
472if (getValueForKey(key, &val, &size, config))
473{
474if (*val == '#') {
475val++;
476*value = strtol(val, NULL, 16);
477return true;
478}
479}
480return false;
481}
482
483bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
484{
485const char *overrideVal;
486int overrideSize;
487bool override, ret;
488
489if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) {
490return true;
491}
492
493ret = getValueForConfigTableKey(config, key, val, size);
494
495// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)
496// and prefer its values with the exceptions for
497// "Kernel"="mach_kernel" and "Kernel Flags"="".
498
499if (config->canOverride) {
500if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize)) {
501override = true;
502
503// NOTE: Values are defined by apple as being in com.apple.Boot.plist
504// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey
505if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0)) {
506override = false;
507}
508
509if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0)) {
510override = false;
511}
512
513if (override) {
514*val = overrideVal;
515*size = overrideSize;
516ret = true;
517}
518}
519}
520return ret;
521}
522
523
524#if UNUSED
525void
526printSystemConfig(char *p1)
527{
528char *p2 = p1, tmp;
529
530while (*p1 != '\0') {
531while (*p2 != '\0' && *p2 != '\n') {
532p2++;
533}
534tmp = *p2;
535*p2 = '\0';
536printf("%s\n", p1);
537*p2 = tmp;
538if (tmp == '\0') {
539break;
540}
541p1 = ++p2;
542 }
543}
544#endif
545
546//==========================================================================
547// ParseXMLFile
548// Modifies the input buffer.
549// Expects to see one dictionary in the XML file.
550// Puts the first dictionary it finds in the
551// tag pointer and returns 0, or returns -1 if not found
552// (and does not modify dict pointer).
553// Prints an error message if there is a parsing error.
554//
555int ParseXMLFile( char *buffer, TagPtr *dict )
556{
557long length, pos;
558TagPtr tag;
559pos = 0;
560char *configBuffer;
561
562configBuffer = malloc(strlen(buffer)+1);
563strcpy(configBuffer, buffer);
564
565while (1) {
566length = XMLParseNextTag(configBuffer + pos, &tag);
567if (length == -1) {
568break;
569}
570
571pos += length;
572
573if (tag == 0) {
574continue;
575}
576if (tag->type == kTagTypeDict) {
577break;
578}
579
580XMLFreeTag(tag);
581}
582free(configBuffer);
583if (length < 0) {
584error ("Error parsing plist file\n");
585return -1;
586}
587*dict = tag;
588return 0;
589}
590
591/* loadConfigFile
592 *
593 * Returns 0 - successful.
594 * -1 - unsuccesful.
595 */
596int loadConfigFile (const char *configFile, config_file_t *config)
597{
598int fd, count;
599
600if ((fd = open_bvdev("bt(0,0)", configFile, 0)) < 0)
601{
602return -1;
603}
604// read file
605count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
606close(fd);
607
608// build xml dictionary
609ParseXMLFile(config->plist, &config->dictionary);
610return 0;
611}
612
613
614/* loadSystemConfig
615 *
616 * Returns 0 - successful.
617 * -1 - unsuccesful.
618 */
619int loadSystemConfig(config_file_t *config)
620{
621char *dirspec[] = {
622"/Mac OS X Install Data/com.apple.Boot.plist",// OS X Installer (Lion 10.7)
623"/OS X Install Data/com.apple.Boot.plist",// OS X Installer (10.8+)
624//"/.IABootFiles/com.apple.Boot.plist",// OS X Installer
625"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",// com.apple.Boot.plist
626"/com.apple.recovery.boot/com.apple.Boot.plist"// OS X Recovery
627};
628
629int i, fd, count, ret=-1;
630
631for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
632{
633if ((fd = open(dirspec[i], 0)) >= 0)
634{
635// read file
636count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
637close(fd);
638
639// build xml dictionary
640ParseXMLFile(config->plist, &config->dictionary);
641sysConfigValid = true;
642ret=0;
643
644break;
645}
646}
647
648if(ret == -1) ret = loadHelperConfig(config);
649
650// Always enable canOverride flag (for SystemConfig)
651config->canOverride = true;
652
653return ret;
654}
655
656/* loadChameleonConfig
657 *
658 * Returns 0 - successful.
659 * -1 - unsuccesful.
660 */
661int loadChameleonConfig(config_file_t *config, BVRef chain)
662{
663char *dirspec[] = {
664"/Extra/org.chameleon.Boot.plist",
665"/Extra/com.apple.Boot.plist", /* DEPRECIATED */
666};
667
668int i;
669
670for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
671{
672if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 )
673{
674return 0;
675}
676
677if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 )
678{
679return 0;
680}
681
682if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 )
683{
684return 0;
685}
686BVRef bvr;
687for ( bvr = chain; bvr; bvr = bvr->next ) /* C99 Error */
688{
689char device[256];
690getDeviceDescription(bvr, device);
691
692if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 )
693{
694return 0;
695}
696}
697}
698return -1;
699}
700
701/* loadChameleonConfigForDevice
702 *
703 * Returns 0 - successful.
704 * -1 - unsuccesful.
705 */
706int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)
707{
708char full_path[1024];
709int fd;
710
711snprintf(full_path, sizeof(full_path), "%s%s", device, path);
712
713if ((fd = open(full_path, 0)) >= 0)
714{
715// Check for depreciated file names and annoy the user about it.
716if(strstr(full_path, "com.apple.Boot.plist")) {
717error("%s is depreciated.\n", full_path);
718full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;
719error("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);
720pause("");
721}
722// read file
723read(fd, config->plist, IO_CONFIG_DATA_SIZE);
724close(fd);
725
726// build xml dictionary
727ParseXMLFile(config->plist, &config->dictionary);
728sysConfigValid = true;
729return 0;
730}
731return -1;
732}
733
734/* loadHelperConfig
735 *
736 * Returns 0 - successful.
737 * -1 - unsuccesful.
738 */
739int loadHelperConfig(config_file_t *config)
740{
741char *dirspec[] = {
742"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
743"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
744"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
745};
746
747int i, fd, count, ret=-1;
748
749for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
750{
751if ((fd = open(dirspec[i], 0)) >= 0)
752{
753// read file
754count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
755close(fd);
756
757// build xml dictionary
758ParseXMLFile(config->plist, &config->dictionary);
759sysConfigValid = true;
760ret=0;
761break;
762}
763}
764return ret;
765}
766
767char * newString(const char * oldString)
768{
769if ( oldString )
770{
771return strcpy(malloc(strlen(oldString)+1), oldString);
772}
773else
774{
775return NULL;
776}
777}
778
779/*
780 * Extracts the next argument from the command line, double quotes are allowed here.
781 */
782char * getNextArg(char ** argPtr, char * val)
783{
784char * ptr = *argPtr;
785const char * strStart;
786int len = 0;
787bool isQuoted = false;
788
789*val = '\0';
790
791// Scan for the next non-whitespace character.
792while ( *ptr && (*ptr == ' ' || *ptr == '=') )
793{
794ptr++;
795}
796
797strStart = ptr;
798
799// Skip the leading double quote character.
800if (*ptr == '\"')
801{
802isQuoted = true;
803ptr++;
804strStart++;
805}
806
807// Scan for the argument terminator character.
808// This can be either a NULL character - in case we reach the end of the string,
809// a double quote in case of quoted argument,
810// or a whitespace character (' ' or '=') for non-quoted argument.
811while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
812 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
813 ) {
814ptr++;
815}
816
817len = ptr - strStart;
818
819// Skip the closing double quote character and adjust
820// the starting pointer for the next getNextArg call.
821if (*ptr && isQuoted && *ptr == '\"') {
822ptr++;
823}
824
825// Copy the extracted argument to val.
826strncat(val, strStart, len);
827
828// Set command line pointer.
829*argPtr = ptr;
830
831return ptr;
832}
833

Archive Download this file

Revision: HEAD