cpp

Coverage Report

Created: 2022-11-10 11:34

/home/andy/git/oilshell/oil/cpp/leaky_core.cc
Line
Count
Source (jump to first uncovered line)
1
// leaky_core.cc
2
3
#include "cpp/leaky_core.h"
4
5
#include <errno.h>
6
#include <pwd.h>  // passwd
7
#include <signal.h>
8
#include <sys/resource.h>  // getrusage
9
#include <sys/times.h>     // tms / times()
10
#include <sys/utsname.h>   // uname
11
#include <sys/wait.h>      // waitpid()
12
#include <time.h>          // time()
13
#include <unistd.h>        // getuid(), environ
14
15
namespace pyos {
16
17
static SignalHandler gSignalHandler;
18
19
0
Tuple2<int, int> WaitPid() {
20
0
  int status;
21
0
  int result = ::waitpid(-1, &status, WUNTRACED);
22
0
  if (result < 0) {
23
0
    return Tuple2<int, int>(-1, errno);
24
0
  }
25
0
  return Tuple2<int, int>(result, status);
26
0
}
27
28
2
Tuple2<int, int> Read(int fd, int n, List<Str*>* chunks) {
29
2
  Str* s = OverAllocatedStr(n);  // Allocate enough for the result
30
31
2
  int length = ::read(fd, s->data(), n);
32
2
  if (length < 0) {
33
0
    return Tuple2<int, int>(-1, errno);
34
0
  }
35
2
  if (length == 0) {
36
1
    return Tuple2<int, int>(length, 0);
37
1
  }
38
39
  // Now we know how much data we got back
40
1
  s->SetObjLenFromStrLen(length);
41
1
  chunks->append(s);
42
43
1
  return Tuple2<int, int>(length, 0);
44
2
}
45
46
3
Tuple2<int, int> ReadByte(int fd) {
47
3
  unsigned char buf[1];
48
3
  ssize_t n = read(fd, &buf, 1);
49
3
  if (n < 0) {  // read error
50
0
    return Tuple2<int, int>(-1, errno);
51
3
  } else if (n == 0) {  // EOF
52
1
    return Tuple2<int, int>(EOF_SENTINEL, 0);
53
2
  } else {  // return character
54
2
    return Tuple2<int, int>(buf[0], 0);
55
2
  }
56
3
}
57
58
// for read --line
59
0
Str* ReadLine() {
60
0
  assert(0);  // Does this get called?
61
0
}
62
63
0
Dict<Str*, Str*>* Environ() {
64
0
  auto d = NewDict<Str*, Str*>();
65
66
0
  for (char** env = environ; *env; ++env) {
67
0
    char* pair = *env;
68
69
0
    char* eq = strchr(pair, '=');
70
0
    assert(eq != nullptr);  // must look like KEY=value
71
72
0
    int len = strlen(pair);
73
74
0
    int key_len = eq - pair;
75
0
    Str* key = StrFromC(pair, key_len);
76
77
0
    int val_len = len - key_len - 1;
78
0
    Str* val = StrFromC(eq + 1, val_len);
79
80
0
    d->set(key, val);
81
0
  }
82
83
0
  return d;
84
0
}
85
86
3
int Chdir(Str* dest_dir) {
87
3
  if (chdir(dest_dir->data_) == 0) {
88
2
    return 0;  // success
89
2
  } else {
90
1
    return errno;
91
1
  }
92
3
}
93
94
0
Str* GetMyHomeDir() {
95
0
  uid_t uid = getuid();  // always succeeds
96
97
  // Don't free this.  (May return a pointer to a static area)
98
0
  struct passwd* entry = getpwuid(uid);
99
0
  if (entry == nullptr) {
100
0
    return nullptr;
101
0
  }
102
0
  return StrFromC(entry->pw_dir);
103
0
}
104
105
0
Str* GetHomeDir(Str* user_name) {
106
  // Don't free this.  (May return a pointer to a static area)
107
0
  struct passwd* entry = getpwnam(user_name->data_);
108
0
  if (entry == nullptr) {
109
0
    return nullptr;
110
0
  }
111
0
  return StrFromC(entry->pw_dir);
112
0
}
113
114
0
Str* GetUserName(int uid) {
115
0
  Str* result = kEmptyString;
116
117
0
  if (passwd* pw = getpwuid(uid)) {
118
0
    result = StrFromC(pw->pw_name);
119
0
  } else {
120
0
    throw Alloc<IOError>(errno);
121
0
  }
122
123
0
  return result;
124
0
}
125
126
0
Str* OsType() {
127
0
  Str* result = kEmptyString;
128
129
0
  utsname un = {};
130
0
  if (::uname(&un) == 0) {
131
0
    result = StrFromC(un.sysname);
132
0
  } else {
133
0
    throw Alloc<IOError>(errno);
134
0
  }
135
136
0
  return result;
137
0
}
138
139
0
Tuple3<double, double, double> Time() {
140
0
  rusage ru;  // NOTE(Jesse): Doesn't have to be cleared to 0.  The kernel
141
              // clears unused fields.
142
0
  if (::getrusage(RUSAGE_SELF, &ru) == -1) {
143
0
    throw Alloc<IOError>(errno);
144
0
  }
145
146
0
  time_t t = ::time(nullptr);
147
0
  auto result = Tuple3<double, double, double>(
148
0
      static_cast<double>(t), static_cast<double>(ru.ru_utime.tv_sec),
149
0
      static_cast<double>(ru.ru_stime.tv_sec));
150
0
  return result;
151
0
}
152
153
0
void PrintTimes() {
154
0
  tms t;
155
0
  if (times(&t) == -1) {
156
0
    throw Alloc<IOError>(errno);
157
0
  } else {
158
0
    {
159
0
      int user_minutes = t.tms_utime / 60;
160
0
      float user_seconds = t.tms_utime % 60;
161
0
      int system_minutes = t.tms_stime / 60;
162
0
      float system_seconds = t.tms_stime % 60;
163
0
      printf("%dm%1.3fs %dm%1.3fs\n", user_minutes, user_seconds,
164
0
             system_minutes, system_seconds);
165
0
    }
166
167
0
    {
168
0
      int child_user_minutes = t.tms_cutime / 60;
169
0
      float child_user_seconds = t.tms_cutime % 60;
170
0
      int child_system_minutes = t.tms_cstime / 60;
171
0
      float child_system_seconds = t.tms_cstime % 60;
172
0
      printf("%dm%1.3fs %dm%1.3fs", child_user_minutes, child_user_seconds,
173
0
             child_system_minutes, child_system_seconds);
174
0
    }
175
0
  }
176
0
}
177
178
0
bool InputAvailable(int fd) {
179
0
  NotImplemented();
180
0
}
181
182
SignalHandler::SignalHandler()
183
1
    : signal_queue_(), last_sig_num_(0), sigwinch_num_(UNTRAPPED_SIGWINCH) {
184
1
}
185
186
0
void SignalHandler::Update(int sig_num) {
187
0
  assert(signal_queue_ != nullptr);
188
0
  assert(signal_queue_->len_ < signal_queue_->capacity_);
189
0
  signal_queue_->append(sig_num);
190
0
  if (sig_num == SIGWINCH) {
191
0
    sig_num = sigwinch_num_;
192
0
  }
193
0
  last_sig_num_ = sig_num;
194
0
}
195
196
0
static List<int>* AllocSignalQueue() {
197
0
  List<int>* ret = NewList<int>();
198
0
  ret->reserve(kMaxSignalsInFlight);
199
0
  return ret;
200
0
}
201
202
0
List<int>* SignalHandler::TakeSignalQueue() {
203
0
  List<int>* new_queue = AllocSignalQueue();
204
0
  List<int>* ret = signal_queue_;
205
0
  signal_queue_ = new_queue;
206
0
  return ret;
207
0
}
208
209
0
void Sigaction(int sig_num, sighandler_t handler) {
210
0
  struct sigaction act = {};
211
0
  act.sa_handler = handler;
212
0
  assert(sigaction(sig_num, &act, nullptr) == 0);
213
0
}
214
215
0
static void signal_handler(int sig_num) {
216
0
  gSignalHandler.Update(sig_num);
217
0
}
218
219
0
void RegisterSignalInterest(int sig_num) {
220
0
  struct sigaction act = {};
221
0
  act.sa_handler = signal_handler;
222
0
  assert(sigaction(sig_num, &act, nullptr) == 0);
223
0
}
224
225
0
List<int>* TakeSignalQueue() {
226
0
  return gSignalHandler.TakeSignalQueue();
227
0
}
228
229
0
int LastSignal() {
230
0
  return gSignalHandler.last_sig_num_;
231
0
}
232
233
0
void SetSigwinchCode(int code) {
234
0
  gSignalHandler.sigwinch_num_ = code;
235
0
}
236
237
0
void InitShell() {
238
0
  gSignalHandler.signal_queue_ = AllocSignalQueue();
239
0
}
240
241
}  // namespace pyos
242
243
namespace pyutil {
244
245
0
bool IsValidCharEscape(int c) {
246
0
  if (c == '/' || c == '.' || c == '-') {
247
0
    return false;
248
0
  }
249
0
  if (c == ' ') {  // foo\ bar is idiomatic
250
0
    return true;
251
0
  }
252
0
  return ispunct(c);
253
0
}
254
255
3
Str* ChArrayToString(List<int>* ch_array) {
256
3
  int n = len(ch_array);
257
3
  Str* result = NewStr(n);
258
11
  for (int i = 0; i < n; ++i) {
259
8
    result->data_[i] = ch_array->index_(i);
260
8
  }
261
3
  result->data_[n] = '\0';
262
3
  return result;
263
3
}
264
265
0
Str* _ResourceLoader::Get(Str* path) {
266
  /* NotImplemented(); */
267
0
  return StrFromC("TODO");
268
0
}
269
270
0
_ResourceLoader* GetResourceLoader() {
271
0
  return Alloc<_ResourceLoader>();
272
0
}
273
274
0
void CopyFile(Str* in_path, Str* out_path) {
275
0
  assert(0);
276
0
}
277
278
0
Str* GetVersion(_ResourceLoader* loader) {
279
  /* NotImplemented(); */
280
0
  return StrFromC("TODO");
281
0
}
282
283
0
Str* ShowAppVersion(Str* app_name, _ResourceLoader* loader) {
284
0
  assert(0);
285
0
}
286
287
2
Str* BackslashEscape(Str* s, Str* meta_chars) {
288
2
  int upper_bound = len(s) * 2;
289
2
  Str* buf = OverAllocatedStr(upper_bound);
290
2
  char* p = buf->data_;
291
292
11
  for (int i = 0; i < len(s); ++i) {
293
9
    char c = s->data_[i];
294
9
    if (memchr(meta_chars->data_, c, len(meta_chars))) {
295
3
      *p++ = '\\';
296
3
    }
297
9
    *p++ = c;
298
9
  }
299
2
  buf->SetObjLenFromStrLen(p - buf->data_);
300
2
  return buf;
301
2
}
302
303
0
Str* strerror(IOError_OSError* e) {
304
0
  return StrFromC(::strerror(e->errno_));
305
0
}
306
307
}  // namespace pyutil