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