From ee2298a313b6e425d6ff0324be6a313b1cd9a399 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Mon, 2 Mar 2009 22:54:30 -0800 Subject: auto import from //depot/cupcake/@137055 --- CHANGES.TXT | 24 +- Makefile.android | 1 + android/avd/info.c | 548 ++++++++++++++++++++++++++++++++++------------ android/avd/info.h | 14 +- android/cmdline-options.h | 22 +- android/help.c | 52 +++-- android/main.c | 283 ++++++++++-------------- android/user-config.c | 212 ++++++++++++++++++ android/user-config.h | 51 +++++ android/utils/ini.c | 42 +++- android/utils/ini.h | 5 + android/utils/path.c | 129 +++++++++++ android/utils/path.h | 30 +++ block.c | 2 +- block.h | 3 +- vl.c | 6 +- 16 files changed, 1084 insertions(+), 340 deletions(-) create mode 100644 android/user-config.c create mode 100644 android/user-config.h diff --git a/CHANGES.TXT b/CHANGES.TXT index c437e0c..0f362b7 100644 --- a/CHANGES.TXT +++ b/CHANGES.TXT @@ -46,6 +46,28 @@ IMPORTANT CHANGES: required and 'emulator' will start a new emulator instance exactly as previously. +- A new option '-sysdir ' has been introduced, the interpretation of + the '-system' option has changed, and '-image ' should now be + considered obsolete. In more details: + + * you should now use '-sysdir ' instead of '-system ' to specify + the directory where system images will be searched by the emulator + on startup. + + * you should now use '-system ' to indicate which system.img partition + image to use at startup. + + * you should not use '-system ' or '-image ' anymore. However, + these options are still supported but will print a warning to remind you + to change your scripts/habits. + + The change was done to reduce confusion as to what these options provide. + +- Options '-noaudio', '-nojni', '-noskin' and 'nocache' are deprecated. + You should use '-no-audio', '-no-jni', '-no-skin' and '-no-cache' instead. + +- Option 'initdata' is deprecated, you should use '-init-data' instead. + - Hardware emulation is now limited to the corresponding Android Virtual Device's configuration. This means it is now possible to not emulate a touch-screen, trackball, dpad, keyboard, modem, etc... @@ -70,7 +92,7 @@ OTHER: available. - Environment variable ANDROID_SDK_ROOT can be used to specifiy the location - of the SDK. + of the SDK installation path. - Environment variable ANDROID_SDK_HOME can be used to specify the location of the '.android' data directory. diff --git a/Makefile.android b/Makefile.android index fe89e4a..35fcad8 100644 --- a/Makefile.android +++ b/Makefile.android @@ -433,6 +433,7 @@ VL_SOURCES := vl.c osdep.c cutils.c \ android/main.c \ android/qemud.c \ android/resource.c \ + android/user-config.c \ android/utils/bufprint.c \ android/utils/debug.c \ android/utils/dirscanner.c \ diff --git a/android/avd/info.c b/android/avd/info.c index 432e279..230ddaa 100644 --- a/android/avd/info.c +++ b/android/avd/info.c @@ -16,12 +16,21 @@ #include "android/utils/tempfile.h" #include "android/utils/debug.h" #include "android/utils/dirscanner.h" -#include "qemu-common.h" +#include #include #include #include +#include #include +/* define this to 1 to support obsolete platform/add-on + * specific parsing and path searching as was used temporarily + * in post-1.1 / pre-cupcake SDKs. + * + * the corresponding code should be removed soon. + */ +#define SUPPORT_PLATFORM_OR_ADDON 1 + /* global variables - see android/globals.h */ AvdInfoParams android_avdParams[1]; AvdInfo* android_avdInfo; @@ -32,6 +41,44 @@ AvdInfo* android_avdInfo; /* technical note on how all of this is supposed to work: * + * Each AVD corresponds to a "content directory" that is used to + * store persistent disk images and configuration files. Most remarkable + * are: + * + * - a "config.ini" file used to hold configuration information for the + * AVD + * + * - mandatory user data image ("userdata-qemu.img") and cache image + * ("cache.img") + * + * - optional mutable system image ("system-qemu.img"), kernel image + * ("kernel-qemu") and read-only ramdisk ("ramdisk.img") + * + * When starting up an AVD, the emulator looks for relevant disk images + * in the content directory. If it doesn't find a given image there, it + * will try to search in the list of system directories listed in the + * 'config.ini' file through one of the following (key,value) pairs: + * + * images.sysdir.1 = + * images.sysdir.2 = + * + * The search paths can be absolute, or relative to the root SDK installation + * path (which is determined from the emulator program's location, or from the + * ANDROID_SDK_ROOT environment variable). + * + * Individual image disk search patch can be over-riden on the command-line + * with one of the usual options. + */ + +#if SUPPORT_PLATFORM_OR_ADDON +/* + * BELOW IS THE DOCUMENTATION FOR AN OBSOLETE SCHEME THAT USED TO BE MORE + * COMPLEX TO IMPLEMENT, AND EXPOSED TOO MUCH SDK INTERNALS WITHIN THE + * EMULATOR SOURCE CODE. + * + * THE CORRESPONDING CODE IS STILL THERE FOR LEGACY SUPPORT REASON BUT WILL + * SOON BE REMOVED FOR SIMPLIFICATION REASONS. + * * we assume the following SDK layout: * * SDK/ @@ -194,10 +241,12 @@ AvdInfo* android_avdInfo; */ /* the name of the $SDKROOT subdirectory that contains all platforms */ -#define PLATFORMS_SUBDIR "platforms" +# define PLATFORMS_SUBDIR "platforms" /* the name of the $SDKROOT subdirectory that contains add-ons */ -#define ADDONS_SUBDIR "add-ons" +# define ADDONS_SUBDIR "add-ons" + +#endif /* SUPPORT_PLATFORM_OR_ADDON */ /* this is the subdirectory of $HOME/.android where all * root configuration files (and default content directories) @@ -205,6 +254,28 @@ AvdInfo* android_avdInfo; */ #define ANDROID_AVD_DIR "avd" +/* the prefix of config.ini keys that will be used for search directories + * of system images. + */ +#define SEARCH_PREFIX "images.sysdir." + +/* the maximum number of search path keys we're going to read from the + * config.ini file + */ +#define MAX_SEARCH_PATHS 2 + +/* the config.ini key that will be used to indicate the full relative + * path to the skin directory (including the skin name). + * + * If SUPPORT_PLATFORM_OR_ADDON is defined, then this can also be + * the name of a skin, without any path, and platform/add-on directories + * will be searched for it. + */ +#define SKIN_PATH "skin" + +/* default skin name */ +#define SKIN_DEFAULT "HVGA" + /* certain disk image files are mounted read/write by the emulator * to ensure that several emulators referencing the same files * do not corrupt these files, we need to lock them and respond @@ -240,10 +311,15 @@ struct AvdInfo { /* for the normal virtual device case */ char* deviceName; char* sdkRootPath; + char sdkRootPathFromEnv; + char* searchPaths[ MAX_SEARCH_PATHS ]; + int numSearchPaths; +#if SUPPORT_PLATFORM_OR_ADDON int platformVersion; char* platformPath; char* addonTarget; char* addonPath; +#endif char* contentPath; IniFile* rootIni; /* root .ini file */ IniFile* configIni; /* virtual device's config.ini */ @@ -265,10 +341,15 @@ avdInfo_free( AvdInfo* i ) int nn; for (nn = 0; nn < AVD_IMAGE_MAX; nn++) - qemu_free(i->imagePath[nn]); + AFREE(i->imagePath[nn]); - qemu_free(i->skinName); - qemu_free(i->skinDirPath); + AFREE(i->skinName); + AFREE(i->skinDirPath); + + for (nn = 0; nn < i->numSearchPaths; nn++) + AFREE(i->searchPaths[nn]); + + i->numSearchPaths = 0; if (i->configIni) { iniFile_free(i->configIni); @@ -280,20 +361,22 @@ avdInfo_free( AvdInfo* i ) i->rootIni = NULL; } - qemu_free(i->contentPath); - qemu_free(i->sdkRootPath); + AFREE(i->contentPath); + AFREE(i->sdkRootPath); if (i->inAndroidBuild) { - qemu_free(i->androidOut); - qemu_free(i->androidBuildRoot); + AFREE(i->androidOut); + AFREE(i->androidBuildRoot); } else { - qemu_free(i->platformPath); - qemu_free(i->addonTarget); - qemu_free(i->addonPath); +#if SUPPORT_PLATFORM_OR_ADDON + AFREE(i->platformPath); + AFREE(i->addonTarget); + AFREE(i->addonPath); +#endif } - qemu_free(i->deviceName); - qemu_free(i); + AFREE(i->deviceName); + AFREE(i); } } @@ -333,7 +416,8 @@ _getSdkRoot( AvdInfo* i ) if (env != NULL && env[0] != 0) { if (path_exists(env)) { D("found " SDK_ROOT_ENV ": %s", env); - i->sdkRootPath = qemu_strdup(env); + i->sdkRootPath = ASTRDUP(env); + i->sdkRootPathFromEnv = 1; return 0; } D(SDK_ROOT_ENV " points to unknown directory: %s", env); @@ -350,6 +434,41 @@ _getSdkRoot( AvdInfo* i ) return 0; } +static void +_getSearchPaths( AvdInfo* i ) +{ + char temp[PATH_MAX], *p = temp, *end= p+sizeof temp; + int nn, count = 0; + + + + for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) { + char* path; + + p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 ); + if (p >= end) + continue; + + path = iniFile_getString( i->configIni, temp ); + if (path != NULL) { + DD(" found image search path: %s", path); + if (!path_is_absolute(path)) { + p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path); + AFREE(path); + path = ASTRDUP(temp); + } + i->searchPaths[count++] = path; + } + } + + i->numSearchPaths = count; + if (count == 0) + DD("no search paths found in this AVD's config.ini"); + else + DD("found a total of %d search paths for this AVD", count); +} + +#if SUPPORT_PLATFORM_OR_ADDON /* returns the full path of the platform subdirectory * corresponding to a given API version */ @@ -402,7 +521,7 @@ _findPlatformByVersion( const char* sdkRoot, int version ) if (apiVersion == version) { /* Bingo */ - subdir = qemu_strdup(subdir); + subdir = ASTRDUP(subdir); break; } } @@ -422,7 +541,7 @@ _findPlatformByVersion( const char* sdkRoot, int version ) static char* _findAddonByTarget( const char* sdkRoot, const char* target, int *pversion ) { - char* targetCopy = qemu_strdup(target); + char* targetCopy = ASTRDUP(target); char* targetVendor = NULL; char* targetName = NULL; int targetVersion = -1; @@ -516,7 +635,7 @@ _findAddonByTarget( const char* sdkRoot, const char* target, int *pversion ) if (matches == 3) { /* bingo */ *pversion = version; - subdir = qemu_strdup(subdir); + subdir = ASTRDUP(subdir); break; } } @@ -527,9 +646,10 @@ _findAddonByTarget( const char* sdkRoot, const char* target, int *pversion ) return subdir; FAIL: - qemu_free(targetCopy); + AFREE(targetCopy); return NULL; } +#endif /* SUPPORT_PLATFORM_OR_ADDON */ static int _checkAvdName( const char* name ) @@ -568,23 +688,29 @@ _getRootIni( AvdInfo* i ) /* the .ini variable name that points to the content directory * in a root AVD ini file. This is required */ # define ROOT_PATH_KEY "path" -# define ROOT_TARGET_KEY "target" -/* retrieve the content path and target from the root .ini file */ static int -_getTarget( AvdInfo* i ) +_getContentPath( AvdInfo* i ) { i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY); - i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY); - - iniFile_free(i->rootIni); - i->rootIni = NULL; if (i->contentPath == NULL) { derror("bad config: %s", "virtual device file lacks a "ROOT_PATH_KEY" entry"); return -1; } + D("virtual device content at %s", i->contentPath); + return 0; +} + +#if SUPPORT_PLATFORM_OR_ADDON +# define ROOT_TARGET_KEY "target" + +/* retrieve the content path and target from the root .ini file */ +static int +_getTarget( AvdInfo* i ) +{ + i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY); if (i->addonTarget == NULL) { derror("bad config: %s", @@ -592,7 +718,6 @@ _getTarget( AvdInfo* i ) return -1; } - D("virtual device content at %s", i->contentPath); D("virtual device target is %s", i->addonTarget); if (!strncmp(i->addonTarget, "android-", 8)) { /* target is platform */ @@ -634,7 +759,7 @@ _getTarget( AvdInfo* i ) D("virtual device platform version %d", i->platformVersion); return 0; } - +#endif /* SUPPORT_PLATFORM_OR_ADDON */ /* find and parse the config.ini file from the content directory */ static int @@ -712,9 +837,9 @@ imageLoader_set( ImageLoader* l, AvdImageType id ) static char* imageLoader_setPath( ImageLoader* l, const char* path ) { - path = path ? qemu_strdup(path) : NULL; + path = path ? ASTRDUP(path) : NULL; - qemu_free(l->pPath[0]); + AFREE(l->pPath[0]); l->pPath[0] = (char*) path; return (char*) path; @@ -739,45 +864,58 @@ enum { #define IMAGE_OPTIONAL 0 -/* find an image from the SDK add-on and/or platform - * directories. returns the full path or NULL if - * the file could not be found. +/* find an image from the SDK search directories. + * returns the full path or NULL if the file could not be found. * * note: this stores the result in the image's path as well */ static char* imageLoader_lookupSdk( ImageLoader* l ) { - AvdInfo* i = l->info; - char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp); + AvdInfo* i = l->info; + const char* image = l->imageFile; + char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp); do { - /* try the add-on directory, if any */ - if (i->addonPath != NULL) { - DD("searching %s in add-on directory: %s", - l->imageFile, i->addonPath); + /* try the search paths */ + int nn; - p = bufprint(temp, end, "%s/images/%s", - i->addonPath, l->imageFile); + for (nn = 0; nn < i->numSearchPaths; nn++) { + const char* searchDir = i->searchPaths[nn]; - if (p < end && path_exists(temp)) + p = bufprint(temp, end, "%s/%s", searchDir, image); + if (p < end && path_exists(temp)) { + DD("found %s in search dir: %s", image, searchDir); + goto FOUND; + } + DD(" no %s in search dir: %s", image, searchDir); + } + +#if SUPPORT_PLATFORM_OR_ADDON + /* try the add-on directory, if any */ + if (i->addonPath != NULL) { + p = bufprint(temp, end, "%s/images/%s", i->addonPath, image); + if (p < end && path_exists(temp)) { + DD("found %s in add-on dir:", image, i->addonPath); break; + } + DD(" no %s in add-on dir: ", image, i->addonPath); } /* or try the platform directory */ - DD("searching %s in platform directory: %s", - l->imageFile, i->platformPath); - p = bufprint(temp, end, "%s/images/%s", - i->platformPath, l->imageFile); - if (p < end && path_exists(temp)) + i->platformPath, image); + if (p < end && path_exists(temp)) { + DD("found %s in platform dir:", image, i->platformPath); break; - - DD("could not find %s in SDK", l->imageFile); + } + DD(" no %s in platform dir: ", image, i->platformPath); +#endif return NULL; } while (0); +FOUND: l->pState[0] = IMAGE_STATE_READONLY; return imageLoader_setPath(l, temp); @@ -795,16 +933,16 @@ imageLoader_lookupContent( ImageLoader* l ) AvdInfo* i = l->info; char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp); - DD("searching %s in content directory", l->imageFile); p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile); if (p >= end) { derror("content directory path too long"); exit(2); } if (!path_exists(temp)) { - DD("not found %s in content directory", l->imageFile); + DD(" no %s in content directory", l->imageFile); return NULL; } + DD("found %s in content directory", l->imageFile); /* assume content image files must be locked */ l->pState[0] = IMAGE_STATE_MUSTLOCK; @@ -827,7 +965,7 @@ imageLoader_lock( ImageLoader* l, unsigned flags ) if (l->pState[0] != IMAGE_STATE_MUSTLOCK) return; - D("locking %s image at %s", l->imageText, path); + D(" locking %s image at %s", l->imageText, path); if (filelock_create(path) != NULL) { /* succesful lock */ @@ -913,15 +1051,14 @@ imageLoader_load( ImageLoader* l, { const char* path = NULL; - DD("looking for %s image (%s)", l->imageText, l->imageFile); - /* first, check user-provided path */ path = l->params->forcePaths[l->id]; if (path != NULL) { imageLoader_setPath(l, path); - if (path_exists(path)) + if (path_exists(path)) { + DD("found user-provided %s image: %s", l->imageText, l->imageFile); goto EXIT; - + } D("user-provided %s image does not exist: %s", l->imageText, path); @@ -933,20 +1070,20 @@ imageLoader_load( ImageLoader* l, } } else { - const char* contentFile; + const char* contentFile; /* second, look in the content directory */ path = imageLoader_lookupContent(l); if (path) goto EXIT; - contentFile = qemu_strdup(l->temp); + contentFile = ASTRDUP(l->temp); /* it's not there */ if (flags & IMAGE_SEARCH_SDK) { /* third, look in the SDK directory */ path = imageLoader_lookupSdk(l); if (path) { - qemu_free((char*)contentFile); + AFREE((char*)contentFile); goto EXIT; } } @@ -954,13 +1091,25 @@ imageLoader_load( ImageLoader* l, /* if the file is required, abort */ if (flags & IMAGE_REQUIRED) { - derror("could not find required %s image (%s)", - l->imageText, l->imageFile); + AvdInfo* i = l->info; + + derror("could not find required %s image (%s).", + l->imageText, l->imageFile); + + if (i->inAndroidBuild) { + dprint( "Did you build everything ?" ); + } else if (!i->sdkRootPathFromEnv) { + dprint( "Maybe defining %s to point to a valid SDK " + "installation path might help ?", SDK_ROOT_ENV ); + } else { + dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV, + i->sdkRootPath ); + } exit(2); } path = imageLoader_setPath(l, contentFile); - qemu_free((char*)contentFile); + AFREE((char*)contentFile); } /* otherwise, do we need to create it ? */ @@ -1006,7 +1155,7 @@ _getImagePaths(AvdInfo* i, AvdInfoParams* params ) * if there is one in the content directory just lock * and use it. */ - imageLoader_set ( l, AVD_IMAGE_SYSTEM ); + imageLoader_set ( l, AVD_IMAGE_INITSYSTEM ); imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK ); /* the data partition - this one is special because if it @@ -1038,7 +1187,7 @@ _getImagePaths(AvdInfo* i, AvdInfoParams* params ) srcPath = imageLoader_extractPath(l); imageLoader_copyFrom( l, srcPath ); - qemu_free((char*) srcPath); + AFREE((char*) srcPath); } else { @@ -1092,32 +1241,49 @@ _getImagePaths(AvdInfo* i, AvdInfoParams* params ) return 0; } +/* check that a given directory contains a valid skin. + * returns 1 on success, 0 on failure. + */ +static int +_checkSkinPath( const char* skinPath ) +{ + char temp[MAX_PATH], *p=temp, *end=p+sizeof(temp); + + /* for now, if it has a 'layout' file, it is a valid skin path */ + p = bufprint(temp, end, "%s/layout", skinPath); + if (p >= end || !path_exists(temp)) + return 0; + + return 1; +} + /* check that there is a skin named 'skinName' listed from 'skinDirRoot' * this returns 1 on success, 0 on failure * on success, the 'temp' buffer will get the path containing the real * skin directory (after alias expansion), including the skin name. */ static int -_checkSkinDir( char* temp, char* end, const char* skinDirRoot, const char* skinName ) +_checkSkinDir( char* temp, + char* end, + const char* skinDirRoot, + const char* skinName ) { DirScanner* scanner; - char *p, *q; + char *p; int result; - p = bufprint(temp, end, "%s/skins/%s", - skinDirRoot, skinName); - - DD("probing skin content in %s", temp); + p = bufprint(temp, end, "%s/skins/%s", + skinDirRoot, skinName); if (p >= end || !path_exists(temp)) { + DD(" ignore bad skin directory %s", temp); return 0; } /* first, is this a normal skin directory ? */ - q = bufprint(p, end, "/layout"); - if (q < end && path_exists(temp)) { + if (_checkSkinPath(temp)) { /* yes */ - *p = 0; + DD(" found skin directory: %s", temp); return 1; } @@ -1138,10 +1304,10 @@ _checkSkinDir( char* temp, char* end, const char* skinDirRoot, const char* s p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, file+6); - q = bufprint(p, end, "/layout"); - if (q < end && path_exists(temp)) { + if (p < end && _checkSkinPath(temp)) { /* yes, it's an alias */ - *p = 0; + DD(" skin alias '%s' points to skin directory: %s", + file+6, temp); result = 1; break; } @@ -1151,6 +1317,54 @@ _checkSkinDir( char* temp, char* end, const char* skinDirRoot, const char* s return result; } +/* try to see if the skin name leads to a magic skin or skin path directly + * returns 1 on success, 0 on error. + * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo. + */ +static int +_getSkinPathFromName( AvdInfo* i, const char* skinName ) +{ + char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); + + /* if the skin name has the format 'NNNNxNNN' where + * NNN is a decimal value, then this is a 'magic' skin + * name that doesn't require a skin directory + */ + if (isdigit(skinName[0])) { + int width, height; + if (sscanf(skinName, "%dx%d", &width, &height) == 2) { + D("'magic' skin format detected: %s", skinName); + i->skinName = ASTRDUP(skinName); + i->skinDirPath = NULL; + return 1; + } + } + + /* is the skin name a direct path to the skin directory ? */ + if (_checkSkinPath(skinName)) { + goto FOUND_IT; + } + + /* is the skin name a relative path from the SDK root ? */ + p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName); + if (p < end && _checkSkinPath(temp)) { + skinName = temp; + goto FOUND_IT; + } + + /* nope */ + return 0; + +FOUND_IT: + if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) { + derror("malformed skin name: %s", skinName); + exit(2); + } + D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath); + return 1; +} + +/* return 0 on success, -1 on error */ static int _getSkin( AvdInfo* i, AvdInfoParams* params ) { @@ -1158,34 +1372,52 @@ _getSkin( AvdInfo* i, AvdInfoParams* params ) char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); char explicitSkin = 1; - /* determine the skin name, the default is "HVGA" - * unless specified by the caller or in config.ini + /* this function is used to compute the 'skinName' and 'skinDirPath' + * fields of the AvdInfo. + */ + + /* processing here is a bit tricky, so here's how it happens + * + * - command-line option '-skin ' can be used to specify the + * name of a skin, to override the AVD settings. + * + * - skins are searched from /../skins for each in the + * images search list, unless a '-skindir ' option has been + * provided on the command-line + * + * - otherwise, the config.ini can also contain a SKIN_PATH key that + * shall give the full path to the skin directory, either relative + * to the SDK root, or an absolute path. + * + * - skin names like '320x480' corresponds to "magic skins" that + * simply display a framebuffer, without any ornaments of the + * corresponding size. They do not correspond to any real skin + * directory / files and are handled later. But they must be + * recognized here and report a NULL skindir. */ if (params->skinName) { - skinName = qemu_strdup(params->skinName); + skinName = ASTRDUP(params->skinName); } else { - skinName = iniFile_getString( i->configIni, "skin" ); - if (skinName == NULL) { - skinName = qemu_strdup("HVGA"); - explicitSkin = 0; - } + skinName = iniFile_getString( i->configIni, SKIN_PATH ); + explicitSkin = 0; } - i->skinName = skinName; - - /* if the skin name has the format 'NNNNxNNN' where - * NNN is a decimal value, then this is a 'magic' skin - * name that doesn't require a skin directory + /* first, check that the skin name is not magic or a direct + * directory path */ - if (isdigit(skinName[0])) { - int width, height; - if (sscanf(skinName, "%dx%d", &width, &height) == 2) { - D("'magic' skin format detected: %s", skinName); - i->skinDirPath = NULL; - return 0; - } + if (skinName != NULL && _getSkinPathFromName(i, skinName)) { + AFREE(skinName); + return 0; + } + + /* if not, the default skinName is "HVGA" */ + if (skinName == NULL) { + skinName = ASTRDUP(SKIN_DEFAULT); + explicitSkin = 0; } + i->skinName = skinName; + /* now try to find the skin directory for that name - * first try the content directory */ do { @@ -1194,17 +1426,12 @@ _getSkin( AvdInfo* i, AvdInfoParams* params ) * user wants, unless an explicit name was given */ if (!explicitSkin) { - char* q; - p = bufprint(temp, end, "%s/skin", i->contentPath); - q = bufprint(p, end, "/layout"); - if (q < end && path_exists(temp)) { - /* use this one - cheat a little */ - *p = 0; + if (p < end && _checkSkinPath(temp)) { D("using skin content from %s", temp); - qemu_free(i->skinName); - i->skinName = qemu_strdup("skin"); - i->skinDirPath = qemu_strdup(i->contentPath); + AFREE(i->skinName); + i->skinName = ASTRDUP("skin"); + i->skinDirPath = ASTRDUP(i->contentPath); return 0; } } @@ -1213,6 +1440,25 @@ _getSkin( AvdInfo* i, AvdInfoParams* params ) if (_checkSkinDir(temp, end, i->contentPath, skinName)) break; + /* look in the search paths. For each in the list, + * look the skins in /.. */ + { + int nn; + for (nn = 0; nn < i->numSearchPaths; nn++) { + char* parentDir = path_parent(i->searchPaths[nn], 1); + int ret; + if (parentDir == NULL) + continue; + ret=_checkSkinDir(temp, end, parentDir, skinName); + AFREE(parentDir); + if (ret) + break; + } + if (nn < i->numSearchPaths) + break; + } + +#if SUPPORT_PLATFORM_OR_ADDON /* look in the add-on directory, if any */ if (i->addonPath && _checkSkinDir(temp, end, i->addonPath, skinName)) @@ -1221,10 +1467,19 @@ _getSkin( AvdInfo* i, AvdInfoParams* params ) /* look in the platforms directory */ if (_checkSkinDir(temp, end, i->platformPath, skinName)) break; - +#endif /* didn't find it */ - if (explicitSkin) - dwarning("could not find directory for skin '%s'", skinName); + if (explicitSkin) { + derror("could not find directory for skin '%s'," + " please use a different name", skinName); + exit(2); + } else { + dwarning("no skin directory matched '%s', so reverted to default", + skinName); + AFREE(i->skinName); + params->skinName = SKIN_DEFAULT; + return _getSkin(i, params); + } return -1; @@ -1234,16 +1489,13 @@ _getSkin( AvdInfo* i, AvdInfoParams* params ) * returned in 'temp' might be different from the original * one due to alias expansion so strip it. */ - p = strrchr(temp, '/'); - if (p == NULL) { - /* should not happen */ - DD("weird skin path: %s", temp); + AFREE(i->skinName); + + if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) { + derror("weird skin path: %s", temp); return -1; } - - *p = 0; - DD("found skin content in %s", temp); - i->skinDirPath = qemu_strdup(temp); + DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath); return 0; } @@ -1261,15 +1513,32 @@ avdInfo_new( const char* name, AvdInfoParams* params ) exit(1); } - i = qemu_mallocz(sizeof *i); - i->deviceName = qemu_strdup(name); + ANEW0(i); + i->deviceName = ASTRDUP(name); - if ( _getSdkRoot(i) < 0 || - _getRootIni(i) < 0 || - _getTarget(i) < 0 || - _getConfigIni(i) < 0 ) + if ( _getSdkRoot(i) < 0 || + _getRootIni(i) < 0 || + _getContentPath(i) < 0 || + _getConfigIni(i) < 0 ) goto FAIL; + /* look for image search paths. handle post 1.1/pre cupcake + * obsolete SDKs. + */ + _getSearchPaths(i); + + if (i->numSearchPaths == 0) { +#if SUPPORT_PLATFORM_OR_ADDON + /* no search paths, look for platform/add-on */ + if (_getTarget(i) < 0) + goto FAIL; +#endif + } + + /* don't need this anymore */ + iniFile_free(i->rootIni); + i->rootIni = NULL; + if ( _getImagePaths(i, params) < 0 || _getSkin (i, params) < 0 ) goto FAIL; @@ -1399,7 +1668,7 @@ _getBuildImagePaths( AvdInfo* i, AvdInfoParams* params ) } } - qemu_free(srcData); + AFREE(srcData); /** load the ramdisk image **/ @@ -1410,7 +1679,7 @@ _getBuildImagePaths( AvdInfo* i, AvdInfoParams* params ) /** load the system image. read-only. the caller must ** take care of checking the state **/ - imageLoader_set ( l, AVD_IMAGE_SYSTEM ); + imageLoader_set ( l, AVD_IMAGE_INITSYSTEM ); imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK ); /* force the system image to read-only status */ @@ -1449,11 +1718,11 @@ _getBuildSkin( AvdInfo* i, AvdInfoParams* params ) if (!skinName) { /* the (current) default skin name for the build system */ - skinName = "HVGA"; + skinName = SKIN_DEFAULT; DD("selecting default skin name '%s'", skinName); } - i->skinName = qemu_strdup(skinName); + i->skinName = ASTRDUP(skinName); if (!skinDir) { @@ -1476,7 +1745,7 @@ _getBuildSkin( AvdInfo* i, AvdInfoParams* params ) } *p = 0; DD("found skin path: %s", temp); - i->skinDirPath = qemu_strdup(temp); + i->skinDirPath = ASTRDUP(temp); return 0; } @@ -1488,15 +1757,15 @@ avdInfo_newForAndroidBuild( const char* androidBuildRoot, { AvdInfo* i; - i = qemu_mallocz(sizeof *i); + ANEW0(i); i->inAndroidBuild = 1; - i->androidBuildRoot = qemu_strdup(androidBuildRoot); - i->androidOut = qemu_strdup(androidOut); - i->contentPath = qemu_strdup(androidOut); + i->androidBuildRoot = ASTRDUP(androidBuildRoot); + i->androidOut = ASTRDUP(androidOut); + i->contentPath = ASTRDUP(androidOut); /* TODO: find a way to provide better information from the build files */ - i->deviceName = qemu_strdup(""); + i->deviceName = ASTRDUP(""); if (_getBuildConfigIni(i) < 0 || _getBuildImagePaths(i, params) < 0 ) @@ -1565,6 +1834,17 @@ avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw ) return ret; } +const char* +avdInfo_getContentPath( AvdInfo* i ) +{ + return i->contentPath; +} + +int +avdInfo_inAndroidBuild( AvdInfo* i ) +{ + return i->inAndroidBuild; +} char* avdInfo_getTracePath( AvdInfo* i, const char* traceName ) @@ -1581,5 +1861,5 @@ avdInfo_getTracePath( AvdInfo* i, const char* traceName ) p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s", i->contentPath, traceName ); } - return qemu_strdup(tmp); + return ASTRDUP(tmp); } diff --git a/android/avd/info.h b/android/avd/info.h index ad8a138..6cd97dc 100644 --- a/android/avd/info.h +++ b/android/avd/info.h @@ -52,8 +52,10 @@ #define AVD_IMAGE_LIST \ _AVD_IMG(KERNEL,"kernel-qemu","kernel") \ _AVD_IMG(RAMDISK,"ramdisk.img","ramdisk") \ - _AVD_IMG(SYSTEM,"system.img","system") \ - _AVD_IMG(USERDATA,"userdata.img","user data") \ + _AVD_IMG(INITSYSTEM,"system.img","init system") \ + _AVD_IMG(INITDATA,"userdata.img","init data") \ + _AVD_IMG(USERSYSTEM,"system-qemu.img","user system") \ + _AVD_IMG(USERDATA,"userdata-qemu.img", "user data") \ _AVD_IMG(CACHE,"cache.img","cache") \ _AVD_IMG(SDCARD,"sdcard.img","SD Card") \ @@ -82,6 +84,8 @@ typedef enum { AVDINFO_WIPE_CACHE = (1 << 2), /* use to ignore ignore SDCard image (default or provided) */ AVDINFO_NO_SDCARD = (1 << 3), + /* use to wipe the system image with new initial values */ + AVDINFO_WIPE_SYSTEM = (1 << 4), } AvdFlags; typedef struct { @@ -150,6 +154,12 @@ const char* avdInfo_getSkinName( AvdInfo* i ); /* Returns the root skin directory for this device */ const char* avdInfo_getSkinDir ( AvdInfo* i ); +/* Returns the content path of the virtual device */ +const char* avdInfo_getContentPath( AvdInfo* i ); + +/* Returns TRUE iff in the Android build system */ +int avdInfo_inAndroidBuild( AvdInfo* i ); + /* Reads the AVD's hardware configuration into 'hw'. returns -1 on error, 0 otherwise */ int avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw ); diff --git a/android/cmdline-options.h b/android/cmdline-options.h index c0d121e..e38b081 100644 --- a/android/cmdline-options.h +++ b/android/cmdline-options.h @@ -59,21 +59,25 @@ * */ -CFG_PARAM( system, "", "read system image from " ) +CFG_PARAM( sysdir, "", "search for system disk images in " ) +CFG_PARAM( system, "", "read initial system image from " ) CFG_PARAM( datadir, "", "write user data into " ) CFG_PARAM( kernel, "", "use specific emulated kernel" ) CFG_PARAM( ramdisk, "", "ramdisk image (default /ramdisk.img" ) -CFG_PARAM( image, "", "system image (default /system.img" ) -CFG_PARAM( initdata, "", "initial data image (default /userdata.img" ) +CFG_PARAM( image, "", "obsolete, use -system instead" ) +CFG_PARAM( init_data, "", "initial data image (default /userdata.img" ) +CFG_PARAM( initdata, "", "same as '-init-data '" ) CFG_PARAM( data, "", "data image (default /userdata-qemu.img" ) CFG_PARAM( cache, "", "cache partition image (default is temporary file)" ) -CFG_FLAG ( nocache, "disable the cache partition" ) +CFG_FLAG ( no_cache, "disable the cache partition" ) +CFG_FLAG ( nocache, "same as -no-cache" ) OPT_PARAM( sdcard, "", "SD card image (default /sdcard.img") OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" ) CFG_PARAM( avd, "", "use a specific android virtual device" ) CFG_PARAM( skindir, "", "search skins in (default /skins)" ) -CFG_PARAM( skin, "", "select a given skin" ) -CFG_FLAG ( noskin, "don't use any emulator skin" ) +CFG_PARAM( skin, "", "select a given skin" ) +CFG_FLAG ( no_skin, "don't use any emulator skin" ) +CFG_FLAG ( noskin, "same as -no-skin" ) CFG_PARAM( memory, "", "physical RAM size in MBs" ) OPT_PARAM( netspeed, "", "maximum network download/upload speeds" ) @@ -83,10 +87,12 @@ OPT_FLAG ( netfast, "disable network shaping" ) OPT_PARAM( trace, "", "enable code profiling (F9 to start)" ) OPT_FLAG ( show_kernel, "display kernel messages" ) OPT_FLAG ( shell, "enable root shell on current terminal" ) -OPT_FLAG ( nojni, "disable JNI checks in the Dalvik runtime" ) +OPT_FLAG ( no_jni, "disable JNI checks in the Dalvik runtime" ) +OPT_FLAG ( nojni, "same as -no-jni" ) OPT_PARAM( logcat, "", "enable logcat output with given tags" ) -OPT_FLAG ( noaudio, "disable audio support" ) +OPT_FLAG ( no_audio, "disable audio support" ) +OPT_FLAG ( noaudio, "same as -no-audio" ) OPT_PARAM( audio, "", "use specific audio backend" ) OPT_PARAM( audio_in, "", "use specific audio input backend" ) OPT_PARAM( audio_out,"", "use specific audio output backend" ) diff --git a/android/help.c b/android/help.c index cd1b827..92531d9 100644 --- a/android/help.c +++ b/android/help.c @@ -115,7 +115,7 @@ help_build_images( stralloc_t* out ) " Skins will be looked in /development/emulator/skins/\n\n" - " You can use the -system, -image, -kernel, -ramdisk, -datadir, -data options\n" + " You can use the -sysdir, -system, -kernel, -ramdisk, -datadir, -data options\n" " to specify different search directories or specific image files. You can\n" " also use the -cache and -sdcard options to indicate specific cache partition\n" " and SD Card image files.\n\n" @@ -160,6 +160,7 @@ help_disk_images( stralloc_t* out ) " It will also use the following writable image files:\n\n" " userdata-qemu.img the persistent data partition image\n" + " system-qemu.img an *optional* persistent system image\n" " cache.img an *optional* cache partition image\n" " sdcard.img an *optional* SD Card partition image\n\n" @@ -176,7 +177,7 @@ help_disk_images( stralloc_t* out ) " If you're neither using the SDK or the Android build system, you\n" " can still run the emulator by explicitely providing the paths to\n" " *all* required disk images through a combination of the following\n" - " options: -system, -kernel, -ramdisk, -image, -datadir, -data, -cache\n" + " options: -sysdir, -datadir, -kernel, -ramdisk, -system, -data, -cache\n" " and -sdcard\n\n" " The actual logic being that the emulator should be able to find all\n" @@ -186,12 +187,12 @@ help_disk_images( stralloc_t* out ) " Other related options are:\n\n" - " -initdata Specify an alernative *initial* user data image\n\n" + " -init-data Specify an alernative *initial* user data image\n\n" " -wipe-data Copy the content of the *initial* user data image\n" " (userdata.img) into the writable one (userdata-qemu.img)\n\n" - " -nocache do not use a cache partition, even if one is\n" + " -no-cache do not use a cache partition, even if one is\n" " available.\n\n" , datadir ); @@ -457,7 +458,7 @@ help_avd(stralloc_t* out) } static void -help_system(stralloc_t* out) +help_sysdir(stralloc_t* out) { char systemdir[MAX_PATH]; char *p = systemdir, *end = p + sizeof(systemdir); @@ -466,7 +467,7 @@ help_system(stralloc_t* out) p = bufprint( p, end, PATH_SEP "lib" PATH_SEP "images" ); PRINTF( - " use '-system ' to specify a directory where system read-only\n" + " use '-sysdir ' to specify a directory where system read-only\n" " image files will be searched. on this system, the default directory is:\n\n" " %s\n\n", systemdir ); @@ -516,21 +517,35 @@ help_ramdisk(stralloc_t* out) } static void -help_image(stralloc_t* out) +help_system(stralloc_t* out) { PRINTF( - " use '-image ' to specify the intial system image that will be loaded.\n" + " use '-system ' to specify the intial system image that will be loaded.\n" " the default image is 'system.img' from the system directory.\n\n" + " NOTE: In previous releases of the Android SDK, this option was named '-image'.\n" + " And using '-system ' was equivalent to using '-sysdir ' now.\n\n" + + " see '-help-disk-images' for more information about disk image files\n\n" + ); +} + +static void +help_image(stralloc_t* out) +{ + PRINTF( + " This option is obsolete, you should use '-system ' instead to point\n" + " to the initial system image.\n\n" + " see '-help-disk-images' for more information about disk image files\n\n" ); } static void -help_initdata(stralloc_t* out) +help_init_data(stralloc_t* out) { PRINTF( - " use '-initdata ' to specify an *init* /data partition file.\n" + " use '-init-data ' to specify an *init* /data partition file.\n" " it is only used when creating a new writable /data image file, or\n" " when you use '-wipe-data' to reset it. the default is 'userdata.img'\n" " from the system directory.\n\n" @@ -569,17 +584,17 @@ help_cache(stralloc_t* out) " backed by a temporary file that is deleted when the emulator exits.\n" " using the -cache option allows it to be persistent.\n\n" - " the '-nocache' option can be used to disable the cache partition.\n\n" + " the '-no-cache' option can be used to disable the cache partition.\n\n" " see '-help-disk-images' for more information about disk image files\n\n" ); } static void -help_nocache(stralloc_t* out) +help_no_cache(stralloc_t* out) { PRINTF( - " use '-nocache' to disable the cache partition in the emulated system.\n" + " use '-no-cache' to disable the cache partition in the emulated system.\n" " the cache partition is optional, but when available, is used by the browser\n" " to cache web pages and images\n\n" @@ -925,10 +940,10 @@ help_logcat(stralloc_t* out) } static void -help_noaudio(stralloc_t* out) +help_no_audio(stralloc_t* out) { PRINTF( - " use '-noaudio' to disable all audio support in the emulator. this may be\n" + " use '-no-audio' to disable all audio support in the emulator. this may be\n" " unfortunately be necessary in some cases:\n\n" " * at least two users have reported that their Windows machine rebooted\n" @@ -1264,12 +1279,17 @@ help_tcpdump(stralloc_t *out) ); } -#define help_noskin NULL +#define help_no_skin NULL #define help_netspeed help_shaper #define help_netdelay help_shaper #define help_netfast help_shaper +#define help_noaudio NULL +#define help_noskin NULL +#define help_nocache NULL +#define help_no_jni NULL #define help_nojni NULL +#define help_initdata NULL #define help_no_window NULL #define help_version NULL #define help_memory NULL diff --git a/android/main.c b/android/main.c index e1d983c..c366a9e 100644 --- a/android/main.c +++ b/android/main.c @@ -51,6 +51,7 @@ #include "android/qemud.h" #include "android/hw-kmsg.h" #include "android/hw-control.h" +#include "android/user-config.h" #include "android/utils/bufprint.h" #include "android/utils/dirscanner.h" #include "android/utils/path.h" @@ -64,6 +65,9 @@ #include "android/globals.h" #include "tcpdump.h" +/* in vl.c */ +extern void qemu_help(int code); + #include "framebuffer.h" AndroidRotation android_framebuffer_rotation; @@ -132,126 +136,28 @@ const char* get_app_dir(void) /*** CONFIGURATION ***/ -static AConfig* emulator_config; -static int emulator_config_found; -static char emulator_configpath[256]; +static AUserConfig* userConfig; void emulator_config_init( void ) { - char* end = emulator_configpath + sizeof(emulator_configpath); - char* p; - void* config; - - emulator_config = aconfig_node("",""); - - p = bufprint_config_file(emulator_configpath, end, "emulator.cfg"); - if (p >= end) { - dwarning( "emulator configuration path too long" ); - emulator_configpath[0] = 0; - return; - } - - config = path_load_file( emulator_configpath, NULL ); - if (config == NULL) - D( "cannot load emulator configuration at '%s'\n", - emulator_configpath ); - else { - aconfig_load( emulator_config, config ); - emulator_config_found = 1; - } + userConfig = auserConfig_new( android_avdInfo ); } /* only call this function on normal exits, so that ^C doesn't save the configuration */ void emulator_config_done( void ) { - int save = 0; /* only save config if we see changes */ - AConfig* guid_node; - char guid_value[32]; - AConfig* window_node; - int prev_x, prev_y, win_x, win_y; - - if (!emulator_configpath[0]) { - D("no config path ?"); - return; - } - - /* compare window positions */ - { - SDL_WM_GetPos( &win_x, &win_y ); - prev_x = win_x - 1; - prev_y = win_y - 1; - - window_node = aconfig_find( emulator_config, "window" ); - if (window_node == NULL) { - aconfig_set( emulator_config, "window", "" ); - window_node = aconfig_find( emulator_config, "window" ); - save = 1; - } + int win_x, win_y; - prev_x = (int)aconfig_unsigned( window_node, "x", 0 ); - prev_y = (int)aconfig_unsigned( window_node, "y", 0 ); - - save = (prev_x != win_x) || (prev_y != win_y); - - /* Beware: If the new window position is definitely off-screen, - * we don't want to save it in the configuration file. This can - * happen for example on Linux where certain window managers - * will 'minimize' a window by moving it to coordinates like - * (-5000,-5000) - */ - if ( !SDL_WM_IsFullyVisible(0) ) { - D( "not saving new emulator window position since it is not fully visible" ); - save = 0; - } - else if (save) - D( "emulator window position changed and will be saved as (%d, %d)", win_x, win_y ); - } - - /* If there is no guid node, create one with the current time in - * milliseconds. Thus, the value doesn't correspond to any system or - * user-specific data - */ -#define GUID_NAME "unique-id" - - guid_node = aconfig_find( emulator_config, GUID_NAME ); - if (!guid_node) { - struct timeval tm; - gettimeofday( &tm, NULL ); - sprintf( guid_value, "%lld", (long long)tm.tv_sec*1000 + tm.tv_usec/1000 ); - save = 1; - aconfig_set( emulator_config, GUID_NAME, guid_value ); + if (!userConfig) { + D("no user configuration?"); + return; } - if (save) { - char xbuf[16], ybuf[16]; - - sprintf( xbuf, "%d", win_x ); - sprintf( ybuf, "%d", win_y ); - - aconfig_set( window_node, "x", xbuf ); - aconfig_set( window_node, "y", ybuf ); - - /* do we need to create the $HOME/.android directory ? */ - if ( !path_exists(emulator_configpath) ) { - char* dir = path_parent(emulator_configpath, 1); - if (dir == NULL) { - D("invalid user-specific config directory: '%s'", emulator_configpath); - return; - } - if ( path_mkdir_if_needed(dir, 0755) < 0 ) { - D("cannot create directory '%s', configuration lost", dir); - free(dir); - return; - } - free(dir); - } - if ( aconfig_save_file( emulator_config, emulator_configpath ) < 0 ) { - D( "cannot save configuration to %s", emulator_configpath); - } else - D( "configuration saved to %s", emulator_configpath ); - } + SDL_WM_GetPos( &win_x, &win_y ); + auserConfig_setWindowPos(userConfig, win_x, win_y); + auserConfig_save(userConfig); } void *loadpng(const char *fn, unsigned *_width, unsigned *_height); @@ -1135,18 +1041,11 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts) found_a_skin: { - AConfig* node = aconfig_find( emulator_config, "window" ); - win_x = 10; win_y = 10; - if (node == NULL) { - if (emulator_config_found) - dwarning( "broken configuration file doesn't have 'window' element" ); - } else { - win_x = aconfig_int( node, "x", win_x ); - win_y = aconfig_int( node, "y", win_y ); - } + if (userConfig) + auserConfig_getWindowPos(userConfig, &win_x, &win_y); } if ( qemulator_init( qemulator, root, path, win_x, win_y, opts ) < 0 ) { fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name); @@ -1339,7 +1238,7 @@ parse_keyset(const char* keyset, AndroidOptions* opts) return; p = temp; - p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->system, keyset); + p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset); if (p < end && load_keyset(temp) == 0) return; @@ -1874,6 +1773,16 @@ int main(int argc, char **argv) exit(1); } + /* special case, if -qemu -h is used, directly invoke the QEMU-specific help */ + if (argc > 0) { + int nn; + for (nn = 0; nn < argc; nn++) + if (!strcmp(argv[nn], "-h")) { + qemu_help(0); + break; + } + } + android_charmap = android_charmaps[0]; if (opts->version) { @@ -1902,6 +1811,55 @@ int main(int argc, char **argv) } } + /* legacy support: we used to use -system and -image + * instead of -sysdir and -system , so handle this by checking + * whether the options point to directories or files. + */ + if (opts->image != NULL) { + if (opts->system != NULL) { + if (opts->sysdir != NULL) { + derror( "You can't use -sysdir, -system and -image at the same time.\n" + "You should probably use '-sysdir -system '.\n" ); + exit(2); + } + } + dwarning( "Please note that -image is obsolete and that -system is now used to point\n" + "to the system image. Next time, try using '-sysdir -system ' instead.\n" ); + opts->sysdir = opts->system; + opts->system = opts->image; + opts->image = NULL; + } + else if (opts->system != NULL && path_is_dir(opts->system)) { + if (opts->sysdir != NULL) { + derror( "Option -system should now be followed by a file path, not a directory one.\n" + "Please use '-sysdir ' to point to the system directory.\n" ); + exit(1); + } + dwarning( "Please note that the -system option should now be used to point to the initial\n" + "system image (like the obsolete -image option). To point to the system directory\n" + "please now use '-sysdir ' instead.\n" ); + + opts->sysdir = opts->system; + opts->system = NULL; + } + + if (opts->nojni) + opts->no_jni = opts->nojni; + + if (opts->nocache) + opts->no_cache = opts->nocache; + + if (opts->noaudio) + opts->no_audio = opts->noaudio; + + if (opts->noskin) + opts->no_skin = opts->noskin; + + if (opts->initdata) { + opts->init_data = opts->initdata; + opts->initdata = NULL; + } + /* If no AVD name was given, try to find the top of the * Android build tree */ @@ -1940,9 +1898,9 @@ int main(int argc, char **argv) { char dataDirIsSystem = 0; - if (!opts->system) { - opts->system = _getSdkImagePath("system.img"); - if (!opts->system) { + if (!opts->sysdir) { + opts->sysdir = _getSdkImagePath("system.img"); + if (!opts->sysdir) { derror( "You did not specify a virtual device name, and the system\n" "directory could not be found.\n\n" @@ -1953,29 +1911,29 @@ int main(int argc, char **argv) ); exit(2); } - D("autoconfig: -system %s", opts->system); + D("autoconfig: -sysdir %s", opts->sysdir); } - if (!opts->image) { - opts->image = _getSdkSystemImage(opts->system, "-image", "system.img"); + if (!opts->system) { + opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img"); D("autoconfig: -image %s", opts->image); } if (!opts->kernel) { - opts->kernel = _getSdkSystemImage(opts->system, "-kernel", "kernel-qemu"); + opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu"); D("autoconfig: -kernel %s", opts->kernel); } if (!opts->ramdisk) { - opts->ramdisk = _getSdkSystemImage(opts->system, "-ramdisk", "ramdisk.img"); + opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img"); D("autoconfig: -ramdisk %s", opts->ramdisk); } /* if no data directory is specified, use the system directory */ if (!opts->datadir) { - opts->datadir = qemu_strdup(opts->system); + opts->datadir = qemu_strdup(opts->sysdir); dataDirIsSystem = 1; - D("autoconfig: -datadir %s", opts->system); + D("autoconfig: -datadir %s", opts->sysdir); } if (!opts->data) { @@ -1983,9 +1941,11 @@ int main(int argc, char **argv) bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir); if (!path_exists(tmp)) { derror( - "There is no file named 'userdata-qemu.img' in your %s directory.\n" - "You should specify one with the '-data ' option.", - dataDirIsSystem ? "system" : "data" + "You did not provide the name of an Android Virtual Device\n" + "with the '-avd ' option. Read -help-avd for more information.\n\n" + + "If you *really* want to *NOT* run an AVD, consider using '-data '\n" + "to specify a data partition image file (I hope you know what you're doing).\n" ); exit(2); } @@ -2005,7 +1965,7 @@ int main(int argc, char **argv) /* setup the virtual device parameters from our options */ - if (opts->nocache) { + if (opts->no_cache) { android_avdParams->flags |= AVDINFO_NO_CACHE; } if (opts->wipe_data) { @@ -2015,17 +1975,17 @@ int main(int argc, char **argv) /* if certain options are set, we can force the path of * certain kernel/disk image files */ - _forceAvdImagePath(AVD_IMAGE_KERNEL, opts->kernel, "kernel", 1); - _forceAvdImagePath(AVD_IMAGE_SYSTEM, opts->image, "system", 1); - _forceAvdImagePath(AVD_IMAGE_RAMDISK, opts->ramdisk,"ramdisk", 1); - _forceAvdImagePath(AVD_IMAGE_USERDATA,opts->data, "user data", 0); - _forceAvdImagePath(AVD_IMAGE_CACHE, opts->cache, "cache", 0); - _forceAvdImagePath(AVD_IMAGE_SDCARD, opts->sdcard, "SD Card", 0); + _forceAvdImagePath(AVD_IMAGE_KERNEL, opts->kernel, "kernel", 1); + _forceAvdImagePath(AVD_IMAGE_INITSYSTEM, opts->system, "system", 1); + _forceAvdImagePath(AVD_IMAGE_RAMDISK, opts->ramdisk,"ramdisk", 1); + _forceAvdImagePath(AVD_IMAGE_USERDATA, opts->data, "user data", 0); + _forceAvdImagePath(AVD_IMAGE_CACHE, opts->cache, "cache", 0); + _forceAvdImagePath(AVD_IMAGE_SDCARD, opts->sdcard, "SD Card", 0); /* we don't accept -skindir without -skin now * to simplify the autoconfig stuff with virtual devices */ - if (opts->noskin) { + if (opts->no_skin) { opts->skin = "320x480"; opts->skindir = NULL; } @@ -2066,7 +2026,7 @@ int main(int argc, char **argv) else { if (!android_build_out) { - android_build_out = android_build_root = opts->system; + android_build_out = android_build_root = opts->sysdir; } android_avdInfo = avdInfo_newForAndroidBuild( android_build_root, @@ -2079,17 +2039,15 @@ int main(int argc, char **argv) } } - if (!opts->skindir) { - /* get the skin from the virtual device configuration */ - opts->skin = (char*) avdInfo_getSkinName( android_avdInfo ); - opts->skindir = (char*) avdInfo_getSkinDir( android_avdInfo ); + /* get the skin from the virtual device configuration */ + opts->skin = (char*) avdInfo_getSkinName( android_avdInfo ); + opts->skindir = (char*) avdInfo_getSkinDir( android_avdInfo ); - if (opts->skin) { - D("autoconfig: -skin %s", opts->skin); - } - if (opts->skindir) { - D("autoconfig: -skindir %s", opts->skindir); - } + if (opts->skin) { + D("autoconfig: -skin %s", opts->skin); + } + if (opts->skindir) { + D("autoconfig: -skindir %s", opts->skindir); } /* Read hardware configuration */ @@ -2242,7 +2200,7 @@ int main(int argc, char **argv) } } - if (opts->nocache) + if (opts->no_cache) opts->cache = 0; if (opts->dns_server) { @@ -2291,12 +2249,12 @@ int main(int argc, char **argv) { const char* filetype = "file"; - if (avdInfo_isImageReadOnly(android_avdInfo, AVD_IMAGE_SYSTEM)) + if (avdInfo_isImageReadOnly(android_avdInfo, AVD_IMAGE_INITSYSTEM)) filetype = "initfile"; bufprint(tmp, tmpend, "system,size=0x4200000,%s=%s", filetype, - avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_SYSTEM)); + avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_INITSYSTEM)); args[n++] = "-nand"; args[n++] = strdup(tmp); @@ -2315,8 +2273,8 @@ int main(int argc, char **argv) } else if (opts->cache) { dwarning( "Emulated hardware doesn't support a cache partition" ); - opts->cache = NULL; - opts->nocache = 1; + opts->cache = NULL; + opts->no_cache = 1; } if (opts->cache) { @@ -2325,7 +2283,7 @@ int main(int argc, char **argv) args[n++] = "-nand"; args[n++] = strdup(tmp); } - else if (!opts->nocache) { + else if (!opts->no_cache) { /* create a temporary cache partition file */ sprintf(tmp, "cache,size=0x%0x", cachePartitionSize); args[n++] = "-nand"; @@ -2472,21 +2430,10 @@ int main(int argc, char **argv) opts->memory = qemu_strdup(tmp); } - if (opts->noaudio) { + if (opts->no_audio) { args[n++] = "-noaudio"; } -#if 0 - if (opts->mic) { - if (path_can_read(opts->mic)) { - args[n++] = "-mic"; - args[n++] = opts->mic; - } else { - dprint("could not find or access audio input at '%s'", opts->mic); - } - } -#endif - if (opts->trace) { args[n++] = "-trace"; args[n++] = opts->trace; @@ -2522,7 +2469,7 @@ int main(int argc, char **argv) p = bufprint(p, end, " android.tracing=1"); } - if (!opts->nojni) { + if (!opts->no_jni) { p = bufprint(p, end, " android.checkjni=1"); } diff --git a/android/user-config.c b/android/user-config.c new file mode 100644 index 0000000..acd1a27 --- /dev/null +++ b/android/user-config.c @@ -0,0 +1,212 @@ +/* Copyright (C) 2009 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "android/user-config.h" +#include "android/utils/bufprint.h" +#include "android/utils/debug.h" +#include "android/utils/system.h" +#include "android/utils/path.h" +#include +#include +#include + +#define D(...) VERBOSE_PRINT(init,__VA_ARGS__) + +#if 0 /* set to 1 for more debugging */ +# define DD(...) D(__VA_ARGS__) +#else +# define DD(...) ((void)0) +#endif + +struct AUserConfig { + ABool changed; + int windowX; + int windowY; + uint64_t uuid; + char* iniPath; +}; + +/* Name of the user-config file */ +#define USER_CONFIG_FILE "emulator-user.ini" + +#define KEY_WINDOW_X "window.x" +#define KEY_WINDOW_Y "window.y" +#define KEY_UUID "uuid" + +#define DEFAULT_X 100 +#define DEFAULT_Y 100 + +/* Create a new AUserConfig object from a given AvdInfo */ +AUserConfig* +auserConfig_new( AvdInfo* info ) +{ + AUserConfig* uc; + char inAndroidBuild = avdInfo_inAndroidBuild(info); + char needUUID = 1; + char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); + char* parentPath; + IniFile* ini = NULL; + + ANEW0(uc); + + /* If we are in the Android build system, store the configuration + * in ~/.android/emulator-user.ini. otherwise, store it in the file + * emulator-user.ini in the AVD's content directory. + */ + if (inAndroidBuild) { + p = bufprint_config_file(temp, end, USER_CONFIG_FILE); + } else { + p = bufprint(temp, end, "%s/%s", avdInfo_getContentPath(info), + USER_CONFIG_FILE); + } + + /* handle the unexpected */ + if (p >= end) { + /* Hmmm, something is weird, let's use a temporary file instead */ + p = bufprint_temp_file(temp, end, USER_CONFIG_FILE); + if (p >= end) { + derror("Weird: Cannot create temporary user-config file?"); + exit(2); + } + dwarning("Weird: Content path too long, using temporary user-config."); + } + + uc->iniPath = ASTRDUP(temp); + DD("looking user-config in: %s", uc->iniPath); + + + /* ensure that the parent directory exists */ + parentPath = path_parent(uc->iniPath, 1); + if (parentPath == NULL) { + derror("Weird: Can't find parent of user-config file: %s", + uc->iniPath); + exit(2); + } + + if (!path_exists(parentPath)) { + if (!inAndroidBuild) { + derror("Weird: No content path for this AVD: %s", parentPath); + exit(2); + } + DD("creating missing directory: %s", parentPath); + if (path_mkdir_if_needed(parentPath, 0755) < 0) { + derror("Using empty user-config, can't create %s: %s", + parentPath, strerror(errno)); + exit(2); + } + } + + if (path_exists(uc->iniPath)) { + DD("reading user-config file"); + ini = iniFile_newFromFile(uc->iniPath); + if (ini == NULL) { + dwarning("Can't read user-config file: %s\nUsing default values", + uc->iniPath); + } + } + + if (ini != NULL) { + uc->windowX = iniFile_getInteger(ini, KEY_WINDOW_X, DEFAULT_X); + DD(" found %s = %d", KEY_WINDOW_X, uc->windowX); + + uc->windowY = iniFile_getInteger(ini, KEY_WINDOW_Y, DEFAULT_Y); + DD(" found %s = %d", KEY_WINDOW_Y, uc->windowY); + + if (iniFile_getValue(ini, KEY_UUID) != NULL) { + uc->uuid = (uint64_t) iniFile_getInt64(ini, KEY_UUID, 0LL); + needUUID = 0; + DD(" found %s = %lld", KEY_UUID, uc->uuid); + } + + iniFile_free(ini); + } + else { + uc->windowX = DEFAULT_X; + uc->windowY = DEFAULT_Y; + uc->changed = 1; + } + + /* Generate a 64-bit UUID if necessary. We simply take the + * current time, which avoids any privacy-related value. + */ + if (needUUID) { + struct timeval tm; + + gettimeofday( &tm, NULL ); + uc->uuid = (uint64_t)tm.tv_sec*1000 + tm.tv_usec/1000; + uc->changed = 1; + DD(" Generated UUID = %lld", uc->uuid); + } + + return uc; +} + + +uint64_t +auserConfig_getUUID( AUserConfig* uconfig ) +{ + return uconfig->uuid; +} + +void +auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY ) +{ + *pX = uconfig->windowX; + *pY = uconfig->windowY; +} + + +void +auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y ) +{ + if (x != uconfig->windowX || y != uconfig->windowY) { + uconfig->windowX = x; + uconfig->windowY = y; + uconfig->changed = 1; + } +} + +/* Save the user configuration back to the content directory. + * Should be used in an atexit() handler */ +void +auserConfig_save( AUserConfig* uconfig ) +{ + IniFile* ini; + char temp[256]; + + if (uconfig->changed == 0) { + D("User-config was not changed."); + return; + } + + bufprint(temp, temp+sizeof(temp), + "%s = %d\n" + "%s = %d\n" + "%s = %lld\n", + KEY_WINDOW_X, uconfig->windowX, + KEY_WINDOW_Y, uconfig->windowY, + KEY_UUID, uconfig->uuid ); + + DD("Generated user-config file:\n%s", temp); + + ini = iniFile_newFromMemory(temp, uconfig->iniPath); + if (ini == NULL) { + D("Weird: can't create user-config iniFile?"); + return; + } + if (iniFile_saveToFile(ini, uconfig->iniPath) < 0) { + dwarning("could not save user configuration: %s: %s", + uconfig->iniPath, strerror(errno)); + } else { + D("User configuration saved to %s", uconfig->iniPath); + } + iniFile_free(ini); +} diff --git a/android/user-config.h b/android/user-config.h new file mode 100644 index 0000000..5fc6325 --- /dev/null +++ b/android/user-config.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2009 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef _ANDROID_USER_CONFIG_H +#define _ANDROID_USER_CONFIG_H + +#include "android/avd/info.h" +#include + +/* a structure used to model the user-configuration settings + * + * At the moment, this is only used to store the last position + * of the emulator window and a unique 64-bit UUID. We might + * add more AVD-specific preferences here in the future. + * + * By definition, these settings should be optional and we + * should be able to work without them, unlike the AVD + * configuration information found in config.ini + */ +typedef struct AUserConfig AUserConfig; + +/* Create a new AUserConfig object from a given AvdInfo */ +AUserConfig* auserConfig_new( AvdInfo* info ); + +/* Retrieve the unique UID for this AVD */ +uint64_t auserConfig_getUUID( AUserConfig* uconfig ); + +/* Retrieve the stored window position for this AVD */ +void auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY ); + +/* Change the stored window position for this AVD */ +void auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y ); + +/* Save the user configuration back to the content directory. + * Should be used in an atexit() handler. This will effectively + * only save the user configuration to disk if its content + * has changed. + */ +void auserConfig_save( AUserConfig* uconfig ); + +/* */ + +#endif /* _ANDROID_USER_CONFIG_H */ diff --git a/android/utils/ini.c b/android/utils/ini.c index 56e40f2..95bb4e3 100644 --- a/android/utils/ini.c +++ b/android/utils/ini.c @@ -17,6 +17,7 @@ #include #include "android/utils/debug.h" #include "android/utils/system.h" /* for ASTRDUP */ +#include "android/utils/bufprint.h" #include "osdep.h" /* W() is used to print warnings, D() to print debugging info */ @@ -172,7 +173,7 @@ iniFile_newFromMemory( const char* text, const char* fileName ) int lineno = 0; if (!fileName) - fileName = ""; + fileName = ""; D("%s: parsing as .ini file", fileName); @@ -197,8 +198,8 @@ iniFile_newFromMemory( const char* text, const char* fileName ) key = p++; if (!isKeyStartChar(*key)) { p = skipToEOL(p); - W("%s:%d: key name doesn't start with valid character. line ignored", - fileName, lineno); + W("%4d: key name doesn't start with valid character. line ignored", + lineno); continue; } @@ -210,8 +211,8 @@ iniFile_newFromMemory( const char* text, const char* fileName ) /* check the equal */ if (*p != '=') { - W("%s:%d: missing expected assignment operator (=). line ignored", - fileName, lineno); + W("%4d: missing expected assignment operator (=). line ignored", + lineno); p = skipToEOL(p); continue; } @@ -232,12 +233,14 @@ iniFile_newFromMemory( const char* text, const char* fileName ) valueLen = p - value; iniFile_addPair(ini, key, keyLen, value, valueLen); - D("%s:%d: KEY='%.*s' VALUE='%.*s'", fileName, lineno, + D("%4d: KEY='%.*s' VALUE='%.*s'", lineno, keyLen, key, valueLen, value); p = skipToEOL(p); } + D("%s: parsing finished", fileName); + return ini; } @@ -283,6 +286,33 @@ EXIT: return ini; } +int +iniFile_saveToFile( IniFile* f, const char* filepath ) +{ + FILE* fp = fopen(filepath, "wt"); + IniPair* pair = f->pairs; + IniPair* pairEnd = pair + f->numPairs; + int result = 0; + + if (fp == NULL) { + D("could not create .ini file: %s: %s", + filepath, strerror(errno)); + return -1; + } + + for ( ; pair < pairEnd; pair++ ) { + char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); + p = bufprint(temp, end, "%s = %s\n", pair->key, pair->value); + if (fwrite(temp, p - temp, 1, fp) != 1) { + result = -1; + break; + } + } + + fclose(fp); + return result; +} + char* iniFile_getString( IniFile* f, const char* key ) { diff --git a/android/utils/ini.h b/android/utils/ini.h index bc8193e..a176bfe 100644 --- a/android/utils/ini.h +++ b/android/utils/ini.h @@ -62,6 +62,11 @@ IniFile* iniFile_newFromMemory( const char* text, const char* fileName ); */ IniFile* iniFile_newFromFile( const char* filePath); +/* try to write an IniFile into a given file. + * returns 0 on success, -1 on error (see errno for error code) + */ +int iniFile_saveToFile( IniFile* f, const char* filePath ); + /* free an IniFile object */ void iniFile_free( IniFile* f ); diff --git a/android/utils/path.c b/android/utils/path.c index 9dd238e..b15b6de 100644 --- a/android/utils/path.c +++ b/android/utils/path.c @@ -101,6 +101,111 @@ path_parent( const char* path, int levels ) return result; } +static char* +substring_dup( const char* start, const char* end ) +{ + int len = end - start; + char* result = android_alloc(len+1); + memcpy(result, start, len); + result[len] = 0; + return result; +} + +int +path_split( const char* path, char* *pdirname, char* *pbasename ) +{ + const char* end = path + strlen(path); + const char* last; + char* basename; + + /* prepare for errors */ + if (pdirname) + *pdirname = NULL; + if (pbasename) + *pbasename = NULL; + + /* handle empty path case */ + if (end == path) { + return -1; + } + + /* strip trailing path separators */ + while (end > path && ispathsep(end[-1])) + end -= 1; + + /* handle "/" and degenerate cases like "////" */ + if (end == path) { + return -1; + } + + /* find last separator */ + last = end; + while (last > path && !ispathsep(last[-1])) + last -= 1; + + /* handle cases where there is no path separator */ + if (last == path) { + if (pdirname) + *pdirname = ASTRDUP("."); + if (pbasename) + *pbasename = substring_dup(path,end); + return 0; + } + + /* handle "/foo" */ + if (last == path+1) { + if (pdirname) + *pdirname = ASTRDUP("/"); + if (pbasename) + *pbasename = substring_dup(path+1,end); + return 0; + } + + /* compute basename */ + basename = substring_dup(last,end); + if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) { + AFREE(basename); + return -1; + } + + if (pbasename) + *pbasename = basename; + else { + AFREE(basename); + } + + /* compute dirname */ + if (pdirname != NULL) + *pdirname = substring_dup(path,last-1); + + return 0; +} + +char* +path_basename( const char* path ) +{ + char* basename; + + if (path_split(path, NULL, &basename) < 0) + return NULL; + + return basename; +} + +char* +path_dirname( const char* path ) +{ + char* dirname; + + if (path_split(path, &dirname, NULL) < 0) + return NULL; + + return dirname; +} + + + + /** MISC FILE AND DIRECTORY HANDLING **/ @@ -290,6 +395,30 @@ path_get_size( const char* path, uint64_t *psize ) } +ABool +path_is_absolute( const char* path ) +{ +#ifdef _WIN32 + if (path == NULL) + return 0; + + if (path[0] == '/' || path[0] == '\\') + return 1; + + /* 'C:' is always considered to be absolute + * even if used with a relative path like C:foo which + * is different from C:\foo + */ + if (path[0] != 0 && path[1] == ':') + return 1; + + return 0; +#else + return (path != NULL && path[0] == '/'); +#endif +} + + /** OTHER FILE UTILITIES ** ** path_empty_file() creates an empty file at a given path location. diff --git a/android/utils/path.h b/android/utils/path.h index 10436c6..e822834 100644 --- a/android/utils/path.h +++ b/android/utils/path.h @@ -55,6 +55,9 @@ extern ABool path_is_regular( const char* path ); /* checks that a path points to a directory */ extern ABool path_is_dir( const char* path ); +/* checks that a path is absolute or not */ +extern ABool path_is_absolute( const char* path ); + /* checks that one can read/write a given (regular) file */ extern ABool path_can_read( const char* path ); extern ABool path_can_write( const char* path ); @@ -77,6 +80,33 @@ extern APosixStatus path_get_size( const char* path, uint64_t *psize ); */ extern char* path_parent( const char* path, int levels ); +/* split a path into a (dirname,basename) pair. the result strings must be freed + * by the caller. Return 0 on success, or -1 on error. Error conditions include + * the following: + * - 'path' is empty + * - 'path' is "/" or degenerate cases like "////" + * - basename is "." or ".." + * + * if there is no directory separator in path, *dirname will be set to "." + * if the path is of type "/foo", then *dirname will be set to "/" + * + * pdirname can be NULL if you don't want the directory name + * pbasename can be NULL if you don't want the base name + */ +extern int path_split( const char* path, char* *pdirname, char* *pbasename ); + +/* a convenience function to retrieve the directory name as returned by + * path_split(). Returns NULL if path_split() returns an error. + * the result string must be freed by the caller + */ +extern char* path_dirname( const char* path ); + +/* a convenience function to retrieve the base name as returned by + * path_split(). Returns NULL if path_split() returns an error. + * the result must be freed by the caller. + */ +extern char* path_basename( const char* path ); + /** OTHER FILE UTILITIES ** ** path_empty_file() creates an empty file at a given path location. diff --git a/block.c b/block.c index 23ce5e4..06bea78 100644 --- a/block.c +++ b/block.c @@ -56,7 +56,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, static BlockDriver *first_drv; -int path_is_absolute(const char *path) +static int path_is_absolute(const char *path) { const char *p; #ifdef _WIN32 diff --git a/block.h b/block.h index d774a2e..7917eb8 100644 --- a/block.h +++ b/block.h @@ -150,7 +150,8 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf); char *get_human_readable_size(char *buf, int buf_size, int64_t size); -int path_is_absolute(const char *path); +// don't remove below comment, it makes integration with upstream sources easier +//int path_is_absolute(const char *path); void path_combine(char *dest, int dest_size, const char *base_path, const char *filename); diff --git a/vl.c b/vl.c index 99c49bf..a9c1940 100644 --- a/vl.c +++ b/vl.c @@ -8102,7 +8102,7 @@ ExitRequested: #endif } -static void help(int exitcode) +void qemu_help(int exitcode) { printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" @@ -9046,7 +9046,7 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_h: - help(0); + qemu_help(0); break; case QEMU_OPTION_m: { uint64_t value; @@ -9465,7 +9465,7 @@ int main(int argc, char **argv) if (!linux_boot && net_boot == 0 && !machine->nodisk_ok && nb_drives_opt == 0) - help(1); + qemu_help(1); if (!linux_boot && *kernel_cmdline != '\0') { fprintf(stderr, "-append only allowed with -kernel option\n"); -- cgit v1.1