aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:30 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:30 -0800
commitee2298a313b6e425d6ff0324be6a313b1cd9a399 (patch)
treee23c2549bfe9c14afbabe8cc2afa1da5218b540b
parentd944e7a273e10cb40d795bdc25503b97ee60ae66 (diff)
downloadexternal_qemu-ee2298a313b6e425d6ff0324be6a313b1cd9a399.zip
external_qemu-ee2298a313b6e425d6ff0324be6a313b1cd9a399.tar.gz
external_qemu-ee2298a313b6e425d6ff0324be6a313b1cd9a399.tar.bz2
auto import from //depot/cupcake/@137055
-rw-r--r--CHANGES.TXT24
-rw-r--r--Makefile.android1
-rw-r--r--android/avd/info.c548
-rw-r--r--android/avd/info.h14
-rw-r--r--android/cmdline-options.h22
-rw-r--r--android/help.c52
-rw-r--r--android/main.c283
-rw-r--r--android/user-config.c212
-rw-r--r--android/user-config.h51
-rw-r--r--android/utils/ini.c42
-rw-r--r--android/utils/ini.h5
-rw-r--r--android/utils/path.c129
-rw-r--r--android/utils/path.h30
-rw-r--r--block.c2
-rw-r--r--block.h3
-rw-r--r--vl.c6
16 files changed, 1084 insertions, 340 deletions
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 <dir>' has been introduced, the interpretation of
+ the '-system' option has changed, and '-image <file>' should now be
+ considered obsolete. In more details:
+
+ * you should now use '-sysdir <dir>' instead of '-system <dir>' to specify
+ the directory where system images will be searched by the emulator
+ on startup.
+
+ * you should now use '-system <file>' to indicate which system.img partition
+ image to use at startup.
+
+ * you should not use '-system <dir>' or '-image <path>' 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 <ctype.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
+/* 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 = <first search path>
+ * images.sysdir.2 = <second search path>
+ *
+ * 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 <foo>.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 <name>' can be used to specify the
+ * name of a skin, to override the AVD settings.
+ *
+ * - skins are searched from <dir>/../skins for each <dir> in the
+ * images search list, unless a '-skindir <path>' 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 <dir> in the list,
+ * look the skins in <dir>/.. */
+ {
+ 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("<build>");
+ i->deviceName = ASTRDUP("<build>");
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, "<dir>", "read system image from <dir>" )
+CFG_PARAM( sysdir, "<dir>", "search for system disk images in <dir>" )
+CFG_PARAM( system, "<file>", "read initial system image from <file>" )
CFG_PARAM( datadir, "<dir>", "write user data into <dir>" )
CFG_PARAM( kernel, "<file>", "use specific emulated kernel" )
CFG_PARAM( ramdisk, "<file>", "ramdisk image (default <system>/ramdisk.img" )
-CFG_PARAM( image, "<file>", "system image (default <system>/system.img" )
-CFG_PARAM( initdata, "<file>", "initial data image (default <system>/userdata.img" )
+CFG_PARAM( image, "<file>", "obsolete, use -system <file> instead" )
+CFG_PARAM( init_data, "<file>", "initial data image (default <system>/userdata.img" )
+CFG_PARAM( initdata, "<file>", "same as '-init-data <file>'" )
CFG_PARAM( data, "<file>", "data image (default <datadir>/userdata-qemu.img" )
CFG_PARAM( cache, "<file>", "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, "<file>", "SD card image (default <system>/sdcard.img")
OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
CFG_PARAM( avd, "<name>", "use a specific android virtual device" )
CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
-CFG_PARAM( skin, "<file>", "select a given skin" )
-CFG_FLAG ( noskin, "don't use any emulator skin" )
+CFG_PARAM( skin, "<name>", "select a given skin" )
+CFG_FLAG ( no_skin, "don't use any emulator skin" )
+CFG_FLAG ( noskin, "same as -no-skin" )
CFG_PARAM( memory, "<size>", "physical RAM size in MBs" )
OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
@@ -83,10 +87,12 @@ OPT_FLAG ( netfast, "disable network shaping" )
OPT_PARAM( trace, "<name>", "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, "<tags>", "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, "<backend>", "use specific audio backend" )
OPT_PARAM( audio_in, "<backend>", "use specific audio input backend" )
OPT_PARAM( audio_out,"<backend>", "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 <build-root>/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 <dir>' to specify a directory where system read-only\n"
+ " use '-sysdir <dir>' 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 <file>' to specify the intial system image that will be loaded.\n"
+ " use '-system <file>' 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 <path>' was equivalent to using '-sysdir <path>' 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 <file>' 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 <file>' to specify an *init* /data partition file.\n"
+ " use '-init-data <file>' 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 <dir> and -image <file>
+ * instead of -sysdir <dir> and -system <file>, 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 <path> -system <file>'.\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 <path> -system <file>' 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 <path>' 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 <path>' 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 <filepath>' option.",
- dataDirIsSystem ? "system" : "data"
+ "You did not provide the name of an Android Virtual Device\n"
+ "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
+
+ "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\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 <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#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 <stdint.h>
+
+/* 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 <errno.h>
#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 = "<unknownFile>";
+ fileName = "<memoryFile>";
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");