-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpms.cpp
More file actions
132 lines (109 loc) · 3.69 KB
/
Copy pathpms.cpp
File metadata and controls
132 lines (109 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <iostream>
#include <fstream>
#include <filesystem>
#include <cstdlib>
#include <vector>
#include <string>
#include <sstream>
#include <unistd.h> // geteuid()
namespace fs = std::filesystem;
// =======================================================
// Helper functions
// =======================================================
bool is_absolute_path(const std::string &path) {
return !path.empty() && path[0] == '/';
}
void require_root() {
if (geteuid() != 0) {
std::cerr << "Error: you must run this command as root (sudo/doas)." << std::endl;
exit(1);
}
}
void require_absolute(const std::string &path) {
if (!is_absolute_path(path)) {
std::cerr << "Error: package path must be an *absolute* path." << std::endl;
std::cerr << "Example: sudo pms install /home/user/test.pms" << std::endl;
exit(1);
}
}
// =======================================================
// Package metadata
// =======================================================
struct PackageInfo {
std::string name;
std::string version;
std::vector<std::string> dependencies;
};
// Reads metadata from control file in extracted dir
PackageInfo read_control(const fs::path &control_path) {
PackageInfo info;
std::ifstream f(control_path);
std::string line;
while (std::getline(f, line)) {
if (line.rfind("Name:", 0) == 0) {
info.name = line.substr(5);
} else if (line.rfind("Version:", 0) == 0) {
info.version = line.substr(8);
} else if (line.rfind("Depends:", 0) == 0) {
std::stringstream ss(line.substr(8));
std::string dep;
while (std::getline(ss, dep, ',')) {
if (!dep.empty()) info.dependencies.push_back(dep);
}
}
}
return info;
}
// =======================================================
// Install package
// =======================================================
int install_package(const std::string &pkg_path) {
require_root(); // ← MUST BE ROOT
require_absolute(pkg_path); // ← PATH MUST BE ABSOLUTE
fs::path tmp = "/tmp/pms_extract";
fs::remove_all(tmp);
fs::create_directories(tmp);
// Extract using 'ar'
std::string ar_cmd =
"cd " + tmp.string() + " && ar -x " + pkg_path;
if (system(ar_cmd.c_str()) != 0) {
std::cerr << "Error: ar failed to extract package (file may not exist)" << std::endl;
return 1;
}
// Expect data.tar
fs::path data_tar = tmp / "data.tar";
if (!fs::exists(data_tar)) {
std::cerr << "Malformed package: data.tar missing" << std::endl;
return 1;
}
// Extract data.tar
std::string tar_cmd = "tar -xf " + data_tar.string() + " -C /";
if (system(tar_cmd.c_str()) != 0) {
std::cerr << "Failed to extract data.tar" << std::endl;
return 1;
}
// Read metadata
PackageInfo info = read_control(tmp / "control");
std::cout << "Installed: " << info.name << " " << info.version << std::endl;
// Save to database
fs::create_directories("/var/lib/pms/db");
std::ofstream db("/var/lib/pms/db/" + info.name);
db << info.version << std::endl;
for (auto &dep : info.dependencies) db << dep << std::endl;
return 0;
}
// =======================================================
// Main entry
// =======================================================
int main(int argc, char **argv) {
if (argc < 3) {
std::cout << "Usage: pms install <package.pms>" << std::endl;
return 0;
}
std::string cmd = argv[1];
if (cmd == "install") {
return install_package(argv[2]);
}
std::cerr << "Unknown command" << std::endl;
return 1;
}