Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/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
194TagPtr value;
195value = 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)) {
340value = 0;
341}
342return value;
343}
344
345
346/* Returns TRUE if a value was found, FALSE otherwise.
347 * The boolean value of the key is stored in 'val'.
348 */
349
350bool getBoolForKey( const char *key, bool *result_val, config_file_t *config )
351{
352 const char *key_val;
353 int size;
354
355if (getValueForKey(key, &key_val, &size, config)) {
356if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {
357*result_val = true;
358} else {
359*result_val = false;
360}
361return true;
362}
363return false;
364}
365
366bool getIntForKey( const char *key, int *value, config_file_t *config )
367{
368const char *val;
369int size, sum;
370bool negative = false;
371
372if (getValueForKey(key, &val, &size, config)) {
373if ( size ) {
374if (*val == '-') {
375negative = true;
376val++;
377size--;
378}
379
380for (sum = 0; size > 0; size--) {
381if (*val < '0' || *val > '9') {
382return false;
383}
384
385sum = (sum * 10) + (*val++ - '0');
386}
387
388if (negative) {
389sum = -sum;
390}
391*value = sum;
392return true;
393}
394}
395return false;
396}
397
398/*
399 *
400 */
401
402bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
403{
404const char *val;
405
406int size = 0;
407int sum = 0;
408
409bool negative = false;
410bool percentage = false;
411
412if (getValueForKey(key, &val, &size, config)) {
413if ( size ) {
414if (*val == '-') {
415negative = true;
416val++;
417size--;
418}
419
420if (val[size-1] == '%') {
421percentage = true;
422size--;
423}
424
425// convert string to integer
426for (sum = 0; size > 0; size--) {
427if (*val < '0' || *val > '9') {
428return false;
429}
430
431sum = (sum * 10) + (*val++ - '0');
432}
433
434if (percentage) {
435sum = ( dimension_max * sum ) / 100;
436}
437
438// calculate offset from opposite origin
439if (negative) {
440sum = ( ( dimension_max - object_size ) - sum );
441}
442
443} else {
444
445// null value calculate center
446sum = ( dimension_max - object_size ) / 2;
447
448}
449
450*value = (uint16_t) sum;
451return true;
452}
453
454// key not found
455return false;
456}
457
458/*
459 *get color value from plist format #RRGGBB
460 */
461
462bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
463{
464const char *val;
465int size;
466
467if (getValueForKey(key, &val, &size, config))
468{
469if (*val == '#') {
470val++;
471*value = strtol(val, NULL, 16);
472return true;
473}
474}
475return false;
476}
477
478bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
479{
480const char *overrideVal;
481int overrideSize;
482bool override, ret;
483
484if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) {
485return true;
486}
487
488ret = getValueForConfigTableKey(config, key, val, size);
489
490// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)
491// and prefer its values with the exceptions for
492// "Kernel"="mach_kernel" and "Kernel Flags"="".
493
494if (config->canOverride) {
495if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize)) {
496override = true;
497
498// NOTE: Values are defined by apple as being in com.apple.Boot.plist
499// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey
500if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0)) {
501override = false;
502}
503
504if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0)) {
505override = false;
506}
507
508if (override) {
509*val = overrideVal;
510*size = overrideSize;
511return true;
512}
513}
514}
515return ret;
516}
517
518
519#if UNUSED
520void
521printSystemConfig(char *p1)
522{
523char *p2 = p1, tmp;
524
525while (*p1 != '\0') {
526while (*p2 != '\0' && *p2 != '\n') {
527p2++;
528}
529tmp = *p2;
530*p2 = '\0';
531printf("%s\n", p1);
532*p2 = tmp;
533if (tmp == '\0') {
534break;
535}
536p1 = ++p2;
537 }
538}
539#endif
540
541//==========================================================================
542// ParseXMLFile
543// Modifies the input buffer.
544// Expects to see one dictionary in the XML file.
545// Puts the first dictionary it finds in the
546// tag pointer and returns 0, or returns -1 if not found
547// (and does not modify dict pointer).
548// Prints an error message if there is a parsing error.
549//
550int ParseXMLFile( char * buffer, TagPtr * dict )
551{
552long length, pos;
553TagPtr tag;
554pos = 0;
555char *configBuffer;
556
557configBuffer = malloc(strlen(buffer)+1);
558strcpy(configBuffer, buffer);
559
560while (1) {
561length = XMLParseNextTag(configBuffer + pos, &tag);
562if (length == -1) {
563break;
564}
565
566pos += length;
567
568if (tag == 0) {
569continue;
570}
571if (tag->type == kTagTypeDict) {
572break;
573}
574
575XMLFreeTag(tag);
576}
577free(configBuffer);
578if (length < 0) {
579error ("Error parsing plist file\n");
580return -1;
581}
582*dict = tag;
583return 0;
584}
585
586/* loadConfigFile
587 *
588 * Returns 0 - successful.
589 * -1 - unsuccesful.
590 */
591int loadConfigFile (const char *configFile, config_file_t *config)
592{
593int fd, count;
594
595if ((fd = open_bvdev("bt(0,0)", configFile, 0)) < 0)
596{
597return -1;
598}
599// read file
600count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
601close(fd);
602
603// build xml dictionary
604ParseXMLFile(config->plist, &config->dictionary);
605return 0;
606}
607
608
609/* loadSystemConfig
610 *
611 * Returns 0 - successful.
612 * -1 - unsuccesful.
613 */
614int loadSystemConfig(config_file_t *config)
615{
616char *dirspec[] = {
617"/Mac OS X Install Data/com.apple.Boot.plist",// OS X Installer (Lion 10.7)
618"/OS X Install Data/com.apple.Boot.plist",// OS X Installer (10.8+)
619"/.IABootFiles/com.apple.Boot.plist",// OS X Installer
620"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",// com.boot.Apple.plist
621"/com.apple.recovery.boot/com.apple.Boot.plist"// OS X Recovery
622};
623
624int i, fd, count, ret=-1;
625
626for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
627{
628if ((fd = open(dirspec[i], 0)) >= 0)
629{
630// read file
631count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
632close(fd);
633
634// build xml dictionary
635ParseXMLFile(config->plist, &config->dictionary);
636sysConfigValid = true;
637ret=0;
638
639break;
640}
641}
642
643if(ret == -1) ret = loadHelperConfig(config);
644
645// Always enable canOverride flag (for SystemConfig)
646config->canOverride = true;
647
648return ret;
649}
650
651/* loadChameleonConfig
652 *
653 * Returns 0 - successful.
654 * -1 - unsuccesful.
655 */
656int loadChameleonConfig(config_file_t *config, BVRef chain)
657{
658char *dirspec[] = {
659"/Extra/org.chameleon.Boot.plist",
660"/Extra/com.apple.Boot.plist", /* DEPRECIATED */
661};
662
663int i;
664
665for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
666{
667if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 )
668{
669return 0;
670}
671
672if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 )
673{
674return 0;
675}
676
677if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 )
678{
679return 0;
680}
681BVRef bvr;
682for ( bvr = chain; bvr; bvr = bvr->next ) /* C99 Error */
683{
684char device[256];
685getDeviceDescription(bvr, device);
686
687if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 )
688{
689return 0;
690}
691}
692}
693return -1;
694}
695
696/* loadChameleonConfigForDevice
697 *
698 * Returns 0 - successful.
699 * -1 - unsuccesful.
700 */
701int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)
702{
703char full_path[1024];
704int fd;
705
706snprintf(full_path, sizeof(full_path), "%s%s", device, path);
707
708if ((fd = open(full_path, 0)) >= 0)
709{
710// Check for depreciated file names and annoy the user about it.
711if(strstr(full_path, "com.apple.Boot.plist")) {
712printf("%s is depreciated.\n", full_path);
713full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;
714printf("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);
715pause();
716}
717// read file
718read(fd, config->plist, IO_CONFIG_DATA_SIZE);
719close(fd);
720
721// build xml dictionary
722ParseXMLFile(config->plist, &config->dictionary);
723sysConfigValid = true;
724return 0;
725}
726return -1;
727}
728
729/* loadHelperConfig
730 *
731 * Returns 0 - successful.
732 * -1 - unsuccesful.
733 */
734int loadHelperConfig(config_file_t *config)
735{
736char *dirspec[] = {
737"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
738"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
739"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
740};
741
742int i, fd, count, ret=-1;
743
744for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
745{
746if ((fd = open(dirspec[i], 0)) >= 0)
747{
748// read file
749count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
750close(fd);
751
752// build xml dictionary
753ParseXMLFile(config->plist, &config->dictionary);
754sysConfigValid = true;
755ret=0;
756break;
757}
758}
759return ret;
760}
761
762char * newString(const char * oldString)
763{
764if ( oldString )
765{
766return strcpy(malloc(strlen(oldString)+1), oldString);
767}
768else
769{
770return NULL;
771}
772}
773
774/*
775 * Extracts the next argument from the command line, double quotes are allowed here.
776 */
777char * getNextArg(char ** argPtr, char * val)
778{
779char * ptr = *argPtr;
780const char * strStart;
781int len = 0;
782bool isQuoted = false;
783
784*val = '\0';
785
786// Scan for the next non-whitespace character.
787while ( *ptr && (*ptr == ' ' || *ptr == '=') )
788{
789ptr++;
790}
791
792strStart = ptr;
793
794// Skip the leading double quote character.
795if (*ptr == '\"')
796{
797isQuoted = true;
798ptr++;
799strStart++;
800}
801
802// Scan for the argument terminator character.
803// This can be either a NULL character - in case we reach the end of the string,
804// a double quote in case of quoted argument,
805// or a whitespace character (' ' or '=') for non-quoted argument.
806while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
807 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
808 ) {
809ptr++;
810}
811
812len = ptr - strStart;
813
814// Skip the closing double quote character and adjust
815// the starting pointer for the next getNextArg call.
816if (*ptr && isQuoted && *ptr == '\"') {
817ptr++;
818}
819
820// Copy the extracted argument to val.
821strncat(val, strStart, len);
822
823// Set command line pointer.
824*argPtr = ptr;
825
826return ptr;
827}
828

Archive Download this file

Revision: 2488