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; }
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; }
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; }
/// 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); }
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; }
// 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; }
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; }
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; }
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; }
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; }
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; }
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); }