static bool IsCfqActive() { std::vector<std::string> items; (void)TPath("/sys/block").ReadDirectory(items); for (auto d : items) { if ( (d.find(std::string("loop")) != std::string::npos) || (d.find(std::string("ram")) != std::string::npos) ) continue; std::string data; std::vector<std::string> tokens; TError error = TPath("/sys/block/" + d + "/queue/scheduler").ReadAll(data); if (error) throw error.GetMsg(); error = SplitString(data, ' ', tokens); if (error) throw error.GetMsg(); bool cfqEnabled = false; for (auto t : tokens) { if (t == std::string("[cfq]")) cfqEnabled = true; } if (!cfqEnabled) { return false; } } return true; }
TError TClient::AcceptConnection(TContext &context, int listenFd) { struct sockaddr_un peer_addr; socklen_t peer_addr_size; TError error; peer_addr_size = sizeof(struct sockaddr_un); Fd = accept4(listenFd, (struct sockaddr *) &peer_addr, &peer_addr_size, SOCK_NONBLOCK | SOCK_CLOEXEC); if (Fd < 0) { error = TError(EError::Unknown, errno, "accept4()"); if (error.GetErrno() != EAGAIN) L_WRN() << "Cannot accept client: " << error << std::endl; return error; } error = IdentifyClient(*context.Cholder, true); if (error) { close(Fd); Fd = -1; return error; } if (Verbose) L() << "Client connected: " << *this << std::endl; return TError::Success(); }
TError TCgroup::Remove() const { struct stat st; TError error; if (Secondary()) return TError(EError::Unknown, "Cannot create secondary cgroup " + Type()); L_ACT() << "Remove cgroup " << *this << std::endl; error = Path().Rmdir(); /* workaround for bad synchronization */ if (error && error.GetErrno() == EBUSY && !Path().StatStrict(st) && st.st_nlink == 2) { for (int i = 0; i < 100; i++) { usleep(config().daemon().cgroup_remove_timeout_s() * 10000); error = Path().Rmdir(); if (!error || error.GetErrno() != EBUSY) break; } } if (error && (error.GetErrno() != ENOENT || Exists())) L_ERR() << "Cannot remove cgroup " << *this << " : " << error << std::endl; return error; }
int main(int argc, char *argv[]) { if (argc == 2 && !strcmp(argv[1], "connectivity")) return TestConnectivity(); // in case client closes pipe we are writing to in the protobuf code Signal(SIGPIPE, SIG_IGN); TLogger::DisableLog(); umask(0); if (argc >= 2) { string name(argv[1]); if (name == "-h" || name == "--help") { Usage(); return EXIT_FAILURE; } if (name == "-v" || name == "--version") { std::cout << PORTO_VERSION << " " << PORTO_REVISION << std::endl; return EXIT_FAILURE; } } try { config.Load(); test::InitUsersAndGroups(); auto nl = std::make_shared<TNl>(); TError error = nl->Connect(); if (error) throw error.GetMsg(); error = nl->OpenLinks(test::links, false); if (error) throw error.GetMsg(); test::InitKernelFeatures(); string what = ""; if (argc >= 2) what = argv[1]; if (what == "stress") return Stresstest(argc - 2, argv + 2); else return Selftest(argc - 1, argv + 1); } catch (string err) { std::cerr << "Exception: " << err << std::endl; } catch (const std::exception &exc) { std::cerr << "Exception: " << exc.what() << std::endl; } catch (...) { std::cerr << "Unknown exception" << std::endl; } return EXIT_FAILURE; };
int GroupGid(const std::string &group) { TGroup g(group); TError error = g.Load(); if (error) throw error.GetMsg(); return g.GetId(); }
int UserUid(const std::string &user) { TUser u(user); TError error = u.Load(); if (error) throw error.GetMsg(); return u.GetId(); }
int ReadPid(const std::string &path) { int pid = 0; TError error = TPath(path).ReadInt(pid); if (error) throw std::string(error.GetMsg()); return pid; }
int ReadPid(const std::string &path) { TFile f(path); int pid = 0; TError error = f.AsInt(pid); if (error) throw std::string(error.GetMsg()); return pid; }
std::string ReadLink(const std::string &path) { TPath lnk; TPath f(path); TError error = f.ReadLink(lnk); if (error) throw error.GetMsg(); return lnk.ToString(); }
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) { std::shared_ptr<TContainer> ct; struct ucred cr; socklen_t len = sizeof(cr); TError error; if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len)) return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed"); /* check that request from the same pid and container is still here */ if (!initial && Pid == cr.pid && TaskCred.Uid == cr.uid && TaskCred.Gid == cr.gid && !ClientContainer.expired()) return TError::Success(); TaskCred.Uid = cr.uid; TaskCred.Gid = cr.gid; Pid = cr.pid; error = holder.FindTaskContainer(Pid, ct); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot identify container of pid " << Pid << " : " << error << std::endl; if (error) return error; if (!ct->IsPortoEnabled()) return TError(EError::Permission, "Porto disabled in container " + ct->GetName()); ClientContainer = ct; error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64); if (error) Comm = "<unknown process>"; else Comm.resize(Comm.length() - 1); /* cut \n at the end */ if (ct->IsRoot()) { Cred.Uid = cr.uid; Cred.Gid = cr.gid; error = LoadGroups(); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot load supplementary group list" << Pid << " : " << error << std::endl; } else { /* requests from containers are executed in behalf of their owners */ Cred = ct->OwnerCred; } ReadOnlyAccess = !Cred.IsPortoUser(); return TError::Success(); }
void AsNobody(TPortoAPI &api) { TUser nobody(GetDefaultUser()); TError error = nobody.Load(); if (error) throw error.GetMsg(); TGroup nogroup(GetDefaultGroup()); error = nogroup.Load(); if (error) throw error.GetMsg(); AsUser(api, nobody, nogroup); }
void AsDaemon(TPortoAPI &api) { TUser daemonUser("daemon"); TError error = daemonUser.Load(); if (error) throw error.GetMsg(); TGroup daemonGroup("daemon"); error = daemonGroup.Load(); if (error) throw error.GetMsg(); AsUser(api, daemonUser, daemonGroup); }
void CCmdCifTest::HandleParserComplete(CParser& /*aParser*/, const TError& aError) { TInt err = aError.Error(); if (err) { iFailures++; PrintError(err, _L("%S failed at line %d"), &aError.ScriptFileName(), aError.ScriptLineNumber()); } else { if (iVerbose) { Printf(_L("Smoketest for %S completed ok.\r\n"), &iCurrentCif->Name()); } iPasses++; } TestCompleted(err); }
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) { struct ucred cr; socklen_t len = sizeof(cr); TError error; if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len)) return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed"); if (!initial && Pid == cr.pid && Cred.Uid == cr.uid && Cred.Gid == cr.gid && !ClientContainer.expired()) return TError::Success(); Cred.Uid = cr.uid; Cred.Gid = cr.gid; Pid = cr.pid; error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64); if (error) Comm = "<unknown process>"; else Comm.resize(Comm.length() - 1); /* cut \n at the end */ error = LoadGroups(); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot load supplementary group list" << Pid << " : " << error << std::endl; ReadOnlyAccess = !Cred.IsPortoUser(); std::shared_ptr<TContainer> container; error = holder.FindTaskContainer(Pid, container); if (error && error.GetErrno() != ENOENT) L_WRN() << "Cannot identify container of pid " << Pid << " : " << error << std::endl; if (error) return error; if (!container->Prop->Get<bool>(P_ENABLE_PORTO)) return TError(EError::Permission, "Porto disabled in container " + container->GetName()); ClientContainer = container; return TError::Success(); }
std::map<std::string, std::string> GetCgroups(const std::string &pid) { std::map<std::string, std::string> cgmap; TFile f("/proc/" + pid + "/cgroup"); std::vector<std::string> lines; TError error = f.AsLines(lines); if (error) throw std::string("Can't get cgroups: " + error.GetMsg()); std::vector<std::string> tokens; for (auto l : lines) { tokens.clear(); error = SplitString(l, ':', tokens, 3); if (error) throw std::string("Can't get cgroups: " + error.GetMsg()); cgmap[tokens[1]] = tokens[2]; } return cgmap; }
void BootstrapCommand(const std::string &cmd, const TPath &path, bool remove) { if (remove) (void)path.RemoveAll(); vector<string> lines; ExpectSuccess(Popen("ldd " + cmd, lines)); for (auto &line : lines) { vector<string> tokens; TError error = SplitString(line, ' ', tokens); if (error) throw error.GetMsg(); TPath from; string name; if (tokens.size() == 2) { from = StringTrim(tokens[0]); TPath p(tokens[0]); name = p.BaseName(); } else if (tokens.size() == 4) { if (tokens[2] == "") continue; from = StringTrim(tokens[2]); name = StringTrim(tokens[0]); } else { continue; } TPath dest = path / from.DirName(); if (!dest.Exists()) { error = dest.MkdirAll(0755); if (error) throw error.GetMsg(); } Expect(system(("cp " + from.ToString() + " " + dest.ToString() + "/" + name).c_str()) == 0); } Expect(system(("cp " + cmd + " " + path.ToString()).c_str()) == 0); }
void InitUsersAndGroups() { TError error; error = Nobody.Load("nobody"); if (error) throw error.GetMsg(); error = Alice.Load("porto-alice"); if (error) throw error.GetMsg(); error = Bob.Load("porto-bob"); if (error) throw error.GetMsg(); ExpectNeq(Alice.Uid, Bob.Uid); ExpectNeq(Alice.Gid, Bob.Gid); Expect(!Nobody.IsPortoUser()); Expect(Alice.IsPortoUser()); Expect(Bob.IsPortoUser()); }
std::map<std::string, std::string> GetCgroups(const std::string &pid) { std::map<std::string, std::string> cgmap; std::vector<std::string> lines; TError error = TPath("/proc/" + pid + "/cgroup").ReadLines(lines); if (error) throw std::string("Can't get cgroups: " + error.GetMsg()); std::vector<std::string> tokens; std::vector<std::string> subsys; for (auto l : lines) { tokens.clear(); error = SplitString(l, ':', tokens, 3); if (error) throw std::string("Can't get cgroups: " + error.GetMsg()); subsys.clear(); SplitString(tokens[1], ',', subsys); for (auto s : subsys) cgmap[s] = tokens[2]; } return cgmap; }
void ICmd::PrintError(const TError &error, const string &str) { if (error.GetMsg().length()) std::cerr << str << ": " << ErrorName(error.GetError()) << " (" << error.GetMsg() << ")" << std::endl; else std::cerr << str << ": " << ErrorName(error.GetError()) << std::endl; }
void TTask::Abort(const TError &error) const { TError ret = error.Serialize(Wfd); if (ret) L_ERR() << ret << std::endl; exit(EXIT_FAILURE); }
TError TTask::Start() { int ret; int pfd[2], syncfd[2]; Pid = 0; if (Env->CreateCwd) { TError error = CreateCwd(); if (error) { if (error.GetError() != EError::NoSpace) L_ERR() << "Can't create temporary cwd: " << error << std::endl; return error; } } ExitStatus = 0; ret = pipe2(pfd, O_CLOEXEC); if (ret) { TError error(EError::Unknown, errno, "pipe2(pdf)"); L_ERR() << "Can't create communication pipe for child: " << error << std::endl; return error; } Rfd = pfd[0]; Wfd = pfd[1]; // we want our child to have portod master as parent, so we // are doing double fork here (fork + clone); // we also need to know child pid so we are using pipe to send it back pid_t forkPid = fork(); if (forkPid < 0) { TError error(EError::Unknown, errno, "fork()"); L() << "Can't spawn child: " << error << std::endl; close(Rfd); close(Wfd); return error; } else if (forkPid == 0) { TError error; SetDieOnParentExit(SIGKILL); SetProcessName("portod-spawn-p"); char stack[8192]; (void)setsid(); // move to target cgroups for (auto cg : Env->LeafCgroups) { error = cg.second->Attach(getpid()); if (error) { L() << "Can't attach to cgroup: " << error << std::endl; ReportPid(-1); Abort(error); } } error = Env->ClientMntNs.SetNs(); if (error) { L() << "Can't move task to client mount namespace: " << error << std::endl; ReportPid(-1); Abort(error); } error = ReopenStdio(); if (error) { ReportPid(-1); Abort(error); } error = Env->ParentNs.Enter(); if (error) { L() << "Cannot enter namespaces: " << error << std::endl; ReportPid(-1); Abort(error); } int cloneFlags = SIGCHLD; if (Env->Isolate) cloneFlags |= CLONE_NEWPID | CLONE_NEWIPC; if (Env->NewMountNs) cloneFlags |= CLONE_NEWNS; if (!Env->Hostname.empty()) cloneFlags |= CLONE_NEWUTS; if (Env->NetCfg.NewNetNs) cloneFlags |= CLONE_NEWNET; int ret = pipe2(syncfd, O_CLOEXEC); if (ret) { TError error(EError::Unknown, errno, "pipe2(pdf)"); L() << "Can't create sync pipe for child: " << error << std::endl; ReportPid(-1); Abort(error); } WaitParentRfd = syncfd[0]; WaitParentWfd = syncfd[1]; pid_t clonePid = clone(ChildFn, stack + sizeof(stack), cloneFlags, this); close(WaitParentRfd); ReportPid(clonePid); if (clonePid < 0) { TError error(errno == ENOMEM ? EError::ResourceNotAvailable : EError::Unknown, errno, "clone()"); L() << "Can't spawn child: " << error << std::endl; Abort(error); } if (config().network().enabled()) { error = IsolateNet(clonePid); if (error) { L() << "Can't isolate child network: " << error << std::endl; Abort(error); } } int result = 0; ret = write(WaitParentWfd, &result, sizeof(result)); if (ret != sizeof(result)) { TError error(EError::Unknown, "Partial write to child sync pipe (" + std::to_string(ret) + " != " + std::to_string(result) + ")"); L() << "Can't spawn child: " << error << std::endl; Abort(error); } _exit(EXIT_SUCCESS); } close(Wfd); int status = 0; int forkResult = waitpid(forkPid, &status, 0); if (forkResult < 0) (void)kill(forkPid, SIGKILL); int n = read(Rfd, &Pid, sizeof(Pid)); if (n <= 0) { close(Rfd); return TError(EError::InvalidValue, errno, "Container couldn't start due to resource limits"); } TError error; (void)TError::Deserialize(Rfd, error); close(Rfd); if (error || status) { if (Pid > 0) { (void)kill(Pid, SIGKILL); L_ACT() << "Kill partly constructed container " << Pid << ": " << strerror(errno) << std::endl; } Pid = 0; ExitStatus = -1; if (!error) error = TError(EError::InvalidValue, errno, "Container couldn't start due to resource limits (child terminated with " + std::to_string(status) + ")"); return error; } State = Started; ClearEnv(); return TError::Success(); }
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()"); SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); int faceID = meshDS->ShapeToIndex( aShape ); SMESH_MesherHelper helper(aMesh); _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); const bool ignoreMediumNodes = _quadraticMesh; // ------------------------ // get all edges of a face // ------------------------ const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD )); TError problem; TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem ); if ( problem && !problem->IsOK() ) return error( problem ); int nbWires = wires.size(); if ( nbWires == 0 ) return error( "Problem in StdMeshers_FaceSide::GetFaceWires()"); if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments return error(COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()); // ------------------------- // Make input netgen mesh // ------------------------- Ng_Init(); netgen::Mesh * ngMesh = new netgen::Mesh (); netgen::OCCGeometry occgeo; NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh ); occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978) occgeo.fmap.Add( F ); vector< const SMDS_MeshNode* > nodeVec; problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec ); if ( problem && !problem->IsOK() ) { delete ngMesh; Ng_Exit(); return error( problem ); } // -------------------- // compute edge length // -------------------- double edgeLength = 0; if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) { int nbSegments = 0; for ( int iW = 0; iW < nbWires; ++iW ) { edgeLength += wires[ iW ]->Length(); nbSegments += wires[ iW ]->NbSegments(); } if ( nbSegments ) edgeLength /= nbSegments; } if ( _hypMaxElementArea ) { double maxArea = _hypMaxElementArea->GetMaxArea(); edgeLength = sqrt(2. * maxArea/sqrt(3.0)); } if ( edgeLength < DBL_MIN ) edgeLength = occgeo.GetBoundingBox().Diam(); //cout << " edgeLength = " << edgeLength << endl; netgen::mparam.maxh = edgeLength; netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0; //ngMesh->SetGlobalH ( edgeLength ); // ------------------------- // Generate surface mesh // ------------------------- char *optstr = 0; int startWith = MESHCONST_MESHSURFACE; int endWith = MESHCONST_OPTSURFACE; int err = 1; try { #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; #endif #ifdef NETGEN_V5 err = netgen::OCCGenerateMesh(occgeo, ngMesh,netgen::mparam, startWith, endWith); #else err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); #endif } catch (Standard_Failure& ex) { string comment = ex.DynamicType()->Name(); if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) { comment += ": "; comment += ex.GetMessageString(); } error(COMPERR_OCC_EXCEPTION, comment); } catch (NgException exc) { error( SMESH_Comment("NgException: ") << exc.What() ); } catch (...) { error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()"); } // ---------------------------------------------------- // Fill the SMESHDS with the generated nodes and faces // ---------------------------------------------------- int nbNodes = ngMesh->GetNP(); int nbFaces = ngMesh->GetNSE(); int nbInputNodes = nodeVec.size(); nodeVec.resize( nbNodes, 0 ); // add nodes for ( int i = nbInputNodes + 1; i <= nbNodes; ++i ) { const MeshPoint& ngPoint = ngMesh->Point(i); SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); nodeVec[ i-1 ] = node; } // create faces bool reverse = ( aShape.Orientation() == TopAbs_REVERSED ); for ( int i = 1; i <= nbFaces ; ++i ) { const Element2d& elem = ngMesh->SurfaceElement(i); vector<const SMDS_MeshNode*> nodes( elem.GetNP() ); for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); const SMDS_MeshNode* node = nodeVec.at(pind-1); if ( reverse ) nodes[ nodes.size()-j ] = node; else nodes[ j-1 ] = node; if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) { const PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v); } } SMDS_MeshFace* face = 0; if ( elem.GetType() == TRIG ) face = helper.AddFace(nodes[0],nodes[1],nodes[2]); else face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); Ng_Exit(); NETGENPlugin_Mesher::RemoveTmpFiles(); return !err; }