Chameleon

Chameleon Svn Source Tree

Root/trunk/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 snprintf(buf, len + 3,"\"%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);
159if (!newstr)
160{
161return 0;
162}
163strlcpy(newstr, begin, bufsize);
164*list = end;
165*size = newsize;
166return newstr;
167}
168
169#endif
170
171/*
172 * compress == compress escaped characters to one character
173 */
174int stringLength(const char *table, int compress)
175{
176int ret = 0;
177
178while (*table) {
179if (*table == '\\') {
180table += 2;
181ret += 1 + (compress ? 0 : 1);
182}
183else
184{
185if (*table == '\"')
186{
187return ret;
188}
189ret++;
190table++;
191}
192}
193return ret;
194}
195
196
197bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)
198{
199if (config->dictionary != 0 ) {
200// Look up key in XML dictionary
201TagPtr value;
202value = XMLGetProperty(config->dictionary, key);
203if (value != 0) {
204if (value->type != kTagTypeString) {
205error("Non-string tag '%s' found in config file\n", key);
206return false;
207}
208*val = value->string;
209*size = strlen(value->string);
210return true;
211}
212} else {
213
214// Legacy plist-style table
215
216}
217
218return false;
219}
220
221#if UNUSED
222
223/*
224 * Returns a new malloc'ed string if one is found
225 * in the string table matching 'key'. Also translates
226 * \n escapes in the string.
227 */
228char *newStringForStringTableKey(char *table, char *key, config_file_t *config)
229{
230const char *val;
231char *newstr, *p;
232int size;
233
234if (getValueForConfigTableKey(config, key, &val, &size))
235{
236newstr = (char *)malloc(size+1);
237if (!newstr)
238{
239return 0;
240}
241for (p = newstr; size; size--, p++, val++) {
242if ((*p = *val) == '\\') {
243switch (*++val) {
244case 'r':
245*p = '\r';
246break;
247case 'n':
248*p = '\n';
249break;
250case 't':
251*p = '\t';
252break;
253default:
254*p = *val;
255break;
256}
257size--;
258}
259}
260*p = '\0';
261return newstr;
262} else {
263return 0;
264}
265}
266
267#endif
268
269char *
270newStringForKey(char *key, config_file_t *config)
271{
272const char *val;
273char *newstr;
274int size;
275
276if (getValueForKey(key, &val, &size, config) && size) {
277newstr = (char *)malloc(size + 1);
278if (!newstr)
279{
280return 0;
281}
282strlcpy(newstr, val, size + 1);
283return newstr;
284} else {
285return 0;
286}
287}
288
289/* parse a command line
290 * in the form: [<argument> ...] [<option>=<value> ...]
291 * both <option> and <value> must be either composed of
292 * non-whitespace characters, or enclosed in quotes.
293 */
294
295static const char *getToken(const char *line, const char **begin, int *len)
296{
297if (*line == '\"') {
298*begin = ++line;
299while (*line && *line != '\"') {
300line++;
301}
302*len = line++ - *begin;
303} else {
304*begin = line;
305while (*line && !isspace(*line) && *line != '=') {
306line++;
307}
308*len = line - *begin;
309}
310return line;
311}
312
313bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
314{
315const char *key, *value;
316int key_len, value_len;
317bool retval = false;
318
319while (*line) {
320/* look for keyword or argument */
321while (isspace(*line))
322{
323line++;
324}
325
326/* now look for '=' or whitespace */
327line = getToken(line, &key, &key_len);
328/* line now points to '=' or space */
329if (*line && !isspace(*line)) {
330line = getToken(++line, &value, &value_len);
331} else {
332value = line;
333value_len = 0;
334}
335if ((strlen(match) == key_len) && strncmp(match, key, key_len) == 0)
336{
337// create a new string
338char* newstr = malloc(value_len + 1);
339strncpy(newstr, value, value_len);
340newstr[value_len] = 0;
341
342*matchval = newstr;
343*len = value_len;
344retval = true;
345/* Continue to look for this key; last one wins. */
346}
347}
348
349return retval;
350}
351
352/* Return NULL if no option has been successfully retrieved, or the string otherwise */
353const char *getStringForKey(const char *key, config_file_t *config)
354{
355static const char *value = 0;
356int len = 0;
357if (!getValueForKey(key, &value, &len, config))
358{
359value = 0;
360}
361return value;
362}
363
364
365/* Returns TRUE if a value was found, FALSE otherwise.
366 * The boolean value of the key is stored in 'val'.
367 */
368
369bool getBoolForKey(const char *key, bool *result_val, config_file_t *config)
370{
371 const char *key_val;
372 int size;
373
374if (getValueForKey(key, &key_val, &size, config))
375{
376if ((size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y'))
377{
378*result_val = true;
379}
380else
381{
382*result_val = false;
383}
384return true;
385}
386return false;
387}
388
389bool getIntForKey(const char *key, int *value, config_file_t *config)
390{
391const char *val;
392int size, sum;
393bool negative = false;
394
395if (getValueForKey(key, &val, &size, config))
396{
397if (size)
398{
399if (*val == '-')
400{
401negative = true;
402val++;
403size--;
404}
405
406for (sum = 0; size > 0; size--)
407{
408if (*val < '0' || *val > '9')
409{
410return false;
411}
412
413sum = (sum * 10) + (*val++ - '0');
414}
415
416if (negative)
417{
418sum = -sum;
419}
420*value = sum;
421return true;
422}
423}
424return false;
425}
426/*
427 *
428 */
429
430bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
431{
432const char *val;
433
434int size = 0;
435int sum = 0;
436
437bool negative = false;
438bool percentage = false;
439
440if (getValueForKey(key, &val, &size, config))
441{
442if ( size )
443{
444if (*val == '-')
445{
446negative = true;
447val++;
448size--;
449}
450
451if (val[size-1] == '%')
452{
453percentage = true;
454size--;
455}
456
457// convert string to integer
458for (sum = 0; size > 0; size--)
459{
460if (*val < '0' || *val > '9')
461{
462return false;
463}
464
465sum = (sum * 10) + (*val++ - '0');
466}
467
468if (percentage)
469{
470sum = ( dimension_max * sum ) / 100;
471}
472
473// calculate offset from opposite origin
474if (negative)
475{
476sum = ( ( dimension_max - object_size ) - sum );
477}
478
479}
480else
481{
482
483// null value calculate center
484sum = ( dimension_max - object_size ) / 2;
485
486}
487
488*value = (uint16_t) sum;
489return true;
490}
491
492// key not found
493return false;
494}
495
496/*
497 *get color value from plist format #RRGGBB
498 */
499
500bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
501{
502const char *val;
503int size;
504
505if (getValueForKey(key, &val, &size, config))
506{
507if (*val == '#') {
508val++;
509*value = strtol(val, NULL, 16);
510return true;
511}
512}
513return false;
514}
515
516bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
517{
518const char *overrideVal;
519int overrideSize;
520bool override, ret;
521
522if (getValueForBootKey(bootArgs->CommandLine, key, val, size))
523{
524return true;
525}
526
527ret = getValueForConfigTableKey(config, key, val, size);
528
529// Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden)
530// and prefer its values with the exceptions for
531// "Kernel"="mach_kernel" and "Kernel Flags"="".
532
533if (config->canOverride)
534{
535if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize))
536{
537override = true;
538
539// NOTE: Values are defined by apple as being in com.apple.Boot.plist
540// kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey
541if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0))
542{
543override = false;
544}
545
546if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0))
547{
548override = false;
549}
550
551if (override)
552{
553*val = overrideVal;
554*size = overrideSize;
555ret = true;
556}
557}
558}
559return ret;
560}
561
562
563#if UNUSED
564void
565printSystemConfig(char *p1)
566{
567char *p2 = p1, tmp;
568
569while (*p1 != '\0')
570{
571while (*p2 != '\0' && *p2 != '\n')
572{
573p2++;
574}
575tmp = *p2;
576*p2 = '\0';
577printf("%s\n", p1);
578*p2 = tmp;
579if (tmp == '\0')
580{
581break;
582}
583p1 = ++p2;
584 }
585}
586#endif
587
588//==========================================================================
589// ParseXMLFile
590// Modifies the input buffer.
591// Expects to see one dictionary in the XML file.
592// Puts the first dictionary it finds in the
593// tag pointer and returns 0, or returns -1 if not found
594// (and does not modify dict pointer).
595// Prints an error message if there is a parsing error.
596//
597int ParseXMLFile( char *buffer, TagPtr *dict )
598{
599long length, pos;
600TagPtr tag = 0;
601pos = 0;
602char *configBuffer;
603
604length = strlen(buffer) + 1;
605
606configBuffer = malloc(strlen(buffer)+1);
607if (!configBuffer)
608{
609return -1;
610}
611strlcpy(configBuffer, buffer, length );
612
613while (1)
614{
615length = XMLParseNextTag(configBuffer + pos, &tag);
616if (length == -1)
617{
618break;
619}
620
621pos += length;
622
623if (tag == 0)
624{
625continue;
626}
627if (tag->type == kTagTypeDict)
628{
629break;
630}
631
632XMLFreeTag(tag);
633}
634free(configBuffer);
635if (length < 0) {
636error ("Error parsing plist file\n");
637return -1;
638}
639*dict = tag;
640return 0;
641}
642
643/* loadConfigFile
644 *
645 * Returns 0 - successful.
646 * -1 - unsuccesful.
647 */
648int loadConfigFile (const char *configFile, config_file_t *config)
649{
650int fd, count;
651
652if ((fd = open_bvdev("bt(0,0)", configFile, 0)) < 0)
653{
654return -1;
655}
656// read file
657count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
658close(fd);
659
660// build xml dictionary
661ParseXMLFile(config->plist, &config->dictionary);
662return 0;
663}
664
665
666/* loadSystemConfig
667 *
668 * Returns 0 - successful.
669 * -1 - unsuccesful.
670 */
671int loadSystemConfig(config_file_t *config)
672{
673char *dirspec[] = {
674"/Mac OS X Install Data/com.apple.Boot.plist",// OS X Installer (Lion 10.7)
675"/OS X Install Data/com.apple.Boot.plist",// OS X Installer (10.8+)
676//"/.IABootFiles/com.apple.Boot.plist",// OS X Installer
677"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",// com.apple.Boot.plist
678"/com.apple.recovery.boot/com.apple.Boot.plist"// OS X Recovery
679};
680
681int i, fd, count, ret=-1;
682
683for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
684{
685if ((fd = open(dirspec[i], 0)) >= 0)
686{
687// read file
688count = read(fd, config->plist, IO_CONFIG_DATA_SIZE);
689close(fd);
690
691// build xml dictionary
692ParseXMLFile(config->plist, &config->dictionary);
693sysConfigValid = true;
694ret=0;
695
696break;
697}
698}
699
700if(ret == -1) ret = loadHelperConfig(config);
701
702// Always enable canOverride flag (for SystemConfig)
703config->canOverride = true;
704
705return ret;
706}
707
708/* loadChameleonConfig
709 *
710 * Returns 0 - successful.
711 * -1 - unsuccesful.
712 */
713int loadChameleonConfig(config_file_t *config, BVRef chain)
714{
715char *dirspec[] = {
716"/Extra/org.chameleon.Boot.plist",
717"/Extra/com.apple.Boot.plist", /* DEPRECIATED */
718};
719
720int i;
721
722for(i = 0; i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
723{
724if ( loadChameleonConfigForDevice(config, "rd(0,0)", dirspec[i]) == 0 )
725{
726return 0;
727}
728
729if ( loadChameleonConfigForDevice(config, "", dirspec[i]) == 0 )
730{
731return 0;
732}
733
734if ( loadChameleonConfigForDevice(config, "bt(0,0)", dirspec[i]) == 0 )
735{
736return 0;
737}
738BVRef bvr;
739for ( bvr = chain; bvr; bvr = bvr->next ) /* C99 Error */
740{
741char device[256];
742getDeviceDescription(bvr, device);
743
744if ( loadChameleonConfigForDevice(config, device, dirspec[i]) == 0 )
745{
746return 0;
747}
748}
749}
750return -1;
751}
752
753/* loadChameleonConfigForDevice
754 *
755 * Returns 0 - successful.
756 * -1 - unsuccesful.
757 */
758int loadChameleonConfigForDevice(config_file_t *config, const char *device, const char *path)
759{
760char full_path[1024];
761int fd;
762
763snprintf(full_path, sizeof(full_path), "%s%s", device, path);
764
765if ((fd = open(full_path, 0)) >= 0)
766{
767// Check for depreciated file names and annoy the user about it.
768if(strstr(full_path, "com.apple.Boot.plist")) {
769printf("%s is depreciated.\n", full_path);
770full_path[strlen(full_path) - strlen("com.apple.Boot.plist")] = 0;
771printf("Please use the file %sorg.chameleon.Boot.plist instead.\n", full_path);
772pause();
773}
774// read file
775read(fd, config->plist, IO_CONFIG_DATA_SIZE);
776close(fd);
777
778// build xml dictionary
779ParseXMLFile(config->plist, &config->dictionary);
780sysConfigValid = true;
781return 0;
782}
783return -1;
784}
785
786/* loadHelperConfig
787 *
788 * Returns 0 - successful.
789 * -1 - unsuccesful.
790 */
791int loadHelperConfig(config_file_t *config)
792{
793int rfd, pfd, sfd, count, ret=-1, fixedsize;
794
795char *dirspec[] = {
796"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
797"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
798"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
799};
800
801// This is a simple rock - paper scissors algo. R beats S, P beats R, S beats P
802// If all three, S is used for now. This should be changed to something else (say, timestamp?)
803
804pfd = open(dirspec[0], 0);
805if(pfd >= 0)// com.apple.boot.P exists
806{
807
808sfd = open(dirspec[2], 0); // com.apple.boot.S takes precidence if it also exists
809if(sfd >= 0)
810{
811// Use sfd
812fixedsize = MIN(file_size(sfd), IO_CONFIG_DATA_SIZE);
813count = read(sfd, config->plist, fixedsize);
814close(sfd);
815close(pfd);
816if (count != fixedsize) return -1;
817
818// build xml dictionary
819ParseXMLFile(config->plist, &config->dictionary);
820sysConfigValid = true;
821ret=0;
822
823}
824else
825{
826// used pfd
827fixedsize = MIN(file_size(pfd), IO_CONFIG_DATA_SIZE);
828count = read(pfd, config->plist, fixedsize);
829close(pfd);
830if (count != fixedsize) return -1;
831
832// build xml dictionary
833ParseXMLFile(config->plist, &config->dictionary);
834sysConfigValid = true;
835ret = 0;
836}
837
838}
839else
840{
841rfd = open(dirspec[1], 0); // com.apple.boot.R exists
842if(rfd >= 0)
843{
844pfd = open(dirspec[2], 0); // com.apple.boot.P takes recidence if it exists
845if(pfd >= 0)
846{
847// use sfd
848fixedsize = MIN(file_size(pfd), IO_CONFIG_DATA_SIZE);
849count = read(pfd, config->plist, fixedsize);
850close(pfd);
851close(rfd);
852if (count != fixedsize) return -1;
853
854// build xml dictionary
855ParseXMLFile(config->plist, &config->dictionary);
856sysConfigValid = true;
857ret = 0;
858
859}
860else
861{
862// use rfd
863 fixedsize = MIN(file_size(rfd), IO_CONFIG_DATA_SIZE);
864count = read(rfd, config->plist, fixedsize);
865close(rfd);
866if (count != fixedsize) return -1;
867
868// build xml dictionary
869ParseXMLFile(config->plist, &config->dictionary);
870sysConfigValid = true;
871ret = 0;
872
873}
874
875}
876else
877{
878sfd = open(dirspec[2], 0); // com.apple.boot.S exists, but nothing else does
879if(sfd >= 0)
880{
881// use sfd
882fixedsize = MIN(file_size(sfd), IO_CONFIG_DATA_SIZE);
883count = read(sfd, config->plist, fixedsize);
884close(sfd);
885if (count != fixedsize) return -1;
886
887// build xml dictionary
888ParseXMLFile(config->plist, &config->dictionary);
889sysConfigValid = true;
890ret = 0;
891
892}
893}
894
895}
896
897return ret;
898}
899
900char * newString(const char * oldString)
901{
902if ( oldString )
903{
904return strcpy(malloc(strlen(oldString)+1), oldString);
905}
906else
907{
908return NULL;
909}
910}
911
912/*
913 * Extracts the next argument from the command line, double quotes are allowed here.
914 */
915char * getNextArg(char ** argPtr, char * val)
916{
917char * ptr = *argPtr;
918const char * strStart;
919int len = 0;
920bool isQuoted = false;
921
922*val = '\0';
923
924// Scan for the next non-whitespace character.
925while ( *ptr && (*ptr == ' ' || *ptr == '=') )
926{
927ptr++;
928}
929
930strStart = ptr;
931
932// Skip the leading double quote character.
933if (*ptr == '\"')
934{
935isQuoted = true;
936ptr++;
937strStart++;
938}
939
940// Scan for the argument terminator character.
941// This can be either a NULL character - in case we reach the end of the string,
942// a double quote in case of quoted argument,
943// or a whitespace character (' ' or '=') for non-quoted argument.
944while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
945 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
946 ) {
947ptr++;
948}
949
950len = ptr - strStart;
951
952// Skip the closing double quote character and adjust
953// the starting pointer for the next getNextArg call.
954if (*ptr && isQuoted && *ptr == '\"') {
955ptr++;
956}
957
958// Copy the extracted argument to val.
959strncat(val, strStart, len);
960
961// Set command line pointer.
962*argPtr = ptr;
963
964return ptr;
965}
966

Archive Download this file

Revision: 2715