cpp

Coverage Report

Created: 2022-08-03 12:23

/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