passenger 5.3.1 → 5.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +19 -0
  3. data/build/cxx_tests.rb +3 -1
  4. data/build/support/cxx_dependency_map.rb +120 -27
  5. data/dev/configkit-schemas/index.json +15 -3
  6. data/src/agent/Core/AdminPanelConnector.h +5 -2
  7. data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +2 -0
  8. data/src/agent/Core/Config.h +2 -1
  9. data/src/agent/Core/Controller/Config.h +6 -1
  10. data/src/agent/Core/Controller/InitRequest.cpp +6 -1
  11. data/src/agent/Core/CoreMain.cpp +26 -60
  12. data/src/agent/Core/SpawningKit/DirectSpawner.h +18 -6
  13. data/src/agent/Core/SpawningKit/ErrorRenderer.h +8 -8
  14. data/src/agent/Core/SpawningKit/Handshake/Perform.h +217 -61
  15. data/src/agent/Core/SpawningKit/Handshake/Prepare.h +57 -8
  16. data/src/agent/Core/SpawningKit/Handshake/Session.h +34 -1
  17. data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +20 -4
  18. data/src/agent/Core/SpawningKit/SmartSpawner.h +90 -27
  19. data/src/agent/ExecHelper/ExecHelperMain.cpp +3 -0
  20. data/src/agent/Shared/ApiAccountUtils.h +2 -2
  21. data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +14 -4
  22. data/src/agent/Watchdog/Config.h +2 -1
  23. data/src/agent/Watchdog/WatchdogMain.cpp +38 -0
  24. data/src/apache2_module/Hooks.cpp +1 -0
  25. data/src/cxx_supportlib/ConfigKit/IN_PRACTICE.md +1 -1
  26. data/src/cxx_supportlib/ConfigKit/README.md +1 -1
  27. data/src/cxx_supportlib/Constants.h +6 -1
  28. data/src/cxx_supportlib/FileTools/FileManip.cpp +34 -2
  29. data/src/cxx_supportlib/FileTools/FileManip.h +58 -1
  30. data/src/cxx_supportlib/FileTools/PathManip.cpp +3 -2
  31. data/src/cxx_supportlib/FileTools/PathSecurityCheck.cpp +99 -0
  32. data/src/cxx_supportlib/FileTools/PathSecurityCheck.h +69 -0
  33. data/src/cxx_supportlib/Utils.cpp +37 -6
  34. data/src/cxx_supportlib/Utils.h +6 -0
  35. data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +14 -0
  36. data/src/cxx_supportlib/Utils/IOUtils.cpp +10 -18
  37. data/src/cxx_supportlib/Utils/IOUtils.h +10 -9
  38. data/src/cxx_supportlib/Utils/JsonUtils.h +12 -8
  39. data/src/cxx_supportlib/Utils/SystemMetricsCollector.h +4 -4
  40. data/src/cxx_supportlib/Utils/SystemTime.h +1 -1
  41. data/src/cxx_supportlib/WebSocketCommandReverseServer.h +3 -3
  42. data/src/cxx_supportlib/oxt/system_calls.cpp +25 -1
  43. data/src/cxx_supportlib/oxt/system_calls.hpp +3 -1
  44. data/src/helper-scripts/meteor-loader.rb +115 -28
  45. data/src/helper-scripts/rack-preloader.rb +1 -1
  46. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +4 -4
  47. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +4 -4
  48. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +0 -10
  49. data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +0 -42
  50. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +0 -6
  51. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +0 -8
  52. data/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +10 -0
  53. data/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +22 -0
  54. data/src/nginx_module/MainConfig/AutoGeneratedStruct.h +8 -0
  55. data/src/nginx_module/ngx_http_passenger_module.c +6 -5
  56. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  57. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +0 -1
  58. data/src/ruby_supportlib/phusion_passenger/common_library.rb +3 -0
  59. data/src/ruby_supportlib/phusion_passenger/config/installation_utils.rb +3 -3
  60. data/src/ruby_supportlib/phusion_passenger/constants.rb +5 -0
  61. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +4 -2
  62. data/src/ruby_supportlib/phusion_passenger/platform_info.rb +3 -3
  63. data/src/ruby_supportlib/phusion_passenger/request_handler.rb +1 -1
  64. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +1 -1
  65. metadata +4 -2
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2018 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+ #ifndef _PASSENGER_FILE_TOOLS_PATH_SECURITY_CHECK_H_
27
+ #define _PASSENGER_FILE_TOOLS_PATH_SECURITY_CHECK_H_
28
+
29
+ #include <vector>
30
+ #include <string>
31
+ #include <StaticString.h>
32
+
33
+ namespace Passenger {
34
+
35
+ using namespace std;
36
+
37
+
38
+ /**
39
+ * Checks whether the given path is secure for use by a root process.
40
+ * This is done by checking whether the path itself, as well as any of the
41
+ * parent directories, can only be written to by root. Returns whether the
42
+ * path is deemed secure.
43
+ *
44
+ * If a non-root user can write to any of the directories in the path then that
45
+ * user can cause the root proces to read an arbitrary file. That file can even
46
+ * be one that is not owned by said user, through the use of symlinks.
47
+ *
48
+ * Checking is done according to normal Unix permissions. ACLs and systems like
49
+ * SELinux are not taken into consideration. Also, if this function fails to
50
+ * check a part of the path (e.g. because stat() failed) then this function
51
+ * simply skips that part. Therefore this function does not perform a full check
52
+ * and its result (which *can* be a false positive or a false negative) should be
53
+ * taken with a grain of salt.
54
+ *
55
+ * Error messages that can be used to inform the user which parts of the path
56
+ * are insecure, are outputted into `errors`. This vector becomes non-empty
57
+ * only if result is false.
58
+ *
59
+ * Any errors that occur w.r.t. checking itself (e.g. stat() errors) are
60
+ * outputted into `checkErrors`. This vector may become non-empty no matter
61
+ * the result.
62
+ */
63
+ bool isPathProbablySecureForRootUse(const StaticString &path,
64
+ vector<string> &errors, vector<string> &checkErrors);
65
+
66
+
67
+ } // namespace Passenger
68
+
69
+ #endif /* _PASSENGER_FILE_TOOLS_PATH_SECURITY_CHECK_H_ */
@@ -186,9 +186,37 @@ getProcessUsername(bool fallback) {
186
186
  }
187
187
  }
188
188
 
189
+ string
190
+ getUserName(uid_t uid) {
191
+ struct passwd pwd, *result;
192
+ int ret;
193
+ long bufSize;
194
+ shared_array<char> strings;
195
+
196
+ // _SC_GETPW_R_SIZE_MAX is not a maximum:
197
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
198
+ bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
199
+ strings.reset(new char[bufSize]);
200
+
201
+ result = (struct passwd *) NULL;
202
+ do {
203
+ ret = getpwuid_r(uid, &pwd, strings.get(), bufSize, &result);
204
+ } while (ret == EAGAIN);
205
+ if (ret != 0) {
206
+ result = (struct passwd *) NULL;
207
+ }
208
+
209
+ if (result == (struct passwd *) NULL || result->pw_name == NULL || result->pw_name[0] == '\0') {
210
+ return toString(uid);
211
+ } else {
212
+ return result->pw_name;
213
+ }
214
+ }
215
+
189
216
  string
190
217
  getGroupName(gid_t gid) {
191
- struct group grp, *groupEntry;
218
+ struct group grp, *result;
219
+ int ret;
192
220
  long bufSize;
193
221
  shared_array<char> strings;
194
222
 
@@ -197,15 +225,18 @@ getGroupName(gid_t gid) {
197
225
  bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETGR_R_SIZE_MAX));
198
226
  strings.reset(new char[bufSize]);
199
227
 
200
- groupEntry = (struct group *) NULL;
201
- if (getgrgid_r(gid, &grp, strings.get(), bufSize, &groupEntry) != 0) {
202
- groupEntry = (struct group *) NULL;
228
+ result = (struct group *) NULL;
229
+ do {
230
+ ret = getgrgid_r(gid, &grp, strings.get(), bufSize, &result);
231
+ } while (ret == EAGAIN);
232
+ if (ret != 0) {
233
+ result = (struct group *) NULL;
203
234
  }
204
235
 
205
- if (groupEntry == (struct group *) NULL) {
236
+ if (result == (struct group *) NULL || result->gr_name == NULL || result->gr_name[0] == '\0') {
206
237
  return toString(gid);
207
238
  } else {
208
- return groupEntry->gr_name;
239
+ return result->gr_name;
209
240
  }
210
241
  }
211
242
 
@@ -100,6 +100,12 @@ string escapeShell(const StaticString &input);
100
100
  */
101
101
  string getProcessUsername(bool fallback = true);
102
102
 
103
+ /**
104
+ * Returns either the user name for the given UID, or (if the user name
105
+ * couldn't be looked up) a string representation of the given UID.
106
+ */
107
+ string getUserName(uid_t uid);
108
+
103
109
  /**
104
110
  * Returns either the group name for the given GID, or (if the group name
105
111
  * couldn't be looked up) a string representation of the given GID.
@@ -159,12 +159,24 @@ limitedStrerror(int e, const char *defaultResult = "Unknown error") {
159
159
  return "Permission denied";
160
160
  case EFAULT:
161
161
  return "Bad address";
162
+ case EINVAL:
163
+ return "Invalid argument";
162
164
  case EIO:
163
165
  return "Input/output error";
166
+ case EISDIR:
167
+ return "Is a directory";
168
+ #ifdef ELIBBAD
169
+ case ELIBBAD:
170
+ return "Accessing a corrupted shared library";
171
+ #endif
164
172
  case ELOOP:
165
173
  return "Too many levels of symbolic links";
174
+ case EMFILE:
175
+ return "Too many open files";
166
176
  case ENAMETOOLONG:
167
177
  return "File name too long";
178
+ case ENFILE:
179
+ return "Too many open files in system";
168
180
  case ENOENT:
169
181
  return "No such file or directory";
170
182
  case ENOEXEC:
@@ -173,6 +185,8 @@ limitedStrerror(int e, const char *defaultResult = "Unknown error") {
173
185
  return "Cannot allocate memory";
174
186
  case ENOTDIR:
175
187
  return "Not a directory";
188
+ case EPERM:
189
+ return "Operation not permitted";
176
190
  case ETXTBSY:
177
191
  return "Text file busy";
178
192
  default:
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2017 Phusion Holding B.V.
3
+ * Copyright (c) 2010-2018 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -1354,32 +1354,23 @@ safelyClose(int fd, bool ignoreErrors) {
1354
1354
  }
1355
1355
  }
1356
1356
 
1357
- string
1358
- readAll(const string &filename) {
1359
- FILE *f = fopen(filename.c_str(), "rb");
1360
- if (f != NULL) {
1361
- StdioGuard guard(f, NULL, 0);
1362
- return readAll(fileno(f));
1363
- } else {
1364
- int e = errno;
1365
- throw FileSystemException("Cannot open '" + filename + "' for reading",
1366
- e, filename);
1367
- }
1368
- }
1369
-
1370
- string
1371
- readAll(int fd) {
1357
+ pair<string, bool>
1358
+ readAll(int fd, size_t maxSize) {
1372
1359
  string result;
1373
1360
  char buf[1024 * 32];
1374
1361
  ssize_t ret;
1375
- while (true) {
1362
+ bool eofReached = false;
1363
+
1364
+ while (result.size() < maxSize) {
1376
1365
  do {
1377
1366
  ret = read(fd, buf, sizeof(buf));
1378
1367
  } while (ret == -1 && errno == EINTR);
1379
1368
  if (ret == 0) {
1369
+ eofReached = true;
1380
1370
  break;
1381
1371
  } else if (ret == -1) {
1382
1372
  if (errno == ECONNRESET) {
1373
+ eofReached = true;
1383
1374
  break;
1384
1375
  } else {
1385
1376
  int e = errno;
@@ -1389,7 +1380,8 @@ readAll(int fd) {
1389
1380
  result.append(buf, ret);
1390
1381
  }
1391
1382
  }
1392
- return result;
1383
+
1384
+ return make_pair(result, eofReached);
1393
1385
  }
1394
1386
 
1395
1387
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2017 Phusion Holding B.V.
3
+ * Copyright (c) 2010-2018 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -34,6 +34,7 @@
34
34
  #include <unistd.h>
35
35
  #include <netdb.h>
36
36
  #include <string>
37
+ #include <utility>
37
38
  #include <vector>
38
39
  #include <oxt/macros.hpp>
39
40
  #include <StaticString.h>
@@ -642,18 +643,18 @@ void readPeerCredentials(int sock, uid_t *uid, gid_t *gid);
642
643
  #endif
643
644
 
644
645
  /**
645
- * Read all data from the given file until EOF.
646
+ * Read all data from the given file descriptor until EOF, or until `maxSize`
647
+ * is reached.
646
648
  *
647
- * @throws SystemException
648
- */
649
- string readAll(const string &filename);
650
-
651
- /**
652
- * Read all data from the given file descriptor until EOF.
649
+ * Returns a pair `(contents, eof)`.
650
+ *
651
+ * - `contents` is the read file contents, which is at most `maxSize` bytes.
652
+ * - `eof` indicates whether the entire file has been read. If false, then it
653
+ * means the amount of data is larger than `maxSize`.
653
654
  *
654
655
  * @throws SystemException
655
656
  */
656
- string readAll(int fd);
657
+ pair<string, bool> readAll(int fd, size_t maxSize);
657
658
 
658
659
  } // namespace Passenger
659
660
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2014-2017 Phusion Holding B.V.
3
+ * Copyright (c) 2014-2018 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -321,18 +321,22 @@ monoTimeToJson(MonotonicTimeUsec t, MonotonicTimeUsec monoNow, unsigned long lon
321
321
  }
322
322
 
323
323
  time_t wallClockTime = (time_t) (wallClockTimeUsec / 1000000ull);
324
- char timeStr[32];
324
+ char timeStr[32], *ctimeResult;
325
325
  size_t len;
326
- ctime_r(&wallClockTime, timeStr);
327
- len = strlen(timeStr);
328
- if (len > 0) {
329
- // Get rid of trailing newline
330
- timeStr[len - 1] = '\0';
326
+ ctimeResult = ctime_r(&wallClockTime, timeStr);
327
+ if (ctimeResult != NULL) {
328
+ len = strlen(timeStr);
329
+ if (len > 0) {
330
+ // Get rid of trailing newline
331
+ timeStr[len - 1] = '\0';
332
+ }
331
333
  }
332
334
 
333
335
  Json::Value doc;
334
336
  doc["timestamp"] = wallClockTimeUsec / 1000000.0;
335
- doc["local"] = timeStr;
337
+ if (ctimeResult != NULL) {
338
+ doc["local"] = timeStr;
339
+ }
336
340
  if (t > monoNow) {
337
341
  doc["relative_timestamp"] = (t - monoNow) / 1000000.0;
338
342
  doc["relative"] = distanceOfTimeInWords(t / 1000000ull, monoNow / 1000000ull) + " from now";
@@ -45,8 +45,8 @@
45
45
  #ifdef __linux__
46
46
  #include <sys/sysinfo.h>
47
47
  #include <Exceptions.h>
48
+ #include <FileTools/FileManip.h>
48
49
  #include <Utils/StringScanning.h>
49
- #include <Utils/IOUtils.h>
50
50
  #endif
51
51
  #ifdef __APPLE__
52
52
  #include <mach/mach.h>
@@ -912,7 +912,7 @@ private:
912
912
  string contents;
913
913
  bool hasContents = false;
914
914
  try {
915
- contents = readAll("/proc/meminfo");
915
+ contents = unsafeReadFile("/proc/meminfo");
916
916
  hasContents = true;
917
917
  } catch (const SystemException &) {
918
918
  }
@@ -987,7 +987,7 @@ private:
987
987
  string contents;
988
988
  bool hasContents = false;
989
989
  try {
990
- contents = readAll("/proc/stat");
990
+ contents = unsafeReadFile("/proc/stat");
991
991
  hasContents = true;
992
992
  } catch (const SystemException &) {
993
993
  }
@@ -1066,7 +1066,7 @@ private:
1066
1066
  string contents;
1067
1067
  bool hasContents = false;
1068
1068
  try {
1069
- contents = readAll("/proc/vmstat");
1069
+ contents = unsafeReadFile("/proc/vmstat");
1070
1070
  hasContents = true;
1071
1071
  } catch (const SystemException &) {
1072
1072
  }
@@ -116,7 +116,7 @@ private:
116
116
  template<Granularity granularityNs>
117
117
  static MonotonicTimeUsec _getMonotonicUsec() {
118
118
  if (OXT_UNLIKELY(SystemTimeData::hasForcedUsecValue)) {
119
- return SystemTimeData::hasForcedValue;
119
+ return SystemTimeData::forcedUsecValue;
120
120
  }
121
121
 
122
122
  #if BOOST_OS_MACOS
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2017 Phusion Holding B.V.
3
+ * Copyright (c) 2017-2018 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -47,9 +47,9 @@
47
47
  #include <ConfigKit/AsyncUtils.h>
48
48
  #include <Exceptions.h>
49
49
  #include <FileTools/PathManip.h>
50
+ #include <FileTools/FileManip.h>
50
51
  #include <Utils.h>
51
52
  #include <Utils/StrIntUtils.h>
52
- #include <Utils/IOUtils.h>
53
53
 
54
54
  namespace Passenger {
55
55
 
@@ -497,7 +497,7 @@ private:
497
497
  if (config["password_file"].isNull()) {
498
498
  password = config["password"].asString();
499
499
  } else {
500
- password = strip(readAll(config["password_file"].asString()));
500
+ password = strip(unsafeReadFile(config["password_file"].asString()));
501
501
  }
502
502
  string data = modp::b64_encode(username + ":" + password);
503
503
  conn->append_header("Authorization", "Basic " + data);
@@ -2,7 +2,7 @@
2
2
  * OXT - OS eXtensions for boosT
3
3
  * Provides important functionality necessary for writing robust server software.
4
4
  *
5
- * Copyright (c) 2010-2017 Phusion Holding B.V.
5
+ * Copyright (c) 2010-2018 Phusion Holding B.V.
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -171,6 +171,30 @@ syscalls::open(const char *path, int oflag, mode_t mode) {
171
171
  return ret;
172
172
  }
173
173
 
174
+ int
175
+ syscalls::openat(int dirfd, const char *path, int oflag) {
176
+ int ret;
177
+ CHECK_INTERRUPTION(
178
+ ret == -1,
179
+ true,
180
+ ret = -1,
181
+ ret = ::openat(dirfd, path, oflag)
182
+ );
183
+ return ret;
184
+ }
185
+
186
+ int
187
+ syscalls::openat(int dirfd, const char *path, int oflag, mode_t mode) {
188
+ int ret;
189
+ CHECK_INTERRUPTION(
190
+ ret == -1,
191
+ true,
192
+ ret = -1,
193
+ ret = ::openat(dirfd, path, oflag, mode)
194
+ );
195
+ return ret;
196
+ }
197
+
174
198
  ssize_t
175
199
  syscalls::read(int fd, void *buf, size_t count) {
176
200
  ssize_t ret;
@@ -2,7 +2,7 @@
2
2
  * OXT - OS eXtensions for boosT
3
3
  * Provides important functionality necessary for writing robust server software.
4
4
  *
5
- * Copyright (c) 2010-2017 Phusion Holding B.V.
5
+ * Copyright (c) 2010-2018 Phusion Holding B.V.
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -136,6 +136,8 @@ namespace oxt {
136
136
 
137
137
  int open(const char *path, int oflag);
138
138
  int open(const char *path, int oflag, mode_t mode);
139
+ int openat(int dirfd, const char *path, int oflag);
140
+ int openat(int dirfd, const char *path, int oflag, mode_t mode);
139
141
  ssize_t read(int fd, void *buf, size_t count);
140
142
  ssize_t write(int fd, const void *buf, size_t count);
141
143
  ssize_t writev(int fd, const struct iovec *iov, int iovcnt);