/home/andy/git/oilshell/oil/cpp/leaky_core.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // leaky_core.cc |
2 | | |
3 | | // clang-format off |
4 | | #include "mycpp/myerror.h" |
5 | | // clang-format on |
6 | | |
7 | | #include "cpp/leaky_core.h" |
8 | | |
9 | | #include <errno.h> |
10 | | #include <pwd.h> // passwd |
11 | | #include <signal.h> |
12 | | #include <sys/resource.h> // getrusage |
13 | | #include <sys/times.h> // tms / times() |
14 | | #include <sys/utsname.h> // uname |
15 | | #include <sys/wait.h> // waitpid() |
16 | | #include <time.h> // time() |
17 | | #include <unistd.h> // getuid(), environ |
18 | | |
19 | | #include "mycpp/mylib_old.h" |
20 | | |
21 | | using mylib::StrFromC; |
22 | | |
23 | | namespace pyos { |
24 | | |
25 | 0 | Tuple2<int, int> WaitPid() { |
26 | 0 | int status; |
27 | 0 | int result = ::waitpid(-1, &status, WUNTRACED); |
28 | 0 | if (result < 0) { |
29 | 0 | return Tuple2<int, int>(-1, errno); |
30 | 0 | } |
31 | 0 | return Tuple2<int, int>(result, status); |
32 | 0 | } |
33 | | |
34 | 2 | Tuple2<int, int> Read(int fd, int n, List<Str*>* chunks) { |
35 | | // TODO: Use garbage-collected APIs instead of malloc() |
36 | | |
37 | 2 | char* buf = static_cast<char*>(malloc(n)); |
38 | 2 | int length = ::read(fd, buf, n); |
39 | 2 | if (length < 0) { |
40 | 0 | free(buf); |
41 | 0 | return Tuple2<int, int>(-1, errno); |
42 | 0 | } |
43 | 2 | if (length == 0) { |
44 | 1 | free(buf); |
45 | 1 | return Tuple2<int, int>(length, 0); |
46 | 1 | } |
47 | 1 | Str* s = new Str(buf, length); |
48 | | // MYLIB_LEAKY: the buffer is now owned by the Str instance |
49 | | // free(buf); |
50 | 1 | chunks->append(s); |
51 | 1 | return Tuple2<int, int>(length, 0); |
52 | 2 | } |
53 | | |
54 | 3 | Tuple2<int, int> ReadByte(int fd) { |
55 | 3 | unsigned char buf[1]; |
56 | 3 | ssize_t n = read(fd, &buf, 1); |
57 | 3 | if (n < 0) { // read error |
58 | 0 | return Tuple2<int, int>(-1, errno); |
59 | 3 | } else if (n == 0) { // EOF |
60 | 1 | return Tuple2<int, int>(EOF_SENTINEL, 0); |
61 | 2 | } else { // return character |
62 | 2 | return Tuple2<int, int>(buf[0], 0); |
63 | 2 | } |
64 | 3 | } |
65 | | |
66 | | // for read --line |
67 | 0 | Str* ReadLine() { |
68 | 0 | assert(0); // Does this get called? |
69 | 0 | } |
70 | | |
71 | 0 | Dict<Str*, Str*>* Environ() { |
72 | 0 | auto d = new Dict<Str*, Str*>(); |
73 | |
|
74 | 0 | for (char** env = environ; *env; ++env) { |
75 | 0 | char* pair = *env; |
76 | |
|
77 | 0 | char* eq = strchr(pair, '='); |
78 | 0 | assert(eq != nullptr); // must look like KEY=value |
79 | | |
80 | 0 | int key_len = eq - pair; |
81 | 0 | char* buf = static_cast<char*>(malloc(key_len + 1)); |
82 | 0 | memcpy(buf, pair, key_len); // includes NUL terminator |
83 | 0 | buf[key_len] = '\0'; |
84 | |
|
85 | 0 | Str* key = StrFromC(buf, key_len); |
86 | |
|
87 | 0 | int len = strlen(pair); |
88 | 0 | int val_len = len - key_len - 1; |
89 | 0 | char* buf2 = static_cast<char*>(malloc(val_len + 1)); |
90 | 0 | memcpy(buf2, eq + 1, val_len); // copy starting after = |
91 | 0 | buf2[val_len] = '\0'; |
92 | |
|
93 | 0 | Str* val = StrFromC(buf2, val_len); |
94 | |
|
95 | 0 | d->set(key, val); |
96 | 0 | } |
97 | |
|
98 | 0 | return d; |
99 | 0 | } |
100 | | |
101 | 0 | int Chdir(Str* dest_dir) { |
102 | 0 | if (chdir(dest_dir->data_) == 0) { |
103 | 0 | return 0; // success |
104 | 0 | } else { |
105 | 0 | return errno; |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | 0 | Str* GetMyHomeDir() { |
110 | 0 | uid_t uid = getuid(); // always succeeds |
111 | | |
112 | | // Don't free this. (May return a pointer to a static area) |
113 | 0 | struct passwd* entry = getpwuid(uid); |
114 | 0 | if (entry == nullptr) { |
115 | 0 | return nullptr; |
116 | 0 | } |
117 | 0 | return StrFromC(entry->pw_dir); |
118 | 0 | } |
119 | | |
120 | 0 | Str* GetHomeDir(Str* user_name) { |
121 | | // Don't free this. (May return a pointer to a static area) |
122 | 0 | struct passwd* entry = getpwnam(user_name->data_); |
123 | 0 | if (entry == nullptr) { |
124 | 0 | return nullptr; |
125 | 0 | } |
126 | 0 | return StrFromC(entry->pw_dir); |
127 | 0 | } |
128 | | |
129 | 0 | Str* GetUserName(int uid) { |
130 | 0 | Str* result = kEmptyString; |
131 | |
|
132 | 0 | if (passwd* pw = getpwuid(uid)) { |
133 | 0 | result = new Str(pw->pw_name); |
134 | 0 | } else { |
135 | 0 | throw new IOError(errno); |
136 | 0 | } |
137 | | |
138 | 0 | return result; |
139 | 0 | } |
140 | | |
141 | 0 | Str* OsType() { |
142 | 0 | Str* result = kEmptyString; |
143 | |
|
144 | 0 | utsname un = {}; |
145 | 0 | if (::uname(&un) == 0) { |
146 | 0 | result = new Str(un.sysname); |
147 | 0 | } else { |
148 | 0 | throw new IOError(errno); |
149 | 0 | } |
150 | | |
151 | 0 | return result; |
152 | 0 | } |
153 | | |
154 | 0 | Tuple3<double, double, double> Time() { |
155 | 0 | rusage ru; // NOTE(Jesse): Doesn't have to be cleared to 0. The kernel |
156 | | // clears unused fields. |
157 | 0 | if (::getrusage(RUSAGE_SELF, &ru) == -1) { |
158 | 0 | throw new IOError(errno); |
159 | 0 | } |
160 | | |
161 | 0 | time_t t = ::time(nullptr); |
162 | 0 | auto result = Tuple3<double, double, double>( |
163 | 0 | (double)t, (double)ru.ru_utime.tv_sec, (double)ru.ru_stime.tv_sec); |
164 | 0 | return result; |
165 | 0 | } |
166 | | |
167 | 0 | void PrintTimes() { |
168 | 0 | tms t; |
169 | 0 | if (times(&t) == -1) { |
170 | 0 | throw new IOError(errno); |
171 | 0 | } else { |
172 | 0 | { |
173 | 0 | int user_minutes = t.tms_utime / 60; |
174 | 0 | float user_seconds = t.tms_utime % 60; |
175 | 0 | int system_minutes = t.tms_stime / 60; |
176 | 0 | float system_seconds = t.tms_stime % 60; |
177 | 0 | printf("%dm%1.3fs %dm%1.3fs", user_minutes, user_seconds, system_minutes, |
178 | 0 | system_seconds); |
179 | 0 | } |
180 | |
|
181 | 0 | { |
182 | 0 | int child_user_minutes = t.tms_cutime / 60; |
183 | 0 | float child_user_seconds = t.tms_cutime % 60; |
184 | 0 | int child_system_minutes = t.tms_cstime / 60; |
185 | 0 | float child_system_seconds = t.tms_cstime % 60; |
186 | 0 | printf("%dm%1.3fs %dm%1.3fs", child_user_minutes, child_user_seconds, |
187 | 0 | child_system_minutes, child_system_seconds); |
188 | 0 | } |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | 0 | bool InputAvailable(int fd) { |
193 | 0 | NotImplemented(); |
194 | 0 | } |
195 | | |
196 | 0 | void SignalState_AfterForkingChild() { |
197 | 0 | signal(SIGQUIT, SIG_DFL); |
198 | 0 | signal(SIGPIPE, SIG_DFL); |
199 | 0 | signal(SIGTSTP, SIG_DFL); |
200 | 0 | } |
201 | | |
202 | | } // namespace pyos |
203 | | |
204 | | namespace pyutil { |
205 | | |
206 | 0 | bool IsValidCharEscape(int c) { |
207 | 0 | if (c == '/' || c == '.' || c == '-') { |
208 | 0 | return false; |
209 | 0 | } |
210 | 0 | if (c == ' ') { // foo\ bar is idiomatic |
211 | 0 | return true; |
212 | 0 | } |
213 | 0 | return ispunct(c); |
214 | 0 | } |
215 | | |
216 | 3 | Str* ChArrayToString(List<int>* ch_array) { |
217 | 3 | int n = len(ch_array); |
218 | 3 | unsigned char* buf = static_cast<unsigned char*>(malloc(n + 1)); |
219 | 11 | for (int i = 0; i < n; ++i) { |
220 | 8 | buf[i] = ch_array->index_(i); |
221 | 8 | } |
222 | 3 | buf[n] = '\0'; |
223 | 3 | return new Str(reinterpret_cast<char*>(buf), n); |
224 | 3 | } |
225 | | |
226 | 0 | Str* _ResourceLoader::Get(Str* path) { |
227 | 0 | return new Str("TODO"); |
228 | 0 | } |
229 | | |
230 | 0 | _ResourceLoader* GetResourceLoader() { |
231 | 0 | return new _ResourceLoader(); |
232 | 0 | } |
233 | | |
234 | 0 | void CopyFile(Str* in_path, Str* out_path) { |
235 | 0 | assert(0); |
236 | 0 | } |
237 | | |
238 | 0 | Str* GetVersion(_ResourceLoader* loader) { |
239 | 0 | return new Str("TODO"); |
240 | 0 | } |
241 | | |
242 | 0 | Str* ShowAppVersion(Str* app_name, _ResourceLoader* loader) { |
243 | 0 | assert(0); |
244 | 0 | } |
245 | | |
246 | 2 | Str* BackslashEscape(Str* s, Str* meta_chars) { |
247 | 2 | int upper_bound = s->len_ * 2; |
248 | 2 | char* buf = static_cast<char*>(malloc(upper_bound)); |
249 | 2 | char* p = buf; |
250 | | |
251 | 11 | for (int i = 0; i < s->len_; ++i) { |
252 | 9 | char c = s->data_[i]; |
253 | 9 | if (memchr(meta_chars->data_, c, meta_chars->len_)) { |
254 | 3 | *p++ = '\\'; |
255 | 3 | } |
256 | 9 | *p++ = c; |
257 | 9 | } |
258 | 2 | int len = p - buf; |
259 | 2 | return new Str(buf, len); |
260 | 2 | } |
261 | | |
262 | | // Hack so e->errno will work below |
263 | | #undef errno |
264 | | |
265 | 0 | Str* strerror(_OSError* e) { |
266 | 0 | return new Str(::strerror(e->errno)); |
267 | 0 | } |
268 | | |
269 | | } // namespace pyutil |