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 * Compare a string to a key with quoted characters
42 */
43static inline int
44keyncmp(const char *str, const char *key, int n)
45{
46 int c;
47 while (n--) {
48c = *key++;
49if (c == '\\') {
50 switch(c = *key++) {
51 case 'n':
52c = '\n';
53break;
54 case 'r':
55c = '\r';
56break;
57 case 't':
58c = '\t';
59break;
60 default:
61break;
62 }
63} else if (c == '\"') {
64 // Premature end of key
65 return 1;
66}
67if (c != *str++) {
68 return 1;
69}
70 }
71 return 0;
72}
73
74static void eatThru(char val, const char **table_p)
75{
76register const char *table = *table_p;
77register bool found = false;
78
79while (*table && !found)
80{
81if (*table == '\\') table += 2;
82else
83{
84if (*table == val) found = true;
85table++;
86}
87}
88*table_p = table;
89}
90
91/* Remove key and its associated value from the table. */
92
93bool
94removeKeyFromTable(const char *key, char *table)
95{
96 register int len;
97 register char *tab;
98 char *buf;
99
100 len = strlen(key);
101 tab = (char *)table;
102 buf = (char *)malloc(len + 3);
103
104 sprintf(buf, "\"%s\"", key);
105 len = strlen(buf);
106
107 while(*tab) {
108 if(strncmp(buf, tab, len) == 0) {
109 char c;
110
111 while((c = *(tab + len)) != ';') {
112 if(c == 0) {
113 len = -1;
114 goto out;
115 }
116 len++;
117 }
118 len++;
119 if(*(tab + len) == '\n') len++;
120 goto out;
121 }
122 tab++;
123 }
124 len = -1;
125out:
126 free(buf);
127
128 if(len == -1) return false;
129
130 while((*tab = *(tab + len))) {
131 tab++;
132 }
133
134 return true;
135}
136
137char *newStringFromList(char **list, int *size)
138{
139char *begin = *list, *end;
140char *newstr;
141int newsize = *size;
142int bufsize;
143
144while (*begin && newsize && isspace(*begin)) {
145begin++;
146newsize--;
147}
148end = begin;
149while (*end && newsize && !isspace(*end)) {
150end++;
151newsize--;
152}
153if (begin == end) {
154return 0;
155}
156bufsize = end - begin + 1;
157newstr = malloc(bufsize);
158strlcpy(newstr, begin, bufsize);
159*list = end;
160*size = newsize;
161return newstr;
162}
163
164#endif
165
166/*
167 * compress == compress escaped characters to one character
168 */
169int stringLength(const char *table, int compress)
170{
171int ret = 0;
172
173while (*table) {
174if (*table == '\\') {
175table += 2;
176ret += 1 + (compress ? 0 : 1);
177} else {
178if (*table == '\"') {
179return ret;
180}
181ret++;
182table++;
183}
184}
185return ret;
186}
187
188
189bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)
190{
191if (config->dictionary != 0 ) {
192// Look up key in XML dictionary
193//TagPtr value;
194TagPtr value = XMLGetProperty(config->dictionary, key);
195if (value != 0) {
196if (value->type != kTagTypeString) {
197error("Non-string tag '%s' found in config file\n", key);
198return false;
199}
200*val = value->string;
201*size = strlen(value->string);
202return true;
203}
204} else {
205
206// Legacy plist-style table
207
208}
209
210return false;
211}
212
213#if UNUSED
214
215/*
216 * Returns a new malloc'ed string if one is found
217 * in the string table matching 'key'. Also translates
218 * \n escapes in the string.
219 */
220char *newStringForStringTableKey(char *table, char *key, config_file_t *config)
221{
222const char *val;
223char *newstr, *p;
224int size;
225
226if (getValueForConfigTableKey(config, key, &val, &size)) {
227newstr = (char *)malloc(size+1);
228for (p = newstr; size; size--, p++, val++) {
229if ((*p = *val) == '\\') {
230switch (*++val) {
231case 'r':
232*p = '\r';
233break;
234case 'n':
235*p = '\n';
236break;
237case 't':
238*p = '\t';
239break;
240default:
241*p = *val;
242break;
243}
244size--;
245}
246}
247*p = '\0';
248return newstr;
249} else {
250return 0;
251}
252}
253
254#endif
255
256char *
257newStringForKey(char *key, config_file_t *config)
258{
259const char *val;
260char *newstr;
261int size;
262
263if (getValueForKey(key, &val, &size, config) && size) {
264newstr = (char *)malloc(size + 1);
265strlcpy(newstr, val, size + 1);
266return newstr;
267} else {
268return 0;
269}
270}
271
272/* parse a command line
273 * in the form: [<argument> ...] [<option>=<value> ...]
274 * both <option> and <value> must be either composed of
275 * non-whitespace characters, or enclosed in quotes.
276 */
277
278static const char *getToken(const char *line, const char **begin, int *len)
279{
280if (*line == '\"') {
281*begin = ++line;
282while (*line && *line != '\"') {
283line++;
284}
285*len = line++ - *begin;
286} else {
287*begin = line;
288while (*line && !isspace(*line) && *line != '=') {
289line++;
290}
291*len = line - *begin;
292}
293return line;
294}
295
296bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
297{
298const char *key, *value;
299int key_len, value_len;
300bool retval = false;
301
302while (*line) {
303/* look for keyword or argument */
304while (isspace(*line)) {
305line++;
306}
307
308/* now look for '=' or whitespace */
309line = getToken(line, &key, &key_len);
310/* line now points to '=' or space */
311if (*line && !isspace(*line)) {
312line = getToken(++line, &value, &value_len);
313} else {
314value = line;
315value_len = 0;
316}
317if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0) {
318// create a new string
319char* newstr = malloc(value_len + 1);
320strncpy(newstr, value, value_len);
321newstr[value_len] = 0;
322
323*matchval = newstr;
324*len = value_len;
325retval = true;
326/* Continue to look for this key; last one wins. */
327}
328}
329
330return retval;
331}
332
333/* Return NULL if no option has been successfully retrieved, or the string otherwise */
334const char *getStringForKey(const char *key, config_file_t *config)
335{
336static const char *value = 0;
337int len = 0;
338if (!getValueForKey(key, &value, &len, config)) {
339value = 0;
340}
341return value;
342}
343
344
345/* Returns TRUE if a value was found, FALSE otherwise.
346 * The boolean value of the key is stored in 'val'.
347 */
348
349bool getBoolForKey(const char *key, bool *result_val, config_file_t *config)
350{
351 const char *key_val;
352 int size;
353
354if (getValueForKey(key, &key_val, &size, config)) {
355if ((size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y')) {
356*result_val = true;
357} else {
358*result_val = false;
359}
360return true;
361}
362return false;
363}
364
365bool getIntForKey(const char *key, int *value, config_file_t *config)
366{
367const char *val;
368int size, sum;
369bool negative = false;
370
371if (getValueForKey(key, &val, &size, config)) {
372if (size) {
373if (*val == '-') {
374negative = true;
375val++;
376size--;
377}
378
379for (sum = 0; size > 0; size--) {
380if (*val < '0' || *val > '9') {
381return false;
382}
383
384sum = (sum * 10) + (*val++ - '0');
385}
386
387if (negative) {
388sum = -sum;
389}
390*value = sum;
391return true;
392}
393}
394return false;
395}
396
397/*
398 *
399 */
400
401bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
402{
403const char *val;
404
405int size = 0;
406int sum = 0;
407
408bool negative = false;
409bool percentage = false;
410
411if (getValueForKey(key, &val, &size, config)) {
412if ( size ) {
413if (*val == '-') {
414negative = true;
415val++;
416size--;
417}
418
419if (val[size-1] == '%') {
420percentage = true;
421size--;
422}
423
424// convert string to integer
425for (sum = 0; size > 0; size--) {
426if (*val < '0' || *val > '9') {
427return false;
428}
429
430sum = (sum * 10) + (*val++ - '0');
431}
432
433if (percentage) {
434sum = ( dimension_max * sum ) / 100;
435}
436
437// calculate offset from opposite origin
438if (negative) {
439sum = ( ( dimension_max - object_size ) - sum );
440}
441
442} else {
443
444// null value calculate center
445sum = ( dimension_max - object_size ) / 2;
446
447}
448
449*value = (uint16_t) sum;
450return true;
451}
452
453// key not found
454return false;
455}
456
457/*
458 *get color value from plist format #RRGGBB
459 */
460
461bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
462{
463const char *val;
464int size;
465
466if (getValueForKey(key, &val, &size, config))
467{
468if (*val == '#') {
469val++;
470*value = strtol(val, NULL, 16);
471return true;
472}
473}
474return false;
475}
476
477bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
478{
479const char *overrideVal;
480int overrideSize;
481bool override, ret;
482
483if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) {
484return true;
485}
486
487ret = getValueForConfigTableKey(config, key, val, size);
488
489// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)
490// and prefer its values with the exceptions for
491// "Kernel"="mach_kernel" and "Kernel Flags"="".
492
493if (config->canOverride) {
494if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize)) {
495override = true;
496
497// NOTE: Values are defined by apple as being in com.apple.Boot.plist
498// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey
499if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0)) {
500override = false;
501}
502
503if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0)) {
504override = false;
505}
506
507if (override) {
508*val = overrideVal;
509*size = overrideSize;
510ret = true;
511}
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) {
596return -1;
597}
598// read file
599count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
600close(fd);
601
602// build xml dictionary
603ParseXMLFile(config->plist, &config->dictionary);
604return 0;
605}
606
607
608/* loadSystemConfig
609 *
610 * Returns 0 - successful.
611 * -1 - unsuccesful.
612 */
613int loadSystemConfig(config_file_t *config)
614{
615char *dirspec[] = {
616"/Mac OS X Install Data/com.apple.Boot.plist",// OS X Installer (Lion 10.7)
617"/OS X Install Data/com.apple.Boot.plist",// OS X Installer (10.8+)
618//"/.IABootFiles/com.apple.Boot.plist",// OS X Installer
619"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",// com.apple.Boot.plist
620"/com.apple.recovery.boot/com.apple.Boot.plist"// OS X Recovery
621};
622
623int i, fd, count, ret=-1;
624
625for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {
626if ((fd = open(dirspec[i], 0)) >= 0) {
627// read file
628count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
629close(fd);
630
631// build xml dictionary
632ParseXMLFile(config->plist, &config->dictionary);
633sysConfigValid = true;
634ret=0;
635
636break;
637}
638}
639
640if(ret == -1) ret = loadHelperConfig(config);
641
642// Always enable canOverride flag (for SystemConfig)
643config->canOverride = true;
644
645return ret;
646}
647
648/* loadChameleonConfig
649 *
650 * Returns 0 - successful.
651 * -1 - unsuccesful.
652 */
653int loadChameleonConfig(config_file_t *config, BVRef chain)
654{
655char *dirspec[] = {
656"/Extra/org.chameleon.Boot.plist",
657"/Extra/com.apple.Boot.plist", /* DEPRECIATED */
658};
659
660int i;
661
662for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {
663if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 ) {
664return 0;
665}
666if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 ) {
667return 0;
668}
669if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 ) {
670return 0;
671}
672BVRef bvr;
673for ( bvr = chain; bvr; bvr = bvr->next ) { /* C99 Error */
674char device[256];
675getDeviceDescription(bvr, device);
676
677if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 ) {
678return 0;
679}
680}
681}
682return -1;
683}
684
685/* loadChameleonConfigForDevice
686 *
687 * Returns 0 - successful.
688 * -1 - unsuccesful.
689 */
690int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)
691{
692char full_path[1024];
693int fd;
694
695snprintf(full_path, sizeof(full_path), "%s%s", device, path);
696
697if ((fd = open(full_path, 0)) >= 0) {
698// Check for depreciated file names and annoy the user about it.
699if(strstr(full_path, "com.apple.Boot.plist")) {
700error("%s is depreciated.\n", full_path);
701full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;
702error("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);
703pause("");
704}
705// read file
706read(fd, config->plist, IO_CONFIG_DATA_SIZE);
707close(fd);
708
709// build xml dictionary
710ParseXMLFile(config->plist, &config->dictionary);
711sysConfigValid = true;
712return 0;
713}
714return -1;
715}
716
717/* loadHelperConfig
718 *
719 * Returns 0 - successful.
720 * -1 - unsuccesful.
721 */
722int loadHelperConfig(config_file_t *config)
723{
724char *dirspec[] = {
725"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
726"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
727"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
728};
729
730int i, fd, count, ret=-1;
731
732for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++) {
733if ((fd = open(dirspec[i], 0)) >= 0) {
734// read file
735count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
736close(fd);
737
738// build xml dictionary
739ParseXMLFile(config->plist, &config->dictionary);
740sysConfigValid = true;
741ret=0;
742break;
743}
744}
745return ret;
746}
747
748char * newString(const char * oldString)
749{
750if ( oldString ) {
751return strcpy(malloc(strlen(oldString)+1), oldString);
752} else {
753return NULL;
754}
755}
756
757/*
758 * Extracts the next argument from the command line, double quotes are allowed here.
759 */
760char * getNextArg(char ** argPtr, char * val)
761{
762char * ptr = *argPtr;
763const char * strStart;
764int len = 0;
765bool isQuoted = false;
766
767*val = '\0';
768
769// Scan for the next non-whitespace character.
770while ( *ptr && (*ptr == ' ' || *ptr == '=') ) {
771ptr++;
772}
773
774strStart = ptr;
775
776// Skip the leading double quote character.
777if (*ptr == '\"') {
778isQuoted = true;
779ptr++;
780strStart++;
781}
782
783// Scan for the argument terminator character.
784// This can be either a NULL character - in case we reach the end of the string,
785// a double quote in case of quoted argument,
786// or a whitespace character (' ' or '=') for non-quoted argument.
787while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
788 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
789 ) {
790ptr++;
791}
792
793len = ptr - strStart;
794
795// Skip the closing double quote character and adjust
796// the starting pointer for the next getNextArg call.
797if (*ptr && isQuoted && *ptr == '\"') {
798ptr++;
799}
800
801// Copy the extracted argument to val.
802strncat(val, strStart, len);
803
804// Set command line pointer.
805*argPtr = ptr;
806
807return ptr;
808}
809

Archive Download this file

Revision: 2531