RepoWrapper::RepoWrapper(const char* repoSchema, const std::string& configFile) { if (setenv("HHVM_RUNTIME_REPO_SCHEMA", repoSchema, 1 /* overwrite */)) { fprintf(stderr, "Could not set repo schema"); exit(EXIT_FAILURE); } printf("# Config file: %s\n", configFile.c_str()); printf("# Repo schema: %s\n", repoSchemaId().begin()); register_process_init(); initialize_repo(); hphp_thread_init(); g_context.getCheck(); IniSetting::Map ini = IniSetting::Map::object; Hdf config; if (!configFile.empty()) { Config::ParseConfigFile(configFile, ini, config); // Disable logging to suppress harmless errors about setrlimit. config["Log"]["Level"] = "None"; } RuntimeOption::Load(ini, config); RuntimeOption::RepoCommit = false; compile_file(nullptr, 0, MD5(), nullptr); repo = &Repo::get(); RuntimeOption::AlwaysUseRelativePath = false; RuntimeOption::SafeFileAccess = false; RuntimeOption::EvalAllowHhas = true; Option::WholeProgram = false; LitstrTable::init(); LitstrTable::get().setWriting(); RuntimeOption::RepoAuthoritative = true; repo->loadGlobalData(true /* allowFailure */); std::string hhasLib; auto const phpLib = get_systemlib(&hhasLib); always_assert(!hhasLib.empty() && !phpLib.empty()); auto phpUnit = compile_string(phpLib.c_str(), phpLib.size(), "systemlib.php"); addUnit(phpUnit); auto hhasUnit = compile_string(hhasLib.c_str(), hhasLib.size(), "systemlib.hhas"); addUnit(hhasUnit); SystemLib::s_inited = true; LitstrTable::get().setReading(); }
int pkg_create_repo(char *path, bool force, void (progress)(struct pkg *pkg, void *data), void *data) { FTS *fts = NULL; struct thd_data thd_data; int num_workers; size_t len; pthread_t *tids = NULL; struct pkg_dep *dep = NULL; struct pkg_category *category = NULL; struct pkg_license *license = NULL; struct pkg_option *option = NULL; struct pkg_shlib *shlib = NULL; sqlite3 *sqlite = NULL; int64_t package_id; char *errmsg = NULL; int retcode = EPKG_OK; int ret; char *repopath[2]; char repodb[MAXPATHLEN + 1]; char repopack[MAXPATHLEN + 1]; struct archive *a = NULL; struct archive_entry *ae = NULL; if (!is_dir(path)) { pkg_emit_error("%s is not a directory", path); return (EPKG_FATAL); } repopath[0] = path; repopath[1] = NULL; len = sizeof(num_workers); if (sysctlbyname("hw.ncpu", &num_workers, &len, NULL, 0) == -1) num_workers = 6; if ((fts = fts_open(repopath, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) { pkg_emit_errno("fts_open", path); retcode = EPKG_FATAL; goto cleanup; } snprintf(repodb, sizeof(repodb), "%s/repo.sqlite", path); snprintf(repopack, sizeof(repopack), "%s/repo.txz", path); if (access(repopack, F_OK) == 0) { a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_tar(a); ret = archive_read_open_filename(a, repopack, 4096); if (ret != ARCHIVE_OK) { /* if we can't unpack it it won't be useful for us */ unlink(repopack); } else { while (archive_read_next_header(a, &ae) == ARCHIVE_OK) { if (!strcmp(archive_entry_pathname(ae), "repo.sqlite")) { archive_entry_set_pathname(ae, repodb); archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS); break; } } } if (a != NULL) archive_read_finish(a); } if ((retcode = initialize_repo(repodb, force, &sqlite)) != EPKG_OK) goto cleanup; if ((retcode = initialize_prepared_statements(sqlite)) != EPKG_OK) goto cleanup; thd_data.root_path = path; thd_data.max_results = num_workers; thd_data.num_results = 0; thd_data.stop = false; thd_data.fts = fts; pthread_mutex_init(&thd_data.fts_m, NULL); STAILQ_INIT(&thd_data.results); thd_data.thd_finished = 0; pthread_mutex_init(&thd_data.results_m, NULL); pthread_cond_init(&thd_data.has_result, NULL); pthread_cond_init(&thd_data.has_room, NULL); /* Launch workers */ tids = calloc(num_workers, sizeof(pthread_t)); for (int i = 0; i < num_workers; i++) { pthread_create(&tids[i], NULL, (void *)&read_pkg_file, &thd_data); } for (;;) { struct pkg_result *r; const char *name, *version, *origin, *comment, *desc; const char *arch, *maintainer, *www, *prefix; int64_t flatsize; lic_t licenselogic; pthread_mutex_lock(&thd_data.results_m); while ((r = STAILQ_FIRST(&thd_data.results)) == NULL) { if (thd_data.thd_finished == num_workers) { break; } pthread_cond_wait(&thd_data.has_result, &thd_data.results_m); } if (r != NULL) { STAILQ_REMOVE_HEAD(&thd_data.results, next); thd_data.num_results--; pthread_cond_signal(&thd_data.has_room); } pthread_mutex_unlock(&thd_data.results_m); if (r == NULL) { break; } if (r->retcode != EPKG_OK) { continue; } /* do not add if package if already in repodb (possibly at a different pkg_path) */ if (run_prepared_statement(EXISTS, r->cksum) != SQLITE_ROW) { ERROR_SQLITE(sqlite); goto cleanup; } if (sqlite3_column_int(STMT(EXISTS), 0) > 0) { continue; } if (progress != NULL) progress(r->pkg, data); pkg_get(r->pkg, PKG_ORIGIN, &origin, PKG_NAME, &name, PKG_VERSION, &version, PKG_COMMENT, &comment, PKG_DESC, &desc, PKG_ARCH, &arch, PKG_MAINTAINER, &maintainer, PKG_WWW, &www, PKG_PREFIX, &prefix, PKG_FLATSIZE, &flatsize, PKG_LICENSE_LOGIC, &licenselogic); try_again: if ((ret = run_prepared_statement(PKG, origin, name, version, comment, desc, arch, maintainer, www, prefix, r->size, flatsize, (int64_t)licenselogic, r->cksum, r->path)) != SQLITE_DONE) { if (ret == SQLITE_CONSTRAINT) { switch(maybe_delete_conflicting(origin, version, r->path)) { case EPKG_FATAL: /* sqlite error */ ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; break; case EPKG_END: /* repo already has newer */ continue; break; default: /* conflict cleared, try again */ goto try_again; break; } } else { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } package_id = sqlite3_last_insert_rowid(sqlite); dep = NULL; while (pkg_deps(r->pkg, &dep) == EPKG_OK) { if (run_prepared_statement(DEPS, pkg_dep_origin(dep), pkg_dep_name(dep), pkg_dep_version(dep), package_id) != SQLITE_DONE) { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } category = NULL; while (pkg_categories(r->pkg, &category) == EPKG_OK) { const char *cat_name = pkg_category_name(category); ret = run_prepared_statement(CAT1, cat_name); if (ret == SQLITE_DONE) ret = run_prepared_statement(CAT2, package_id, cat_name); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } license = NULL; while (pkg_licenses(r->pkg, &license) == EPKG_OK) { const char *lic_name = pkg_license_name(license); ret = run_prepared_statement(LIC1, lic_name); if (ret == SQLITE_DONE) ret = run_prepared_statement(LIC2, package_id, lic_name); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } option = NULL; while (pkg_options(r->pkg, &option) == EPKG_OK) { if (run_prepared_statement(OPTS, pkg_option_opt(option), pkg_option_value(option), package_id) != SQLITE_DONE) { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } shlib = NULL; while (pkg_shlibs(r->pkg, &shlib) == EPKG_OK) { const char *shlib_name = pkg_shlib_name(shlib); ret = run_prepared_statement(SHLIB1, shlib_name); if (ret == SQLITE_DONE) ret = run_prepared_statement(SHLIB2, package_id, shlib_name); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite); retcode = EPKG_FATAL; goto cleanup; } } pkg_free(r->pkg); free(r); } if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK) retcode = EPKG_FATAL; cleanup: if (tids != NULL) { // Cancel running threads if (retcode != EPKG_OK) { pthread_mutex_lock(&thd_data.fts_m); thd_data.stop = true; pthread_mutex_unlock(&thd_data.fts_m); } // Join on threads to release thread IDs for (int i = 0; i < num_workers; i++) { pthread_join(tids[i], NULL); } free(tids); } if (fts != NULL) fts_close(fts); finalize_prepared_statements(); if (sqlite != NULL) sqlite3_close(sqlite); if (errmsg != NULL) sqlite3_free(errmsg); sqlite3_shutdown(); return (retcode); }
void ProcessInit() { // Initialize compiler state VM::compile_file(0, 0, MD5(), 0); extern void initialize_repo(); initialize_repo(); // Install VM's ClassInfoHook ClassInfo::SetHook(&vm_class_info_hook); // ensure that nextTx64 and tx64 are set (void)VM::Transl::Translator::Get(); Transl::TargetCache::requestInit(); Unit* nativeFuncUnit = build_native_func_unit(hhbc_ext_funcs, hhbc_ext_funcs_count); SystemLib::s_nativeFuncUnit = nativeFuncUnit; // Search for systemlib.php in the following places: // 1) ${HHVM_LIB_PATH}/systemlib.php // 2) <dirname(realpath(hhvm))>/systemlib.php (requires proc filesystem) // 3) ${HPHP_LIB}/systemlib.php // 4) <HHVM_LIB_PATH_DEFAULT>/systemlib.php // // HHVM_LIB_PATH allows a manual override at runtime. If systemlib.php // exists next to the hhvm binary, that is likely to be the next best // version to use. The realpath()-based lookup will succeed as long as the // proc filesystem exists (e.g. on Linux and some FreeBSD configurations) // and no hard links are in use for the executable. Under certain build // situations, systemlib.php will not be generated next to hhvm binary, so // ${HPHP_LIB} is checked next. Failing all of those options, the // HHVM_LIB_PATH_DEFAULT-based lookup will always succeed, assuming that the // application was built and installed correctly. String currentDir = g_vmContext->getCwd(); HPHP::Eval::PhpFile* file = NULL; #define SYSTEMLIB_PHP "/systemlib.php" #define LOOKUP_STR(s) do { \ String systemlibPath = String(s) + SYSTEMLIB_PHP; \ file = g_vmContext->lookupPhpFile(systemlibPath.get(), currentDir.data(), \ NULL); \ } while (0) #define LOOKUP_ENV(v) do { \ if (!file) { \ const char* s = getenv(#v); \ if (s && *s) { \ LOOKUP_STR(s); \ } \ } \ } while (0) #define LOOKUP_CPP(v) do { \ if (!file) { \ LOOKUP_STR(v); \ } \ } while (0) LOOKUP_ENV(HHVM_LIB_PATH); if (!file) { char hhvm_exe[PATH_MAX+1]; char hhvm_path[PATH_MAX+1]; ssize_t len = readlink("/proc/self/exe", hhvm_exe, sizeof(hhvm_exe)); if (len >= 0) { hhvm_exe[len] = '\0'; if (realpath(hhvm_exe, hhvm_path) != NULL) { char *hphp_lib = dirname(hhvm_path); LOOKUP_STR(hphp_lib); } } } LOOKUP_ENV(HPHP_LIB); #ifdef HHVM_LIB_PATH_DEFAULT LOOKUP_CPP(HHVM_LIB_PATH_DEFAULT); #endif if (!file) { // Die a horrible death. Logger::Error("Unable to find/load systemlib.php"); _exit(1); } #undef SYSTEMLIB_PHP #undef LOOKUP_STR #undef LOOKUP_ENV #undef LOOKUP_CPP SystemLib::s_phpFile = file; file->incRef(); SystemLib::s_unit = file->unit(); // Load the systemlib unit to build the Class objects SystemLib::s_unit->merge(); // load builtins SystemLib::s_nativeFuncUnit->merge(); #define INIT_SYSTEMLIB_CLASS_FIELD(cls) \ { \ Class *cls = *Unit::GetNamedEntity(s_##cls.get())->clsList(); \ ASSERT(cls); \ SystemLib::s_##cls##Class = cls; \ } // Stash a pointer to the VM Classes for stdclass, Exception, // pinitSentinel and resource INIT_SYSTEMLIB_CLASS_FIELD(stdclass); INIT_SYSTEMLIB_CLASS_FIELD(Exception); INIT_SYSTEMLIB_CLASS_FIELD(BadMethodCallException); INIT_SYSTEMLIB_CLASS_FIELD(Directory); INIT_SYSTEMLIB_CLASS_FIELD(RecursiveDirectoryIterator); INIT_SYSTEMLIB_CLASS_FIELD(SplFileInfo); INIT_SYSTEMLIB_CLASS_FIELD(SplFileObject); INIT_SYSTEMLIB_CLASS_FIELD(pinitSentinel); INIT_SYSTEMLIB_CLASS_FIELD(resource); INIT_SYSTEMLIB_CLASS_FIELD(DOMException); INIT_SYSTEMLIB_CLASS_FIELD(PDOException); INIT_SYSTEMLIB_CLASS_FIELD(SoapFault); #undef INIT_SYSTEMLIB_CLASS_FIELD // We call a special bytecode emitter function to build the native // unit which will contain all of our cppext functions and classes. // Each function and method will have a bytecode body that will thunk // to the native implementation. Unit* nativeClassUnit = build_native_class_unit(hhbc_ext_classes, hhbc_ext_class_count); SystemLib::s_nativeClassUnit = nativeClassUnit; // Load the nativelib unit to build the Class objects SystemLib::s_nativeClassUnit->merge(); // Retrieve all of the class pointers for (long long i = 0LL; i < hhbc_ext_class_count; ++i) { const HhbcExtClassInfo* info = hhbc_ext_classes + i; const StringData* name = StringData::GetStaticString(info->m_name); const NamedEntity* ne = Unit::GetNamedEntity(name); Class* cls = Unit::lookupClass(ne); ASSERT(cls); const ObjectStaticCallbacks* osc = get_object_static_callbacks(info->m_name); ASSERT(osc != NULL); *(osc->os_cls_ptr) = cls; } Stack::ValidateStackSize(); SystemLib::s_inited = true; // For debug build, run some quick unit tests at process start time if (debug) { VM::Transl::FixupMapUnitTest _; } }