Esempio n. 1
0
int mkdir_with_parents(const char *dir, int mode)
{
	if (!dir) return -1;
	if (__mkdir(dir, mode) == 0) {
		return 0;
	} else {
		if (errno == EEXIST) {
			return 0;
		} else if (errno == ENOENT) {
			// ignore
		} else {
			return -1;
		}
	}
	int res;
	char *parent = strdup(dir);
	char *parentdir = dirname(parent);
	if (parentdir && (strcmp(parentdir, ".") != 0) && (strcmp(parentdir, dir) != 0)) {
		res = mkdir_with_parents(parentdir, mode);
	} else {
		res = -1;	
	}
	free(parent);
	if (res == 0) {
		mkdir_with_parents(dir, mode);
	}
	return res;
}
Esempio n. 2
0
int mkdir_with_parents(const char *dir, int mode)
{
	if (!dir) return -1;
	if (__mkdir(dir, mode) == 0) {
		return 0;
	} else {
		if (errno == EEXIST) return 0;	
	}
	int res;
	char *parent = strdup(dir);
	parent = dirname(parent);
	if (parent) {
		res = mkdir_with_parents(parent, mode);
	} else {
		res = -1;	
	}
	free(parent);
	if (res == 0) {
		mkdir_with_parents(dir, mode);
	}
	return res;
}
Esempio n. 3
0
bool _vmnetfs_ll_modified_init(struct vmnetfs_image *img, GError **err)
{
    GDir *dir;
    const char *name;
    char *endptr;
    uint64_t dir_num;
    char *path;
    char *uploaded_base;

    if (!mkdir_with_parents(img->modified_base, err)) {
        return false;
    }

    dir = g_dir_open(img->modified_base, 0, err);
    if (dir == NULL) {
        return false;
    }

    img->modified_map = _vmnetfs_bit_new(img->bitmaps, true);
    img->uploaded_map = _vmnetfs_bit_new(img->bitmaps, false);
    while ((name = g_dir_read_name(dir)) != NULL) {
        path = g_strdup_printf("%s/%s", img->modified_base, name);
        dir_num = g_ascii_strtoull(name, &endptr, 10);
        if (*name != 0 && *endptr == 0 && g_file_test(path,
                G_FILE_TEST_IS_DIR)) {
            if (!set_present_from_directory(img, path, dir_num, err)) {
                g_free(path);
                g_dir_close(dir);
                _vmnetfs_bit_free(img->modified_map);
                return false;
            }
        }
        g_free(path);
    }
    g_dir_close(dir);

    // Checkin?
    return true;
}
Esempio n. 4
0
File: common.c Progetto: xorgy/uirc3
/// This differs from the non-unique version in that we expect the filename
/// to be something like a pattern for mkstemp(), so the resulting path can
/// reside in a system-wide directory with no risk of a conflict.
static char *
resolve_relative_runtime_unique_filename (const char *filename)
{
	struct str path;
	str_init (&path);

	const char *runtime_dir = getenv ("XDG_RUNTIME_DIR");
	if (runtime_dir && *runtime_dir == '/')
		str_append (&path, runtime_dir);
	else
		str_append (&path, "/tmp");
	str_append_printf (&path, "/%s/%s", PROGRAM_NAME, filename);

	// Try to create the file's ancestors;
	// typically the user will want to immediately create a file in there
	const char *last_slash = strrchr (path.str, '/');
	if (last_slash && last_slash != path.str)
	{
		char *copy = xstrndup (path.str, last_slash - path.str);
		(void) mkdir_with_parents (copy, NULL);
		free (copy);
	}
	return str_steal (&path);
}
Esempio n. 5
0
static int
emit_package (lcmgen_t *lcm, _package_contents_t *pc)
{
    // create the package directory, if necessary
    char **dirs = g_strsplit (pc->name, ".", 0);
    char *pdname = build_filenamev (dirs);
    char package_dir[PATH_MAX];
    char package_dir_prefix[PATH_MAX];
    int have_package = dirs[0] != NULL;
    int write_init_py = !getopt_get_bool(lcm->gopt, "python-no-init");

    sprintf (package_dir_prefix, "%s%s", getopt_get_string(lcm->gopt, "ppath"), 
            strlen(getopt_get_string(lcm->gopt, "ppath")) > 0 ? 
            G_DIR_SEPARATOR_S : "");
    sprintf(package_dir, "%s%s%s", package_dir_prefix, pdname,
            have_package ? G_DIR_SEPARATOR_S : "");
    free (pdname);
    if (strlen (package_dir)) {
        if (! g_file_test (package_dir, G_FILE_TEST_EXISTS)) {
//            g_mkdir_with_parents (package_dir, 0755);
            mkdir_with_parents (package_dir, 0755);
        }
        if (!g_file_test (package_dir, G_FILE_TEST_IS_DIR)) {
            err ("Could not create directory %s\n", package_dir);
            return -1;
        }
    }

    // write the package __init__.py files, if necessary
    FILE *init_py_fp = NULL;
    GHashTable * init_py_imports = g_hash_table_new_full(g_str_hash, 
            g_str_equal, free, NULL);
    if (have_package && write_init_py) {
        int ndirs = 0;
        for (ndirs=0; dirs[ndirs]; ndirs++);

        for (int i=0 ; i<ndirs; i++) {
            char *initpy_fname_parts[1024];
            assert(ndirs + 4 < 1024);

            initpy_fname_parts[0] = package_dir_prefix;
            for (int j=0; j<=i; j++) {
                initpy_fname_parts[j+1] = dirs[j];
            }
            initpy_fname_parts[i+2] = "__init__.py";
            initpy_fname_parts[i+3] = NULL;

            char *initpy_fname = build_filenamev (initpy_fname_parts);
            int created_initpy = 0;

            // close init_py_fp if already open
            if(init_py_fp) {
                fclose(init_py_fp);
                init_py_fp = NULL;
            }

            if (! g_file_test (initpy_fname, G_FILE_TEST_EXISTS)) {
                // __init__.py does not exist for this package.  Create it.
                created_initpy = 1;
                init_py_fp = fopen(initpy_fname, "w");
            } else {
                // open the existing __init__.py file, and make note of the
                // modules it imports
                created_initpy = 0;
                init_py_fp = fopen(initpy_fname, "r+");
            }

            if (!init_py_fp) {
                perror ("fopen");
                free (initpy_fname);
                return -1;
            }
#ifndef WIN32
            // lock __init__.py for exclusive write access
            // TODO do the equivalent in windows
            struct flock lockinfo;
            lockinfo.l_type = F_WRLCK;
            lockinfo.l_start = 0;
            lockinfo.l_whence = SEEK_SET;
            lockinfo.l_len = 0 ;
            lockinfo.l_pid = getpid();
            if(0 != fcntl(fileno(init_py_fp), F_SETLKW, &lockinfo)) {
                perror("locking __init__.py");
                free(initpy_fname);
                fclose(init_py_fp);
                return -1;
            }
#endif

            if(created_initpy) {
                fprintf (init_py_fp, "\"\"\"LCM package __init__.py file\n"
                        "This file automatically generated by lcm-gen.\n"
                        "DO NOT MODIFY BY HAND!!!!\n"
                        "\"\"\"\n\n");
            } else {
                while(!feof(init_py_fp)) {
                    char buf[4096];
                    memset(buf, 0, sizeof(buf));
                    char *result = fgets(buf, sizeof(buf)-1, init_py_fp);
                    if(!result)
                        break;

                    g_strstrip(buf);
                    char **words = g_strsplit(buf, " ", -1);
                    if(!words[0] || !words[1] || !words[2] || !words[3])
                        continue;
                    if(!strcmp(words[0], "from") && !strcmp(words[2], "import")) {
                        char *module_name = strdup(words[1]+1); // ignore leading dot
                        g_hash_table_replace(init_py_imports, module_name, 
                                module_name);
                    }

                    g_strfreev(words);
                }
            }
            free (initpy_fname);
        }
    }
    g_strfreev (dirs);

    ////////////////////////////////////////////////////////////
    // ENUMS
    for (int i=0; i<pc->enums->len; i++) {
        lcm_enum_t *le = (lcm_enum_t *) g_ptr_array_index (pc->enums, i);

        char path[PATH_MAX];
        sprintf (path, "%s%s.py", package_dir, le->enumname->shortname);

        if(init_py_fp && 
           !g_hash_table_lookup(init_py_imports, le->enumname->shortname))
            fprintf(init_py_fp, "from .%s import %s\n", 
                    le->enumname->shortname,
                    le->enumname->shortname);

        if (!lcm_needs_generation(lcm, le->lcmfile, path))
            continue;

        FILE *f = fopen(path, "w");
        if (f==NULL) return -1;

        fprintf(f, "\"\"\"LCM type definitions\n"
                "This file automatically generated by lcm.\n"
                "DO NOT MODIFY BY HAND!!!!\n"
                "\"\"\"\n"
                "\n"
                "try:\n"
                "    import cStringIO.StringIO as BytesIO\n"
                "except ImportError:\n"
                "    from io import BytesIO\n"
                "import struct\n\n");

        // enums always encoded as int32
        emit (0, "class %s(object):", le->enumname->shortname);
        emit (1, "__slots__ = [ \"value\" ]");
        for (unsigned int v = 0; v < le->values->len; v++) {
            lcm_enum_value_t *lev = (lcm_enum_value_t *) g_ptr_array_index(le->values, v);
            emit(1, "%s = %i", lev->valuename, lev->value);
        }

        emit (1, "_packed_fingerprint = struct.pack(\">Q\", 0x%"PRIx64")",
                le->hash);
        fprintf (f, "\n");

        emit (1, "def __init__ (self, value):");
        emit (2,     "self.value = value");
        fprintf (f, "\n");

        emit (1, "def _get_hash_recursive(parents):");
        emit (2,     "return 0x%"PRIx64, le->hash);
        emit (1, "_get_hash_recursive=staticmethod(_get_hash_recursive)");
        emit (1, "def _get_packed_fingerprint():");
        emit (2,     "return %s._packed_fingerprint", le->enumname->shortname);
        emit (1, "_get_packed_fingerprint = staticmethod(_get_packed_fingerprint)");
        fprintf (f, "\n");

        emit (1, "def encode(self):");
        emit (2,     "return struct.pack(\">Qi\", 0x%"PRIx64", self.value)",
                le->hash);

        emit (1, "def _encode_one(self, buf):");
        emit (2,     "buf.write (struct.pack(\">i\", self.value))");
        fprintf (f, "\n");

        emit (1, "def decode(data):");
        emit (2,     "if hasattr (data, 'read'):");
        emit (3,         "buf = data");
        emit (2,     "else:");
        emit (3,         "buf = BytesIO(data)");
        emit (2,     "if buf.read(8) != %s._packed_fingerprint:", 
                le->enumname->shortname);
        emit (3,         "raise ValueError(\"Decode error\")");
        emit (2,     "return %s(struct.unpack(\">i\", buf.read(4))[0])",
                le->enumname->shortname);
        emit (1, "decode = staticmethod(decode)");

        emit (1, "def _decode_one(buf):");
        emit (2,     "return %s(struct.unpack(\">i\", buf.read(4))[0])",
                le->enumname->shortname);
        emit (1, "_decode_one = staticmethod(_decode_one)");

        fprintf (f, "\n");
        fclose (f);
    }

    ////////////////////////////////////////////////////////////
    // STRUCTS
    for (int i = 0; i<pc->structs->len; i++) {
        lcm_struct_t *ls = (lcm_struct_t *) g_ptr_array_index(pc->structs, i);

        char path[PATH_MAX];
        sprintf (path, "%s%s.py", package_dir, ls->structname->shortname);

        if(init_py_fp && 
           !g_hash_table_lookup(init_py_imports, ls->structname->shortname))
            fprintf(init_py_fp, "from .%s import %s\n", 
                    ls->structname->shortname,
                    ls->structname->shortname);

        if (!lcm_needs_generation(lcm, ls->lcmfile, path))
            continue;

        FILE *f = fopen(path, "w");
        if (f==NULL) return -1;

        fprintf(f, "\"\"\"LCM type definitions\n"
                "This file automatically generated by lcm.\n"
                "DO NOT MODIFY BY HAND!!!!\n"
                "\"\"\"\n"
                "\n"
                "try:\n"
                "    import cStringIO.StringIO as BytesIO\n"
                "except ImportError:\n"
                "    from io import BytesIO\n"
                "import struct\n\n");

        emit_python_dependencies (lcm, f, ls);

        fprintf(f, "class %s(object):\n", ls->structname->shortname);
        fprintf (f,"    __slots__ = [");
        for (unsigned int member = 0; member < ls->members->len; member++) {
            lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index (ls->members, member);
            fprintf (f, "\"%s\"%s", lm->membername, 
                    member < ls->members->len-1 ? ", " : "");
        }
        fprintf (f, "]\n\n");

        // CONSTANTS
        for (unsigned int cn = 0; cn < g_ptr_array_size(ls->constants); cn++) {
            lcm_constant_t *lc = (lcm_constant_t *) g_ptr_array_index(ls->constants, cn);
            assert(lcm_is_legal_const_type(lc->lctypename));
            emit(1, "%s = %s", lc->membername, lc->val_str);
        }
        if (g_ptr_array_size(ls->constants) > 0)
            emit(0, "");

        emit_python_init (lcm, f, ls);
        emit_python_encode (lcm, f, ls);
        emit_python_encode_one (lcm, f, ls);
        emit_python_decode (lcm, f, ls);
        emit_python_decode_one (lcm, f, ls);
        emit_python_fingerprint (lcm, f, ls);
        fclose (f);
    }

    if(init_py_fp)
        fclose(init_py_fp);
    g_hash_table_destroy(init_py_imports);
    return 0;
}
Esempio n. 6
0
// XXX step 2, basically the main function
static int
emit_package (lcmgen_t *lcm, _package_contents_t *pc)
{
    // create the package directory, if necessary
    char **dirs = g_strsplit (pc->name, ".", 0);
    char *pdname = build_filenamev (dirs);
    char package_dir[PATH_MAX];
    char package_dir_prefix[PATH_MAX];
    int have_package = dirs[0] != NULL;

    sprintf (package_dir_prefix, "%s%s", getopt_get_string(lcm->gopt, "lpath"),
            strlen(getopt_get_string(lcm->gopt, "lpath")) > 0 ?
            G_DIR_SEPARATOR_S : "");
    sprintf(package_dir, "%s%s%s", package_dir_prefix, pdname,
            have_package ? G_DIR_SEPARATOR_S : "");
    free (pdname);
    if (strlen (package_dir)) {
        if (! g_file_test (package_dir, G_FILE_TEST_EXISTS)) {
//            g_mkdir_with_parents (package_dir, 0755);
            mkdir_with_parents (package_dir, 0755);
        }
        if (!g_file_test (package_dir, G_FILE_TEST_IS_DIR)) {
            err ("Could not create directory %s\n", package_dir);
            return -1;
        }
    }

    // write the package init.lua files, if necessary
    FILE *init_lua_fp = NULL;
    GHashTable * initlua_requires = NULL;
    GHashTable * initlua_requires_subpack = NULL;

    if (have_package) {
        int ndirs = 0;
        for (ndirs=0; dirs[ndirs]; ndirs++);

        for (int i=0 ; i<ndirs; i++) {

        	// make filename
        	char *initlua_fname;

        	{
        		char *initlua_fname_parts[1024];
        		assert(ndirs + 4 < 1024);

        		initlua_fname_parts[0] = package_dir_prefix;
        		for (int j=0; j<=i; j++) {
        			initlua_fname_parts[j+1] = dirs[j];
        		}
        		initlua_fname_parts[i+2] = "init.lua";
        		initlua_fname_parts[i+3] = NULL;

        		initlua_fname = build_filenamev (initlua_fname_parts);
        	}

            // make current package name
        	char * package_name;

        	{
        		char * name_parts[1024];
        		assert(i < 1024);

        		for (int j = 0; j <= i; j++) {
        			name_parts[j] = dirs[j];
        		}
        		name_parts[i + 1] = NULL;

        		package_name = g_strjoinv(".", name_parts);
        	}

            if (initlua_requires) {
            	g_hash_table_destroy(initlua_requires);
            	initlua_requires = NULL;
            }

            if (initlua_requires_subpack) {
            	g_hash_table_destroy(initlua_requires_subpack);
            	initlua_requires_subpack = NULL;
            }

            initlua_requires = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
            initlua_requires_subpack = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);

            // if the file already exists, read the contents
            if (g_file_test (initlua_fname, G_FILE_TEST_EXISTS)) {

            	init_lua_fp = fopen(initlua_fname, "r");

            	if (!init_lua_fp) {
            		perror ("fopen");
            		free (initlua_fname);
            		g_free(package_name);
            		return -1;
            	}

            	while(!feof(init_lua_fp)) {
            		char buf[4096];
            		memset(buf, 0, sizeof(buf));
            		char *result = fgets(buf, sizeof(buf)-1, init_lua_fp);
            		if(!result)
            			break;

            		// XXX get all of the previous types and packages

            		// this regex works because the first part is greedy
            		GRegex * regex = g_regex_new("require\\('([\\w+\\.]*\\.)(\\w+)'\\)( -- subpackage)?",
						(GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
            		GMatchInfo * matchinfo;

            		if(g_regex_match(regex, buf, (GRegexMatchFlags) 0, &matchinfo)){
            			if(g_match_info_get_match_count(matchinfo) == 3){
            				// not a subpackage
            				gchar * classname = g_match_info_fetch(matchinfo, 2);
            				g_hash_table_insert(initlua_requires, g_strdup(classname), g_strdup(classname));
            			}else if(g_match_info_get_match_count(matchinfo) == 4){
            				// this is a subpackage
            				// XXX fprintf(stderr, "> buff: %s\n", buf);
            				gchar * superpackage = g_match_info_fetch(matchinfo, 1);
            				gchar * subpackage = g_match_info_fetch(matchinfo, 2);
            				// XXX fprintf(stderr, "> super: %s, sub: %s\n", superpackage, subpackage);
            				gchar * fullsubpackage = g_strjoin("", superpackage, subpackage, NULL);
            				// XXX fprintf(stderr, "> [2] inserting: %s\n", fullsubpackage);
            				g_hash_table_insert(initlua_requires_subpack, g_strdup(fullsubpackage), g_strdup(fullsubpackage));
            				g_free(fullsubpackage);
            			}
            		}

            		g_match_info_free(matchinfo);
            		g_regex_unref(regex);
            	}

            	fclose(init_lua_fp);
            	init_lua_fp = NULL;
            }

            init_lua_fp = fopen(initlua_fname, "w");
            // XXX fprintf(stderr, "> opened: %s\n", initlua_fname);

            if (!init_lua_fp) {
            	perror ("fopen");
            	free (initlua_fname);
            	g_free(package_name);
            	return -1;
            }

#ifndef WIN32
            // lock init.lua for exclusive write access
            // TODO do the equivalent in windows
            struct flock lockinfo;
            lockinfo.l_type = F_WRLCK;
            lockinfo.l_start = 0;
            lockinfo.l_whence = SEEK_SET;
            lockinfo.l_len = 0 ;
            lockinfo.l_pid = getpid();
            if(0 != fcntl(fileno(init_lua_fp), F_SETLKW, &lockinfo)) {
                perror("locking init.lua");
                free(initlua_fname);
                g_free(package_name);
                fclose(init_lua_fp);
                return -1;
            }
#endif

            fprintf (init_lua_fp, "--[[\n"
            		"LCM package init.lua file\n"
            		"This file automatically generated by lcm-gen.\n"
            		"DO NOT MODIFY BY HAND!!!!\n"
            		"--]]\n"
            		"\n"
            		"local M = {}\n"
            		"\n");

            // add in all previous types
            GList * package_types = g_hash_table_get_values(initlua_requires);

            for (int j = 0; j < g_list_length(package_types); j++) {
            	char * tn = (char *) g_list_nth_data(package_types, j);
            	char * fn = g_strjoin(".", package_name, tn, NULL);
            	fprintf(init_lua_fp, "M.%s = require('%s')\n", tn, fn);
            	g_free(fn);
            }

            g_list_free(package_types);

            // add in all previous packages
            GList * subpacks = g_hash_table_get_values(initlua_requires_subpack);

            for (int j = 0; j < g_list_length(subpacks); j++) {
            	char * spn = (char *) g_list_nth_data(subpacks, j);
            	// get the base of the package name
            	char ** tmpsplit = g_strsplit(spn, ".", -1);
            	char * sn = tmpsplit[g_strv_length(tmpsplit) - 1];
            	// XXX fprintf(stderr, "[1] sn: %s, spn: %s\n", sn, spn);
            	fprintf(init_lua_fp, "M.%s = require('%s') -- subpackage\n", sn, spn);
            	g_strfreev(tmpsplit);
            }

            g_list_free(subpacks);

            // if the current package has a subpackage (which eventually contains the target package)
            // add a `require` for that subpackage to the current (if it hasn't already)
            if (i + 1 < ndirs) {
            	char *subpack_name = g_strjoin(".", package_name, dirs[i + 1], NULL);

            	// check for the subpackage name
            	if (!g_hash_table_lookup(initlua_requires_subpack, subpack_name)) {

            		// add it if it didn't exist
            		g_hash_table_insert(initlua_requires_subpack, g_strdup(subpack_name), g_strdup(subpack_name));
            		// XXX fprintf(stderr, "[2] sn: %s, spn: %s\n", dirs[i + 1], subpack_name);
            		fprintf(init_lua_fp, "M.%s = require('%s') -- subpackage\n", dirs[i + 1], subpack_name);
            	}

            	g_free(subpack_name);
            }

            // not yet the target?
            if (i + 1 < ndirs) {

            	// close it out
            	fprintf(init_lua_fp, "\nreturn M\n\n");
            	fclose(init_lua_fp);
            	init_lua_fp = NULL;
            }

            free (initlua_fname);
            g_free(package_name);
        }
    }
    g_strfreev (dirs);

    ////////////////////////////////////////////////////////////
    // STRUCTS
    for (int i = 0; i<pc->structs->len; i++) {
        lcm_struct_t *ls = (lcm_struct_t *) g_ptr_array_index(pc->structs, i);

        char path[PATH_MAX];
        sprintf (path, "%s%s.lua", package_dir, ls->structname->shortname);

        if(init_lua_fp){

        	// XXX add the 'require' to the appropriate init.lua
        	if (!g_hash_table_lookup(initlua_requires, ls->structname->shortname)) {
        		fprintf(init_lua_fp, "M.%s = require('%s')\n", ls->structname->shortname, ls->structname->lctypename);
        	}

        	// XXX look for subpackages
        	for (unsigned int m = 0; m < g_ptr_array_size(ls->members); m++) {
        		lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, m);

        		if(g_str_has_prefix(lm->type->package, pc->name)){

        			// make a regex starting with the current package...
        			gchar ** tmpsplit = g_strsplit(pc->name, ".", 0);
        			gchar * regexpackage = g_strjoinv("\\.", tmpsplit);

        			// only look for immediate submodules, not submodules of the submodules
        			gchar * regexstr = g_strjoin("", "^", regexpackage, "\\.(\\w+)", NULL);

        			GRegex * regex = g_regex_new(regexstr, (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
        			GMatchInfo * matchinfo;

        			g_strfreev(tmpsplit);
        			g_free(regexpackage);
        			g_free(regexstr);

        			if (g_regex_match(regex, lm->type->package, (GRegexMatchFlags) 0, &matchinfo)) {
        				if (g_match_info_get_match_count(matchinfo) == 2) {
        					gchar * fullsubpackage = g_match_info_fetch(matchinfo, 0);
        					gchar * subpackage = g_match_info_fetch(matchinfo, 1);

        					// was it already in the file?
        					if (!g_hash_table_lookup(initlua_requires_subpack, fullsubpackage)) {
        						// XXX fprintf(stderr, "> [1] inserting: %s\n", fullsubpackage);
        						g_hash_table_insert(initlua_requires_subpack, g_strdup(fullsubpackage), g_strdup(fullsubpackage));
        						fprintf(init_lua_fp, "M.%s = require('%s') -- subpackage\n", subpackage, fullsubpackage);
        					}
        				}
        			}

        			g_match_info_free(matchinfo);
        			g_regex_unref(regex);
        		}
        	}
        }

        if (!lcm_needs_generation(lcm, ls->lcmfile, path))
            continue;

        FILE *f = fopen(path, "w");
        if (f==NULL) return -1;

        fprintf(f, "--[[\n"
        		"LCM type definitions\n"
        		"This file automatically generated by lcm.\n"
        		"DO NOT MODIFY BY HAND!!!!\n"
        		"--]]\n"
        		"\n"
        		"local lcm = require('lcm')\n\n");

        emit_lua_dependencies (lcm, f, ls);

        // XXX added this...
        emit_lua_locals(lcm, f, ls);
        emit_lua_buffer_helper(lcm, f, ls);

        // XXX step 3, start making the object
        emit(0, "local %s = {}", ls->structname->shortname);
        emit(0, "%s.__index = %s", ls->structname->shortname, ls->structname->shortname);
        emit(0, "");

        // CONSTANTS
        for (unsigned int cn = 0; cn < g_ptr_array_size(ls->constants); cn++) {
            lcm_constant_t *lc = (lcm_constant_t *) g_ptr_array_index(ls->constants, cn);
            assert(lcm_is_legal_const_type(lc->lctypename));
            emit(1, "%s.%s = %s", ls->structname->shortname,
            		lc->membername, lc->val_str);
        }
        if (g_ptr_array_size(ls->constants) > 0)
            emit(0, "");

        // NAMES
        emit(0, "%s.name = '%s'", ls->structname->shortname, ls->structname->lctypename);
        emit(0, "%s.packagename = '%s'", ls->structname->shortname, ls->structname->package);
        emit(0, "%s.shortname = '%s'", ls->structname->shortname, ls->structname->shortname);
        emit(0, "");

        emit_lua_new (lcm, f, ls);
        emit_lua_fingerprint (lcm, f, ls);
        emit_lua_encode (lcm, f, ls);
        emit_lua_encode_one (lcm, f, ls);
        emit_lua_decode (lcm, f, ls);
        emit_lua_decode_one (lcm, f, ls);

        emit(0, "return %s", ls->structname->shortname);
        emit(0, "");

        fclose (f);
    }

    if(init_lua_fp){
    	fprintf(init_lua_fp, "\nreturn M\n\n");
        fclose(init_lua_fp);
    }

    g_hash_table_destroy(initlua_requires);
    return 0;
}
Esempio n. 7
0
static int load_version_data(struct idevicerestore_client_t* client)
{
	if (!client) {
		return -1;
	}

	struct stat fst;
	int cached = 0;

	char version_xml[1024];

	if (client->cache_dir) {
		if (stat(client->cache_dir, &fst) < 0) {
			mkdir_with_parents(client->cache_dir, 0755);
		}
		strcpy(version_xml, client->cache_dir);
		strcat(version_xml, "/");
		strcat(version_xml, VERSION_XML);
	} else {
		strcpy(version_xml, VERSION_XML);
	}

	if ((stat(version_xml, &fst) < 0) || ((time(NULL)-86400) > fst.st_mtime)) {
		char version_xml_tmp[1024];
		strcpy(version_xml_tmp, version_xml);
		strcat(version_xml_tmp, ".tmp");

		if (download_to_file("http://itunes.apple.com/check/version",  version_xml_tmp, 0) == 0) {
			remove(version_xml);
			if (rename(version_xml_tmp, version_xml) < 0) {
				error("ERROR: Could not update '%s'\n", version_xml);
			} else {
				info("NOTE: Updated version data.\n");
			}
		}
	} else {
		cached = 1;
	}

	char *verbuf = NULL;
	size_t verlen = 0;
	read_file(version_xml, (void**)&verbuf, &verlen);

	if (!verbuf) {
		error("ERROR: Could not load '%s'\n", version_xml);
		return -1;
	}

	client->version_data = NULL;
	plist_from_xml(verbuf, verlen, &client->version_data);
	free(verbuf);

	if (!client->version_data) {
		error("ERROR: Cannot parse plist data from '%s'.\n", version_xml);
		return -1;
	}

	if (cached) {
		info("NOTE: using cached version data\n");
	}

	return 0;
}
Esempio n. 8
0
int idevicerestore_start(struct idevicerestore_client_t* client)
{
	int tss_enabled = 0;
	int result = 0;

	if (!client) {
		return -1;
	}

	if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
		error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
		return -1;
	}

	if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
		error("ERROR: no ipsw file given\n");
		return -1;
	}

	if (client->flags & FLAG_DEBUG) {
		idevice_set_debug_level(1);
		irecv_set_debug_level(1);
		idevicerestore_debug = 1;
	}

	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0);

	// update version data (from cache, or apple if too old)
	load_version_data(client);

	// check which mode the device is currently in so we know where to start
	if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) {
		error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
		return -1;
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1);
	info("Found device in %s mode\n", client->mode->string);

	if (client->mode->index == MODE_WTF) {
		unsigned int cpid = 0;

		if (dfu_client_new(client) != 0) {
			error("ERROR: Could not open device in WTF mode\n");
			return -1;
		}
		if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) { 
			error("ERROR: Could not get CPID for WTF mode device\n");
			dfu_client_free(client);
			return -1;
		}

		char wtfname[256];
		sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
		unsigned char* wtftmp = NULL;
		unsigned int wtfsize = 0;

		// Prefer to get WTF file from the restore IPSW
		ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize);
		if (!wtftmp) {
			// Download WTF IPSW
			char* s_wtfurl = NULL;
			plist_t wtfurl = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", "5", "RecoverySoftwareVersions", "WTF", "304218112", "5", "FirmwareURL");
			if (wtfurl && (plist_get_node_type(wtfurl) == PLIST_STRING)) {
				plist_get_string_val(wtfurl, &s_wtfurl);
			}
			if (!s_wtfurl) {
				info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
				s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
			}

			// make a local file name
			char* fnpart = strrchr(s_wtfurl, '/');
			if (!fnpart) {
				fnpart = "x12220000_5_Recovery.ipsw";
			} else {
				fnpart++;
			}
			struct stat fst;
			char wtfipsw[1024];
			if (client->cache_dir) {
				if (stat(client->cache_dir, &fst) < 0) {
					mkdir_with_parents(client->cache_dir, 0755);
				}
				strcpy(wtfipsw, client->cache_dir);
				strcat(wtfipsw, "/");
				strcat(wtfipsw, fnpart);
			} else {
				strcpy(wtfipsw, fnpart);
			}
			if (stat(wtfipsw, &fst) != 0) {
				download_to_file(s_wtfurl, wtfipsw, 0);
			}

			ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize);
			if (!wtftmp) {
				error("ERROR: Could not extract WTF\n");
			}
		}

		if (wtftmp) {
			if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) {
				error("ERROR: Could not send WTF...\n");
			}
		}
		dfu_client_free(client);

		sleep(1);

		free(wtftmp);
		client->mode = &idevicerestore_modes[MODE_DFU];
	}

	// discover the device type
	if (check_product_type(client) == NULL || client->device == NULL) {
		error("ERROR: Unable to discover device type\n");
		return -1;
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2);
	info("Identified device as %s\n", client->device->product_type);

	if ((client->flags & FLAG_PWN) && (client->mode->index != MODE_DFU)) {
		error("ERROR: you need to put your device into DFU mode to pwn it.\n");
		return -1;
	}

	if (client->flags & FLAG_PWN) {
		recovery_client_free(client);

		info("connecting to DFU\n");
		if (dfu_client_new(client) < 0) {
			return -1;
		}
		info("exploiting with limera1n...\n");
		// TODO: check for non-limera1n device and fail
		if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
			error("ERROR: limera1n exploit failed\n");
			dfu_client_free(client);
			return -1;
		}
		dfu_client_free(client);
		info("Device should be in pwned DFU state now.\n");

		return 0;
	}

	if (client->flags & FLAG_LATEST) {
		char* ipsw = NULL;
		int res = ipsw_download_latest_fw(client->version_data, client->device->product_type, "cache", &ipsw);
		if (res != 0) {
			if (ipsw) {
				free(ipsw);
			}
			return res;
		} else {
			client->ipsw = ipsw;
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6);

	if (client->flags & FLAG_NOACTION) {
		return 0;
	}

	if (client->mode->index == MODE_RESTORE) {
		if (restore_reboot(client) < 0) {
			error("ERROR: Unable to exit restore mode\n");
			return -2;
		}

		// we need to refresh the current mode again
		check_mode(client);
		info("Found device in %s mode\n", client->mode->string);
	}

	// verify if ipsw file exists
	if (access(client->ipsw, F_OK) < 0) {
		error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
		return -1;
	}

	// extract buildmanifest
	plist_t buildmanifest = NULL;
	if (client->flags & FLAG_CUSTOM) {
		info("Extracting Restore.plist from IPSW\n");
		if (ipsw_extract_restore_plist(client->ipsw, &buildmanifest) < 0) {
			error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw);
			return -1;
		}
	} else {
		info("Extracting BuildManifest from IPSW\n");
		if (ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &tss_enabled) < 0) {
			error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
			return -1;
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8);

	/* check if device type is supported by the given build manifest */
	if (build_manifest_check_compatibility(buildmanifest, client->device->product_type) < 0) {
		error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
		return -1;
	}

	/* print iOS information from the manifest */
	build_manifest_get_version_information(buildmanifest, client);

	info("Product Version: %s\n", client->version);
	info("Product Build: %s Major: %d\n", client->build, client->build_major);

	if (client->flags & FLAG_CUSTOM) {
		/* prevent signing custom firmware */
		tss_enabled = 0;
		info("Custom firmware requested. Disabled TSS request.\n");
	}

	// choose whether this is an upgrade or a restore (default to upgrade)
	client->tss = NULL;
	plist_t build_identity = NULL;
	if (client->flags & FLAG_CUSTOM) {
		build_identity = plist_new_dict();
		{
			plist_t node;
			plist_t comp;
			plist_t inf;
			plist_t manifest;

			char tmpstr[256];
			char p_all_flash[128];
			char lcmodel[8];
			strcpy(lcmodel, client->device->hardware_model);
			int x = 0;
			while (lcmodel[x]) {
				lcmodel[x] = tolower(lcmodel[x]);
				x++;
			}

			sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
			strcpy(tmpstr, p_all_flash);
			strcat(tmpstr, "/manifest");

			// get all_flash file manifest
			char *files[16];
			char *fmanifest = NULL;
			uint32_t msize = 0;
			if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) {
				error("ERROR: could not extract %s from IPSW\n", tmpstr);
				return -1;
			}

			char *tok = strtok(fmanifest, "\r\n");
			int fc = 0;
			while (tok) {
				files[fc++] = strdup(tok);
				if (fc >= 16) {
					break;
				}
				tok = strtok(NULL, "\r\n");
			}
			free(fmanifest);

			manifest = plist_new_dict();

			for (x = 0; x < fc; x++) {
				inf = plist_new_dict();
				strcpy(tmpstr, p_all_flash);
				strcat(tmpstr, "/");
				strcat(tmpstr, files[x]);
				plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", inf);
				const char* compname = get_component_name(files[x]);
				if (compname) {
					plist_dict_insert_item(manifest, compname, comp);
					if (!strncmp(files[x], "DeviceTree", 10)) {
						plist_dict_insert_item(manifest, "RestoreDeviceTree", plist_copy(comp));
					}
				} else {
					error("WARNING: unhandled component %s\n", files[x]);
					plist_free(comp);
				}
				free(files[x]);
				files[x] = NULL;
			}

			// add iBSS
			sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", inf);
			plist_dict_insert_item(manifest, "iBSS", comp);

			// add iBEC
			sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", inf);
			plist_dict_insert_item(manifest, "iBEC", comp);

			// add kernel cache
			plist_t kdict = NULL;

			node = plist_dict_get_item(buildmanifest, "KernelCachesByTarget");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				char tt[4];
				strncpy(tt, lcmodel, 3);
				tt[3] = 0;
				kdict = plist_dict_get_item(node, tt);
			} else {
				// Populated in older iOS IPSWs
				kdict = plist_dict_get_item(buildmanifest, "RestoreKernelCaches");
			}
			if (kdict && (plist_get_node_type(kdict) == PLIST_DICT)) {
				plist_t kc = plist_dict_get_item(kdict, "Release");
				if (kc && (plist_get_node_type(kc) == PLIST_STRING)) {
					inf = plist_new_dict();
					plist_dict_insert_item(inf, "Path", plist_copy(kc));
					comp = plist_new_dict();
					plist_dict_insert_item(comp, "Info", inf);
					plist_dict_insert_item(manifest, "KernelCache", comp);
					plist_dict_insert_item(manifest, "RestoreKernelCache", plist_copy(comp));
				}
			}

			// add ramdisk
			node = plist_dict_get_item(buildmanifest, "RestoreRamDisks");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				plist_t rd = plist_dict_get_item(node, (client->flags & FLAG_ERASE) ? "User" : "Update");
				// if no "Update" ram disk entry is found try "User" ram disk instead
				if (!rd && !(client->flags & FLAG_ERASE)) {
					rd = plist_dict_get_item(node, "User");
					// also, set the ERASE flag since we actually change the restore variant
					client->flags |= FLAG_ERASE;
				}
				if (rd && (plist_get_node_type(rd) == PLIST_STRING)) {
					inf = plist_new_dict();
					plist_dict_insert_item(inf, "Path", plist_copy(rd));
					comp = plist_new_dict();
					plist_dict_insert_item(comp, "Info", inf);
					plist_dict_insert_item(manifest, "RestoreRamDisk", comp);
				}
			}

			// add OS filesystem
			node = plist_dict_get_item(buildmanifest, "SystemRestoreImages");
			if (!node) {
				error("ERROR: missing SystemRestoreImages in Restore.plist\n");
			}
			plist_t os = plist_dict_get_item(node, "User");
			if (!os) {
				error("ERROR: missing filesystem in Restore.plist\n");
			} else {
				inf = plist_new_dict();
				plist_dict_insert_item(inf, "Path", plist_copy(os));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", inf);
				plist_dict_insert_item(manifest, "OS", comp);
			}

			// add info
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update"));
			plist_dict_insert_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)"));
			plist_dict_insert_item(build_identity, "Info", inf);

			// finally add manifest
			plist_dict_insert_item(build_identity, "Manifest", manifest);
		}
	} else if (client->flags & FLAG_ERASE) {
		build_identity = build_manifest_get_build_identity(buildmanifest, 0);
		if (build_identity == NULL) {
			error("ERROR: Unable to find any build identities\n");
			plist_free(buildmanifest);
			return -1;
		}
	} else {
		// loop through all build identities in the build manifest
		// and list the valid ones
		int i = 0;
		int valid_builds = 0;
		int build_count = build_manifest_get_identity_count(buildmanifest);
		for (i = 0; i < build_count; i++) {
			build_identity = build_manifest_get_build_identity(buildmanifest, i);
			valid_builds++;
		}
	}

	/* print information about current build identity */
	build_identity_print_information(build_identity);

	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0);
	/* retrieve shsh blobs if required */
	if (tss_enabled) {
		debug("Getting device's ECID for TSS request\n");
		/* fetch the device's ECID for the TSS request */
		if (get_ecid(client, &client->ecid) < 0) {
			error("ERROR: Unable to find device ECID\n");
			return -1;
		}
		info("Found ECID " FMT_qu "\n", (long long unsigned int)client->ecid);

		if (client->build_major > 8) {
			unsigned char* nonce = NULL;
			int nonce_size = 0;
			int nonce_changed = 0;
			if (get_nonce(client, &nonce, &nonce_size) < 0) {
				/* the first nonce request with older firmware releases can fail and it's OK */
				info("NOTE: Unable to get nonce from device\n");
			}

			if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
				nonce_changed = 1;
				if (client->nonce) {
					free(client->nonce);
				}
				client->nonce = nonce;
				client->nonce_size = nonce_size;
			} else {
				free(nonce);
			}
		}

		if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
			error("ERROR: Unable to get SHSH blobs for this device\n");
			return -1;
		}
	}

	if (client->flags & FLAG_SHSHONLY) {
		if (!tss_enabled) {
			info("This device does not require a TSS record");
			return 0;
		}
		if (!client->tss) {
			error("ERROR: could not fetch TSS record");
			plist_free(buildmanifest);
			return -1;
		} else {
			char *bin = NULL;
			uint32_t blen = 0;
			plist_to_bin(client->tss, &bin, &blen);
			if (bin) {
				char zfn[1024];
				if (client->cache_dir) {
					strcpy(zfn, client->cache_dir);
					strcat(zfn, "/shsh");
				} else {
					strcpy(zfn, "shsh");
				}
				mkdir_with_parents(zfn, 0755);
				sprintf(zfn+strlen(zfn), "/" FMT_qu "-%s-%s.shsh", (long long int)client->ecid, client->device->product_type, client->version);
				struct stat fst;
				if (stat(zfn, &fst) != 0) {
					gzFile zf = gzopen(zfn, "wb");
					gzwrite(zf, bin, blen);
					gzclose(zf);
					info("SHSH saved to '%s'\n", zfn);
				} else {
					info("SHSH '%s' already present.\n", zfn);
				}
				free(bin);
			} else {
				error("ERROR: could not get TSS record data\n");
			}
			plist_free(client->tss);
			plist_free(buildmanifest);
			return 0;
		}
	}

	/* verify if we have tss records if required */
	if ((tss_enabled) && (client->tss == NULL)) {
		error("ERROR: Unable to proceed without a TSS record.\n");
		plist_free(buildmanifest);
		return -1;
	}

	if ((tss_enabled) && client->tss) {
		/* fix empty dicts */
		fixup_tss(client->tss);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.1);

	// if the device is in normal mode, place device into recovery mode
	if (client->mode->index == MODE_NORMAL) {
		info("Entering recovery mode...\n");
		if (normal_enter_recovery(client) < 0) {
			error("ERROR: Unable to place device into recovery mode from %s mode\n", client->mode->string);
			if (client->tss)
				plist_free(client->tss);
			plist_free(buildmanifest);
			return -5;
		}
	}

	// Get filesystem name from build identity
	char* fsname = NULL;
	if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) {
		error("ERROR: Unable get path for filesystem component\n");
		return -1;
	}

	// check if we already have an extracted filesystem
	int delete_fs = 0;
	char* filesystem = NULL;
	struct stat st;
	memset(&st, '\0', sizeof(struct stat));
	char tmpf[1024];
	if (client->cache_dir) {
		if (stat(client->cache_dir, &st) < 0) {
			mkdir_with_parents(client->cache_dir, 0755);
		}
		strcpy(tmpf, client->cache_dir);
		strcat(tmpf, "/");
		char *ipswtmp = strdup(client->ipsw);
		strcat(tmpf, basename(ipswtmp));
		free(ipswtmp);
	} else {
		strcpy(tmpf, client->ipsw);
	}
	char* p = strrchr((const char*)tmpf, '.');
	if (p) {
		*p = '\0';
	}

	if (stat(tmpf, &st) < 0) {
		__mkdir(tmpf, 0755);
	}
	strcat(tmpf, "/");
	strcat(tmpf, fsname);

	memset(&st, '\0', sizeof(struct stat));
	if (stat(tmpf, &st) == 0) {
		off_t fssize = 0;
		ipsw_get_file_size(client->ipsw, fsname, &fssize);
		if ((fssize > 0) && (st.st_size == fssize)) {
			info("Using cached filesystem from '%s'\n", tmpf);
			filesystem = strdup(tmpf);
		}
	}

	if (!filesystem) {
		char extfn[1024];
		strcpy(extfn, tmpf);
		strcat(extfn, ".extract");
		char lockfn[1024];
		strcpy(lockfn, tmpf);
		strcat(lockfn, ".lock");
		lock_info_t li;

		lock_file(lockfn, &li);
		FILE* extf = NULL;
		if (access(extfn, F_OK) != 0) {
			extf = fopen(extfn, "w");
		}
		unlock_file(&li);
		if (!extf) {
			// use temp filename
			filesystem = tempnam(NULL, "ipsw_");
			if (!filesystem) {
				error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname);
				filesystem = strdup(fsname);
			}
			delete_fs = 1;
		} else {
			// use <fsname>.extract as filename
			filesystem = strdup(extfn);
			fclose(extf);
		}
		remove(lockfn);

		// Extract filesystem from IPSW
		info("Extracting filesystem from IPSW\n");
		if (ipsw_extract_to_file(client->ipsw, fsname, filesystem) < 0) {
			error("ERROR: Unable to extract filesystem from IPSW\n");
			if (client->tss)
				plist_free(client->tss);
			plist_free(buildmanifest);
			return -1;
		}

		if (strstr(filesystem, ".extract")) {
			// rename <fsname>.extract to <fsname>
			rename(filesystem, tmpf);
			free(filesystem);
			filesystem = strdup(tmpf); 
		}
	}

	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3);

	// if the device is in DFU mode, place device into recovery mode
	if (client->mode->index == MODE_DFU) {
		recovery_client_free(client);
		if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) {
			info("connecting to DFU\n");
			if (dfu_client_new(client) < 0) {
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			info("exploiting with limera1n\n");
			// TODO: check for non-limera1n device and fail
			if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
				error("ERROR: limera1n exploit failed\n");
				dfu_client_free(client);
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			dfu_client_free(client);
			info("exploited\n");
		}
		if (dfu_enter_recovery(client, build_identity) < 0) {
			error("ERROR: Unable to place device into recovery mode from %s mode\n", client->mode->string);
			plist_free(buildmanifest);
			if (client->tss)
				plist_free(client->tss);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
	}

	if (client->mode->index == MODE_DFU) {
		client->mode = &idevicerestore_modes[MODE_RECOVERY];
	} else {
		if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) {
			/* send ApTicket */
			if (recovery_send_ticket(client) < 0) {
				error("WARNING: Unable to send APTicket\n");
			}
		}

		/* now we load the iBEC */
		if (recovery_send_ibec(client, build_identity) < 0) {
			error("ERROR: Unable to send iBEC\n");
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
		recovery_client_free(client);
	
		/* this must be long enough to allow the device to run the iBEC */
		/* FIXME: Probably better to detect if the device is back then */
		sleep(7);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5);

	if (client->build_major > 8) {
		// we need another tss request with nonce.
		unsigned char* nonce = NULL;
		int nonce_size = 0;
		int nonce_changed = 0;
		if (get_nonce(client, &nonce, &nonce_size) < 0) {
			error("ERROR: Unable to get nonce from device!\n");
			recovery_send_reset(client);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}

		if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
			nonce_changed = 1;
			if (client->nonce) {
				free(client->nonce);
			}
			client->nonce = nonce;
			client->nonce_size = nonce_size;
		} else {
			free(nonce);
		}

		if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
			// Welcome iOS5. We have to re-request the TSS with our nonce.
			plist_free(client->tss);
			if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
				error("ERROR: Unable to get SHSH blobs for this device\n");
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			if (!client->tss) {
				error("ERROR: can't continue without TSS\n");
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			fixup_tss(client->tss);
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7);

	// now finally do the magic to put the device into restore mode
	if (client->mode->index == MODE_RECOVERY) {
		if (client->srnm == NULL) {
			error("ERROR: could not retrieve device serial number. Can't continue.\n");
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -1;
		}
		if (recovery_enter_restore(client, build_identity) < 0) {
			error("ERROR: Unable to place device into restore mode\n");
			plist_free(buildmanifest);
			if (client->tss)
				plist_free(client->tss);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
		recovery_client_free(client);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.9);

	// device is finally in restore mode, let's do this
	if (client->mode->index == MODE_RESTORE) {
		info("About to restore device... \n");
		result = restore_device(client, build_identity, filesystem);
		if (result < 0) {
			error("ERROR: Unable to restore device\n");
			if (delete_fs && filesystem)
				unlink(filesystem);
			return result;
		}
	}

	info("Cleaning up...\n");
	if (delete_fs && filesystem)
		unlink(filesystem);

	/* special handling of AppleTVs */
	if (strncmp(client->device->product_type, "AppleTV", 7) == 0) {
		if (recovery_client_new(client) == 0) {
			if (recovery_set_autoboot(client, 1) == 0) {
				recovery_send_reset(client);
			} else {
				error("Setting auto-boot failed?!\n");
			}
		} else {
			error("Could not connect to device in recovery mode.\n");
		}
	}

	info("DONE\n");

	if (result == 0) {
		idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0);
	}

	return result;
}
Esempio n. 9
0
bool _vmnetfs_ll_modified_set_size(struct vmnetfs_image *img,
        uint64_t current_size, uint64_t new_size, GError **err)
{
    /* If we're truncating the new last chunk, it must be in the modified
       cache to ensure that subsequent expansions don't reveal the truncated
       part. */
    g_assert(new_size > current_size ||
            new_size % img->chunk_size == 0 ||
            _vmnetfs_bit_test(img->modified_map, new_size / img->chunk_size));

    uint64_t chunk;
    uint64_t current_chunks;
    uint64_t new_chunks;
    char *dir;
    char *file;
    bool ret;
    int fd;

    current_chunks = (current_size + img->chunk_size - 1) / img->chunk_size;
    new_chunks = (new_size + img->chunk_size - 1) / img->chunk_size;

    if (new_size > current_size) {
        for (chunk = current_chunks; chunk < new_chunks; chunk++) {
            dir = get_dir(img, chunk);
            file = get_file(img, chunk);

            ret = mkdir_with_parents(dir, err);
            if (!ret) {
                goto out;
            }
            fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
            if (fd == -1) {
                g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errno),
                        "Couldn't open to write new modified %s: %s", file, strerror(errno));
                goto out;
            }
            if (ftruncate(fd, img->chunk_size)) {
                goto out;
            }
            close(fd);
            g_free(dir);
            g_free(file);

            _vmnetfs_u64_stat_increment(img->chunks_modified, 1);
            _vmnetfs_u64_stat_increment(img->chunks_modified_not_uploaded, 1);
        }
    }
    else {
        /* Special case for the last chunks */
        chunk = new_chunks;
        dir = get_dir(img, chunk);
        file = get_file(img, chunk);
        if (g_file_test(file, G_FILE_TEST_EXISTS)) {
            int partial;
            /* 0 <= partial < img->chunk_size */
            partial = chunk * img->chunk_size - new_size;
            if (partial > 0) {
                int new_size = img->chunk_size - partial;
                fd = open(file, O_WRONLY, S_IRUSR | S_IWUSR);
                if (fd == -1) {
                    g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errno),
                            "Couldn't open to write partial modified %s: %s", file, strerror(errno));
                    goto out;
                }
                if (ftruncate(fd, new_size)) {
                    goto out;
                }
                if (ftruncate(fd, img->chunk_size)) {
                    goto out;
                }
                close(fd);
            }
        }
        g_free(dir);
        g_free(file);
        for (chunk = new_chunks+1; chunk < current_chunks; chunk++) {
            dir = get_dir(img, chunk);
            file = get_file(img, chunk);

            if (g_file_test(file, G_FILE_TEST_EXISTS)) {
                if (remove(file)) {
                    goto out;
                }

                // decrement stats (??)
                _vmnetfs_u64_stat_decrement(img->chunks_modified, 1);
                if (!is_uploaded(img, chunk)) {
                    _vmnetfs_u64_stat_increment(img->chunks_modified_not_uploaded, 1);
                }

            }
            g_free(dir);
            g_free(file);
        }

    }
    return true;

out:
     g_free(dir);
     g_free(file);
     return false;
}
Esempio n. 10
0
bool _vmnetfs_ll_modified_write_chunk(struct vmnetfs_image *img,
        uint64_t image_size, const void *data, uint64_t chunk,
        uint32_t offset, uint32_t length, GError **err)
{
    g_assert(_vmnetfs_bit_test(img->modified_map, chunk) ||
            (offset == 0 && length == MIN(img->chunk_size,
            img->initial_size - chunk * img->chunk_size)));
    g_assert(offset < img->chunk_size);
    g_assert(offset + length <= img->chunk_size);
    g_assert(chunk * img->chunk_size + offset + length <= image_size);

    char *dir;
    char *file;
    bool ret;
    int fd;

    dir = get_dir(img, chunk);
    file = get_file(img, chunk);

    ret = mkdir_with_parents(dir, err);
    if (!ret) {
        goto out;
    }

    fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errno),
                "Couldn't open to write modified %s: %s", file, strerror(errno));
        g_free(file);
        return false;
    }

    ret = _vmnetfs_safe_pwrite("chunk", fd, data, length, offset, err);
    close(fd);
    if (ret) {
        /* If file was not created before, it could not have been uploaded */
        if (!_vmnetfs_bit_test(img->modified_map, chunk)) {
            _vmnetfs_u64_stat_increment(img->chunks_modified, 1);
            _vmnetfs_u64_stat_increment(img->chunks_modified_not_uploaded, 1);
        }
        else {
            /* Chunk was already uploaded, so unset the uploaded bit */
            if (is_uploaded(img, chunk)) {
                void *data;
                int len;
                data = g_malloc(img->chunk_size);
                g_file_get_contents(file, &data, &len, err);
                g_assert(len == img->chunk_size);
                g_file_set_contents(file, data, len, err);
                g_free(data);
                _vmnetfs_u64_stat_increment(img->chunks_modified_not_uploaded, 1);
                _vmnetfs_bit_notify_plus_minus(img->uploaded_map, chunk, 0);
            }
        }
        _vmnetfs_bit_set(img->modified_map, chunk);
    }
    // ret = g_file_set_contents(file, data, length, err);

out:
    g_free(file);
    g_free(dir);
    return ret;
}
Esempio n. 11
0
static int
open_logfile(logger_t* logger)
{
    // maybe run the filename through strftime
    if (logger->use_strftime) {
        char new_prefix[PATH_MAX];
        time_t now = time (NULL);
        strftime(new_prefix, sizeof(new_prefix),
                logger->input_fname, localtime(&now));

        // If auto-increment is enabled and the strftime-formatted filename
        // prefix has changed, then reset the auto-increment counter.
        if(logger->auto_increment && strcmp(new_prefix, logger->fname_prefix))
            logger->next_increment_num = 0;
        strcpy(logger->fname_prefix, new_prefix);
    } else {
        strcpy(logger->fname_prefix, logger->input_fname);
    }

    if (logger->auto_increment) {
        /* Loop through possible file names until we find one that doesn't
         * already exist.  This way, we never overwrite an existing file. */
        do {
            snprintf(logger->fname, sizeof(logger->fname), "%s.%02d",
                    logger->fname_prefix, logger->next_increment_num);
            logger->next_increment_num++;
        } while(g_file_test(logger->fname, G_FILE_TEST_EXISTS));

        if (errno != ENOENT) {
            perror ("Error: checking for previous logs");
            return 1;
        }
    } else {
        strcpy(logger->fname, logger->fname_prefix);
        if (! logger->force_overwrite) {
            if (g_file_test(logger->fname, G_FILE_TEST_EXISTS))
            {
                fprintf (stderr, "Refusing to overwrite existing file \"%s\"\n",
                        logger->fname);
                return 1;
            }
        }
    }

    // create directories if needed
    char *dirpart = g_path_get_dirname (logger->fname);
    if (! g_file_test (dirpart, G_FILE_TEST_IS_DIR)) {
        mkdir_with_parents (dirpart, 0755);
    }
    g_free (dirpart);

    fprintf (stderr, "Opening log file \"%s\"\n", logger->fname);

    // open output file
    logger->log = lcm_eventlog_create(logger->fname, "w");
    if (logger->log == NULL) {
        perror ("Error: fopen failed");
        return 1;
    }
    return 0;
}
Esempio n. 12
0
static void
setup_newroot (bool unshare_pid,
               int privileged_op_socket)
{
  SetupOp *op;

  for (op = ops; op != NULL; op = op->next)
    {
      cleanup_free char *source = NULL;
      cleanup_free char *dest = NULL;
      int source_mode = 0;
      int i;

      if (op->source &&
          op->type != SETUP_MAKE_SYMLINK)
        {
          source = get_oldroot_path (op->source);
          source_mode = get_file_mode (source);
          if (source_mode < 0)
            die_with_error ("Can't get type of source %s", op->source);
        }

      if (op->dest)
        {
          dest = get_newroot_path (op->dest);
          if (mkdir_with_parents (dest, 0755, FALSE) != 0)
            die_with_error ("Can't mkdir parents for %s", op->dest);
        }

      switch (op->type) {
      case SETUP_RO_BIND_MOUNT:
      case SETUP_DEV_BIND_MOUNT:
      case SETUP_BIND_MOUNT:
        if (source_mode == S_IFDIR)
          {
            if (mkdir (dest, 0755) != 0 && errno != EEXIST)
              die_with_error ("Can't mkdir %s", op->dest);
          }
        else
          {
            if (ensure_file (dest, 0666) != 0)
              die_with_error ("Can't create file at %s", op->dest);
          }

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_BIND_MOUNT,
                       (op->type == SETUP_RO_BIND_MOUNT ? BIND_READONLY : 0) |
                       (op->type == SETUP_DEV_BIND_MOUNT ? BIND_DEVICES : 0),
                       source, dest);
        break;

      case SETUP_MOUNT_PROC:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        if (unshare_pid)
          {
            /* Our own procfs */
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_PROC_MOUNT, 0,
                           dest, NULL);
          }
        else
          {
            /* Use system procfs, as we share pid namespace anyway */
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, 0,
                           "oldroot/proc", dest);
          }

        /* There are a bunch of weird old subdirs of /proc that could potentially be
           problematic (for instance /proc/sysrq-trigger lets you shut down the machine
           if you have write access). We should not have access to these as a non-privileged
           user, but lets cover them anyway just to make sure */
        const char *cover_proc_dirs[] = { "sys", "sysrq-trigger", "irq", "bus" };
        for (i = 0; i < N_ELEMENTS (cover_proc_dirs); i++)
          {
            cleanup_free char *subdir = strconcat3 (dest, "/", cover_proc_dirs[i]);
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_READONLY,
                           subdir, subdir);
          }

        break;

      case SETUP_MOUNT_DEV:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_TMPFS_MOUNT, 0,
                       dest, NULL);

        static const char *const devnodes[] = { "null", "zero", "full", "random", "urandom", "tty" };
        for (i = 0; i < N_ELEMENTS (devnodes); i++)
          {
            cleanup_free char *node_dest = strconcat3 (dest, "/", devnodes[i]);
            cleanup_free char *node_src = strconcat ("/oldroot/dev/", devnodes[i]);
            if (create_file (node_dest, 0666, NULL) != 0)
              die_with_error ("Can't create file %s/%s", op->dest, devnodes[i]);
            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES,
                           node_src, node_dest);
          }

        static const char *const stdionodes[] = { "stdin", "stdout", "stderr" };
        for (i = 0; i < N_ELEMENTS (stdionodes); i++)
          {
            cleanup_free char *target = xasprintf ("/proc/self/fd/%d", i);
            cleanup_free char *node_dest = strconcat3 (dest, "/", stdionodes[i]);
            if (symlink (target, node_dest) < 0)
              die_with_error ("Can't create symlink %s/%s", op->dest, stdionodes[i]);
          }

        {
          cleanup_free char *pts = strconcat (dest, "/pts");
          cleanup_free char *ptmx = strconcat (dest, "/ptmx");
          cleanup_free char *shm = strconcat (dest, "/shm");

          if (mkdir (shm, 0755) == -1)
            die_with_error ("Can't create %s/shm", op->dest);

          if (mkdir (pts, 0755) == -1)
            die_with_error ("Can't create %s/devpts", op->dest);
          privileged_op (privileged_op_socket,
                         PRIV_SEP_OP_DEVPTS_MOUNT, BIND_DEVICES,
                         pts, NULL);

          if (symlink ("pts/ptmx", ptmx) != 0)
            die_with_error ("Can't make symlink at %s/ptmx", op->dest);
        }

        /* If stdout is a tty, that means the sandbox can write to the
           outside-sandbox tty. In that case we also create a /dev/console
           that points to this tty device. This should not cause any more
           access than we already have, and it makes ttyname() work in the
           sandbox. */
        if (host_tty_dev != NULL && *host_tty_dev != 0)
          {
            cleanup_free char *src_tty_dev = strconcat ("/oldroot", host_tty_dev);
            cleanup_free char *dest_console = strconcat (dest, "/console");

            if (create_file (dest_console, 0666, NULL) != 0)
              die_with_error ("creating %s/console", op->dest);

            privileged_op (privileged_op_socket,
                           PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES,
                           src_tty_dev, dest_console);
          }

        break;

      case SETUP_MOUNT_TMPFS:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_TMPFS_MOUNT, 0,
                       dest, NULL);
        break;
      case SETUP_MOUNT_MQUEUE:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        privileged_op (privileged_op_socket,
                       PRIV_SEP_OP_MQUEUE_MOUNT, 0,
                       dest, NULL);
        break;
      case SETUP_MAKE_DIR:
        if (mkdir (dest, 0755) != 0 && errno != EEXIST)
          die_with_error ("Can't mkdir %s", op->dest);

        break;

      case SETUP_MAKE_FILE:
        {
          cleanup_fd int dest_fd = -1;

          dest_fd = creat (dest, 0666);
          if (dest_fd == -1)
            die_with_error ("Can't create file %s", op->dest);

          if (copy_file_data (op->fd, dest_fd) != 0)
            die_with_error ("Can't write data to file %s", op->dest);

          close (op->fd);
        }
        break;

      case SETUP_MAKE_BIND_FILE:
        {
          cleanup_fd int dest_fd = -1;
          char tempfile[] = "/bindfileXXXXXX";

          dest_fd = mkstemp (tempfile);
          if (dest_fd == -1)
            die_with_error ("Can't create tmpfile for %s", op->dest);

          if (copy_file_data (op->fd, dest_fd) != 0)
            die_with_error ("Can't write data to file %s", op->dest);

          close (op->fd);

          if (ensure_file (dest, 0666) != 0)
            die_with_error ("Can't create file at %s", op->dest);

          privileged_op (privileged_op_socket,
                         PRIV_SEP_OP_BIND_MOUNT,
                         0, tempfile, dest);
        }
        break;

      case SETUP_MAKE_SYMLINK:
        if (symlink (op->source, dest) != 0)
          die_with_error ("Can't make symlink at %s", op->dest);
        break;

      default:
        die ("Unexpected type %d", op->type);
      }
    }
  privileged_op (privileged_op_socket,
                 PRIV_SEP_OP_DONE, 0, NULL, NULL);
}