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

Archive Download this file

Revision: HEAD