fstat(): Return a different st_ino each time instead of a fixed value
[nativeclient.git] / service_runtime / linux / nacl_host_desc.c
blobab9f9fb48ca97515b1d00f2c660f1c49e21584a4
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Service Runtime. I/O Descriptor / Handle abstraction. Memory
34 * mapping using descriptors.
36 * Note that we avoid using the thread-specific data / thread local
37 * storage access to the "errno" variable, and instead use the raw
38 * system call return interface of small negative numbers as errors.
41 #include <stdint.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <sys/mman.h>
47 #include <unistd.h>
49 #include "native_client/include/nacl_platform.h"
50 #include "native_client/include/portability.h"
52 #include "native_client/service_runtime/nacl_config.h"
53 #include "native_client/service_runtime/nacl_log.h"
54 #include "native_client/service_runtime/nacl_host_desc.h"
55 #include "native_client/service_runtime/sel_util.h"
56 #include "native_client/service_runtime/sel_memory.h"
58 #include "native_client/service_runtime/include/sys/errno.h"
59 #include "native_client/service_runtime/include/sys/fcntl.h"
60 #include "native_client/service_runtime/include/bits/mman.h"
61 #include "native_client/service_runtime/include/sys/stat.h"
64 * Map our ABI to the host OS's ABI. On linux, this should be a big no-op.
66 static INLINE int NaClMapOpenFlags(int nacl_flags)
68 int host_os_flags;
70 nacl_flags &= (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
71 | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
73 host_os_flags = 0;
74 #define C(H) case NACL_ABI_ ## H: \
75 host_os_flags |= H; \
76 break;
77 switch (nacl_flags & NACL_ABI_O_ACCMODE) {
78 C(O_RDONLY);
79 C(O_WRONLY);
80 C(O_RDWR);
82 #undef C
83 #define M(H) do { \
84 if (0 != (nacl_flags & NACL_ABI_ ## H)) { \
85 host_os_flags |= H; \
86 } \
87 } while (0)
88 M(O_CREAT);
89 M(O_TRUNC);
90 M(O_APPEND);
91 #undef M
92 return host_os_flags;
95 static INLINE int NaClMapOpenPerm(int nacl_perm)
97 int host_os_perm;
99 host_os_perm = 0;
100 #define M(H) do { \
101 if (0 != (nacl_perm & NACL_ABI_ ## H)) { \
102 host_os_perm |= H; \
104 } while (0)
105 M(S_IRUSR);
106 M(S_IWUSR);
107 #undef M
108 return host_os_perm;
111 static INLINE int NaClMapFlagMap(int nacl_map_flags)
113 int host_os_flags;
115 host_os_flags = 0;
116 #define M(H) do { \
117 if (0 != (nacl_map_flags & NACL_ABI_ ## H)) { \
118 host_os_flags |= H; \
120 } while (0)
121 M(MAP_SHARED);
122 M(MAP_PRIVATE);
123 M(MAP_FIXED);
124 M(MAP_ANONYMOUS);
125 #undef M
127 return host_os_flags;
130 int NaClHostDescMap(struct NaClHostDesc *d,
131 void *start_addr,
132 size_t len,
133 int prot,
134 int flags,
135 off_t offset)
137 int desc;
138 void *map_addr;
139 int host_prot;
140 int host_flags;
142 NaClLog(4,
143 ("NaClHostDescMap(0x%08"PRIxPTR", 0x%08"PRIxPTR", 0x%08"PRIxS","
144 " 0x%x, 0x%x, 0x%08"PRIx64")\n"),
145 (uintptr_t) d,
146 (uintptr_t) start_addr,
147 len,
148 prot,
149 flags,
150 (int64_t) offset);
151 if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) {
152 NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n");
154 prot &= (NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
155 /* may be PROT_NONE too */
156 flags &= NACL_ABI_MAP_ANONYMOUS;
157 /* NACL_ABI_MAP_SHARED is ignored */
158 flags |= NACL_ABI_MAP_FIXED | NACL_ABI_MAP_PRIVATE;
159 /* supplied start_addr must be okay, mapping must be private! */
161 if (flags & NACL_ABI_MAP_ANONYMOUS) {
162 desc = -1;
163 } else {
164 desc = d->d;
167 * Translate flags, prot to host_flags, host_prot.
169 host_flags = NaClMapFlagMap(flags);
170 host_prot = NaClProtMap(prot);
172 map_addr = mmap(start_addr, len, host_prot, host_flags, desc, offset);
174 if (MAP_FAILED == map_addr) {
175 NaClLog(LOG_INFO,
176 ("NaClHostDescMap:"
177 " mmap(0x%08"PRIxPTR", 0x%"PRIxS", 0x%x, 0x%x, 0x%d, 0x%"PRIx64")"
178 " failed, errno %d.\n"),
179 (uintptr_t) start_addr, len, host_prot, host_flags, desc,
180 (int64_t) offset,
181 errno);
182 return -NaClXlateErrno(errno);
184 if (map_addr != start_addr) {
185 NaClLog(LOG_FATAL,
186 ("NaClHostDescMap: mmap with MAP_FIXED not fixed:"
187 " returned 0x%08"PRIxPTR" instead of 0x%08"PRIxPTR"\n"),
188 (uintptr_t) map_addr,
189 (uintptr_t) start_addr);
191 NaClLog(4, "NaClHostDescMap: returning 0x%08"PRIxPTR"\n",
192 (uintptr_t) start_addr);
193 return (uintptr_t) start_addr; /* and convert to int */
196 int NaClHostDescUnmapUnsafe(void *start_addr,
197 size_t len)
199 int retval;
200 uintptr_t addr;
202 addr = (uintptr_t) start_addr;
204 return ((-1 == (retval = munmap(start_addr, len)))
205 ? -NaClXlateErrno(errno)
206 : retval);
209 int NaClHostDescUnmap(void *start_addr,
210 size_t len)
212 int retval;
213 uintptr_t addr;
215 addr = (uintptr_t) start_addr;
217 return ((-1 == (retval = (uintptr_t) mmap(start_addr,
218 len,
219 PROT_NONE,
220 (MAP_PRIVATE
221 | MAP_ANONYMOUS | MAP_FIXED),
223 (off_t) 0)))
224 ? -NaClXlateErrno(errno) : retval);
227 int NaClHostDescOpen(struct NaClHostDesc *d,
228 char *path,
229 int flags,
230 int mode)
232 int host_desc;
234 NaClLog(3, "NaClHostDescOpen(0x%08"PRIxPTR", %s, 0x%x, 0x%x)\n",
235 (uintptr_t) d, path, flags, mode);
236 if (NULL == d) {
237 NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
240 * Sanitize access flags.
242 if (0 != (flags & ~(NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
243 | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND))) {
244 return -NACL_ABI_EINVAL;
247 switch (flags & NACL_ABI_O_ACCMODE) {
248 case NACL_ABI_O_RDONLY:
249 case NACL_ABI_O_WRONLY:
250 case NACL_ABI_O_RDWR:
251 break;
252 default:
253 NaClLog(LOG_ERROR,
254 "NaClHostDescOpen: bad access flags 0x%x.\n",
255 flags);
256 return -NACL_ABI_EINVAL;
259 flags = NaClMapOpenFlags(flags);
260 mode = NaClMapOpenPerm(mode);
262 NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
263 path, flags, mode);
264 host_desc = open(path, flags, mode);
265 NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc);
266 if (-1 == host_desc) {
267 NaClLog(LOG_ERROR,
268 "NaClHostDescOpen: open returned -1, errno %d\n", errno);
269 return -NaClXlateErrno(errno);
271 d->d = host_desc;
272 NaClLog(3, "NaClHostDescOpen: success.\n");
273 return 0;
276 int NaClHostDescPosixDup(struct NaClHostDesc *d,
277 int posix_d,
278 int mode)
280 int host_desc;
282 if (NULL == d) {
283 NaClLog(LOG_FATAL, "NaClHostDescPosixDup: 'this' is NULL\n");
286 * Sanitize access modes.
288 if (0 != (mode & ~O_ACCMODE)) {
289 return -NACL_ABI_EINVAL;
292 switch (mode & O_ACCMODE) {
293 case O_RDONLY:
294 case O_WRONLY:
295 case O_RDWR:
296 break;
297 default:
298 NaClLog(LOG_ERROR,
299 "NaClHostDescPosixDup: bad access mode 0x%x.\n",
300 mode);
301 return -NACL_ABI_EINVAL;
304 host_desc = dup(posix_d);
305 if (-1 == host_desc) {
306 return -NACL_ABI_EINVAL;
308 d->d = host_desc;
309 return 0;
312 int NaClHostDescPosixTake(struct NaClHostDesc *d,
313 int posix_d,
314 int mode)
316 if (NULL == d) {
317 NaClLog(LOG_FATAL, "NaClHostDescPosixTake: 'this' is NULL\n");
320 * Sanitize access modes.
322 if (0 != (mode & ~O_ACCMODE)) {
323 return -NACL_ABI_EINVAL;
326 switch (mode & O_ACCMODE) {
327 case O_RDONLY:
328 case O_WRONLY:
329 case O_RDWR:
330 break;
331 default:
332 NaClLog(LOG_ERROR,
333 "NaClHostDescPosixTake: bad access mode 0x%x.\n",
334 mode);
335 return -NACL_ABI_EINVAL;
338 d->d = posix_d;
339 return 0;
342 ssize_t NaClHostDescRead(struct NaClHostDesc *d,
343 void *buf,
344 size_t len)
346 ssize_t retval;
348 if (NULL == d) {
349 NaClLog(LOG_FATAL, "NaClHostDescRead: 'this' is NULL\n");
351 return ((-1 == (retval = read(d->d, buf, len)))
352 ? -NaClXlateErrno(errno) : retval);
355 ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
356 void const *buf,
357 size_t len)
359 ssize_t retval;
361 if (NULL == d) {
362 NaClLog(LOG_FATAL, "NaClHostDescWrite: 'this' is NULL\n");
364 return ((-1 == (retval = write(d->d, buf, len)))
365 ? -NaClXlateErrno(errno) : retval);
368 int NaClHostDescSeek(struct NaClHostDesc *d,
369 off_t offset,
370 int whence)
372 int retval;
374 if (NULL == d) {
375 NaClLog(LOG_FATAL, "NaClHostDescSeek: 'this' is NULL\n");
377 return ((-1 == (retval = lseek(d->d, offset, whence)))
378 ? -NaClXlateErrno(errno) : retval);
381 int NaClHostDescIoctl(struct NaClHostDesc *d,
382 int request,
383 void *arg)
385 #if 0
386 int retval;
388 if (NULL == d) {
389 NaClLog(LOG_FATAL, "NaClHostDescIoctl: 'this' is NULL\n");
392 * Validate arg according to request. Arrgh indeed.
394 return ((-1 == (retval = ioctl(d->d, request, arg)))
395 ? -NaClXlateErrno(errno) : retval);
396 #else
397 if (NULL == d) {
398 NaClLog(LOG_FATAL, "NaClHostDescIoctl: 'this' is NULL\n");
400 return -NACL_ABI_ENOSYS;
401 #endif
404 static int next_inode_number = 1;
406 void NaClHostDescStatCommon(struct nacl_abi_stat *nasp,
407 struct stat *sbp)
409 nacl_abi_mode_t m;
411 nasp->nacl_abi_st_dev = 0;
412 /* Python uses st_ino to determine whether an extension module is
413 the same as a previously-loaded module. This hack stops st_ino
414 from being the same for different files. */
415 nasp->nacl_abi_st_ino = next_inode_number++;
417 switch (sbp->st_mode & S_IFMT) {
418 case S_IFREG:
419 m = NACL_ABI_S_IFREG;
420 break;
421 case S_IFDIR:
422 m = NACL_ABI_S_IFDIR;
423 break;
424 #if defined(S_IFCHR)
425 case S_IFCHR:
426 /* stdin/out/err can be inherited, so this is okay */
427 m = NACL_ABI_S_IFCHR;
428 break;
429 #endif
430 default:
431 NaClLog(LOG_ERROR,
432 ("NaClHostDescStatCommon: how did NaCl app open a file"
433 " with st_mode = 0%o?\n"),
434 sbp->st_mode);
435 m = NACL_ABI_S_UNSUP;
437 if (0 != (nasp->nacl_abi_st_mode & S_IRUSR)) {
438 m |= NACL_ABI_S_IRUSR;
440 if (0 != (nasp->nacl_abi_st_mode & S_IWUSR)) {
441 m |= NACL_ABI_S_IWUSR;
443 if (0 != (nasp->nacl_abi_st_mode & S_IXUSR)) {
444 m |= NACL_ABI_S_IXUSR;
446 nasp->nacl_abi_st_mode = m;
447 nasp->nacl_abi_st_nlink = sbp->st_nlink;
448 nasp->nacl_abi_st_uid = -1; /* not root */
449 nasp->nacl_abi_st_gid = -1; /* not wheel */
450 nasp->nacl_abi_st_rdev = 0;
451 nasp->nacl_abi_st_size = sbp->st_size;
452 nasp->nacl_abi_st_blksize = 0;
453 nasp->nacl_abi_st_blocks = 0;
454 nasp->nacl_abi_st_atime = sbp->st_atime;
455 nasp->nacl_abi_st_mtime = sbp->st_mtime;
456 nasp->nacl_abi_st_ctime = sbp->st_ctime;
460 * See NaClHostDescStat below.
462 int NaClHostDescFstat(struct NaClHostDesc *d,
463 struct nacl_abi_stat *nasp)
465 struct stat stbuf;
467 if (fstat(d->d, &stbuf) == -1) {
468 return -errno;
471 NaClHostDescStatCommon(nasp, &stbuf);
473 return 0;
476 int NaClHostDescClose(struct NaClHostDesc *d)
478 int retval;
480 if (NULL == d) {
481 NaClLog(LOG_FATAL, "NaClHostDescClose: 'this' is NULL\n");
483 retval = close(d->d);
484 if (-1 != retval) {
485 d->d = -1;
487 return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
491 * This is not a host descriptor function, but is closely related to
492 * fstat and should behave similarly.
494 int NaClHostDescStat(char const *host_os_pathname,
495 struct nacl_abi_stat *nasp)
497 struct stat stbuf;
499 if (stat(host_os_pathname, &stbuf) == -1) {
500 return -errno;
503 NaClHostDescStatCommon(nasp, &stbuf);
505 return 0;