source: rtems/cpukit/posix/src/shmopen.c @ 05f9858f

5
Last change on this file since 05f9858f was baef823c, checked in by Sebastian Huber <sebastian.huber@…>, on 09/13/17 at 07:22:19

libio: Add hold/drop iop reference

Check iop reference count in close() and return -1 with errno set to
EBUSY in case the file descriptor is still in use.

Update #3132.

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/**
2 * @file
3 */
4
5/*
6 * Copyright (c) 2016 Gedare Bloom.
7 *
8 * The license and distribution terms for this file may be
9 * found in the file LICENSE in this distribution or at
10 * http://www.rtems.org/license/LICENSE.
11 */
12
13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <sys/mman.h>
18#include <errno.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <sys/stat.h>
22
23#include <rtems/libio_.h>
24#include <rtems/seterr.h>
25
26#include <rtems/posix/shmimpl.h>
27#include <rtems/score/wkspace.h>
28
29static const rtems_filesystem_file_handlers_r shm_handlers;
30
31static int shm_fstat(
32  const rtems_filesystem_location_info_t *loc,
33  struct stat *buf
34)
35{
36  POSIX_Shm_Control *shm = loc_to_shm( loc );
37
38  if ( shm == NULL )
39    rtems_set_errno_and_return_minus_one( EIO );
40
41  /* mandatory for shm objects */
42  buf->st_uid = shm->uid;
43  buf->st_gid = shm->gid;
44  buf->st_size = shm->shm_object.size;
45  buf->st_mode = shm->mode;
46
47  /* optional for shm objects */
48  buf->st_atime = shm->atime;
49  buf->st_mtime = shm->mtime;
50  buf->st_ctime = shm->ctime;
51
52  return 0;
53}
54
55/* read() is unspecified for shared memory objects */
56static ssize_t shm_read( rtems_libio_t *iop, void *buffer, size_t count )
57{
58  ssize_t bytes_read;
59  POSIX_Shm_Control *shm = iop_to_shm( iop );
60
61  _Objects_Allocator_lock();
62  bytes_read = (*shm->shm_object.ops->object_read)(
63      &shm->shm_object,
64      buffer,
65      count
66  );
67  _POSIX_Shm_Update_atime( shm );
68
69  _Objects_Allocator_unlock();
70  return bytes_read;
71}
72
73static int shm_ftruncate( rtems_libio_t *iop, off_t length )
74{
75  int err;
76  POSIX_Shm_Control *shm = iop_to_shm( iop );
77
78  _Objects_Allocator_lock();
79
80  err = (*shm->shm_object.ops->object_resize)( &shm->shm_object, length );
81
82  if ( err != 0 ) {
83    _Objects_Allocator_unlock();
84    rtems_set_errno_and_return_minus_one( err );
85  }
86
87  _POSIX_Shm_Update_mtime_ctime( shm );
88
89  _Objects_Allocator_unlock();
90  return 0;
91}
92
93static int shm_close( rtems_libio_t *iop )
94{
95  POSIX_Shm_Control *shm = iop_to_shm( iop );
96  int err;
97
98  err = 0;
99
100  POSIX_Shm_Attempt_delete(shm);
101  iop->pathinfo.node_access = NULL;
102
103  if ( err != 0 ) {
104    rtems_set_errno_and_return_minus_one( err );
105  }
106  return 0;
107}
108
109static int shm_mmap(
110  rtems_libio_t *iop,
111  void** addr,
112  size_t len,
113  int prot,
114  off_t off
115)
116{
117  POSIX_Shm_Control *shm = iop_to_shm( iop );
118
119  _Objects_Allocator_lock();
120
121  *addr = (*shm->shm_object.ops->object_mmap)( &shm->shm_object, len, prot, off);
122  if ( *addr != NULL ) {
123    /* Keep a reference in the shared memory to prevent its removal. */
124    ++shm->reference_count;
125
126    /* Update atime */
127    _POSIX_Shm_Update_atime(shm);
128  } else {
129    _Objects_Allocator_unlock();
130    rtems_set_errno_and_return_minus_one( ENOMEM );
131  }
132
133  _Objects_Allocator_unlock();
134
135  return 0;
136}
137
138static inline POSIX_Shm_Control *shm_allocate(
139  const char *name_arg,
140  size_t name_len,
141  int oflag,
142  mode_t mode,
143  int *error
144)
145{
146  POSIX_Shm_Control *shm;
147  char *name;
148  struct timeval tv;
149
150  /* Reject any name without a leading slash. */
151  if ( name_arg[0] != '/' ) {
152    *error = EINVAL;
153    return NULL;
154  }
155
156  /* Only create the object if requested. */
157  if ( ( oflag & O_CREAT ) != O_CREAT ) {
158    *error = ENOENT;
159    return NULL;
160  }
161
162  name = _Workspace_String_duplicate( name_arg, name_len );
163  if ( name == NULL ) {
164    *error = ENOSPC;
165    return NULL;
166  }
167
168  shm = _POSIX_Shm_Allocate_unprotected();
169  if ( shm == NULL ) {
170    _Workspace_Free( name );
171    *error = ENFILE;
172    return NULL;
173  }
174
175  gettimeofday( &tv, 0 );
176
177  shm->reference_count = 1;
178  shm->shm_object.handle = NULL;
179  shm->shm_object.size = 0;
180  shm->shm_object.ops = &_POSIX_Shm_Object_operations;
181  shm->mode = mode & ~rtems_filesystem_umask;
182  shm->uid = geteuid();
183  shm->gid = getegid();
184  shm->atime = (time_t) tv.tv_sec;
185  shm->mtime = (time_t) tv.tv_sec;
186  shm->ctime = (time_t) tv.tv_sec;
187
188  _Objects_Open_string( &_POSIX_Shm_Information, &shm->Object, name );
189
190  return shm;
191}
192
193static inline bool shm_access_ok( POSIX_Shm_Control *shm, int oflag )
194{
195  int flags;
196  if ( oflag & O_RDONLY ) {
197    flags = RTEMS_FS_PERMS_READ;
198  } else {
199    flags = RTEMS_FS_PERMS_WRITE;
200  }
201  return rtems_filesystem_check_access( flags, shm->mode, shm->uid, shm->gid );
202}
203
204static inline int shm_check_oflag( int oflag )
205{
206  if ( ( oflag & O_ACCMODE ) != O_RDONLY && ( oflag & O_ACCMODE ) != O_RDWR ) {
207    rtems_set_errno_and_return_minus_one( EACCES );
208  }
209
210  if ( ( oflag & ~( O_RDONLY | O_RDWR | O_CREAT | O_EXCL | O_TRUNC ) ) != 0 ) {
211    rtems_set_errno_and_return_minus_one( EACCES );
212  }
213
214  if ( ( oflag & O_TRUNC ) != 0 && ( oflag & O_ACCMODE ) != O_RDWR ) {
215    rtems_set_errno_and_return_minus_one( EACCES );
216  }
217  return 0;
218}
219
220int shm_open( const char *name, int oflag, mode_t mode )
221{
222  int err = 0;
223  int fd;
224  rtems_libio_t *iop;
225  POSIX_Shm_Control *shm;
226  size_t len;
227  Objects_Get_by_name_error obj_err;
228  unsigned int flags;
229
230  if ( shm_check_oflag( oflag ) != 0 ) {
231    return -1;
232  }
233
234  iop = rtems_libio_allocate();
235  if ( iop == NULL ) {
236    rtems_set_errno_and_return_minus_one( EMFILE );
237  }
238
239  _Objects_Allocator_lock();
240  shm = _POSIX_Shm_Get_by_name( name, &len, &obj_err );
241
242  if ( shm == NULL ) {
243    switch ( obj_err ) {
244      case OBJECTS_GET_BY_NAME_INVALID_NAME:
245        err = EINVAL;
246        break;
247
248      case OBJECTS_GET_BY_NAME_NAME_TOO_LONG:
249        err = ENAMETOOLONG;
250        break;
251
252      case OBJECTS_GET_BY_NAME_NO_OBJECT:
253      default:
254        shm = shm_allocate(name, len, oflag, mode, &err);
255        break;
256    }
257  } else { /* shm exists */
258    if ( ( oflag & ( O_EXCL | O_CREAT ) ) == ( O_EXCL | O_CREAT ) ) {
259      /* Request to create failed. */
260      err = EEXIST;
261    } else if ( !shm_access_ok( shm, oflag ) ) {
262      err = EACCES;
263    } else {
264      ++shm->reference_count;
265    }
266  }
267  _Objects_Allocator_unlock();
268  if ( err != 0 ) {
269    rtems_libio_free( iop );
270    rtems_set_errno_and_return_minus_one( err );
271  }
272
273  if ( oflag & O_TRUNC ) {
274    err = shm_ftruncate( iop, 0 );
275    (void) err; /* ignore truncate error */
276  }
277
278  fd = rtems_libio_iop_to_descriptor( iop );
279  iop->data0 = fd;
280  iop->data1 = shm;
281  iop->pathinfo.node_access = shm;
282  iop->pathinfo.handlers = &shm_handlers;
283  iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
284  rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo );
285
286  flags = LIBIO_FLAGS_CLOSE_ON_EXEC;
287  if ( oflag & O_RDONLY ) {
288    flags |= LIBIO_FLAGS_READ;
289  } else {
290    flags |= LIBIO_FLAGS_READ_WRITE;
291  }
292
293  rtems_libio_iop_flags_initialize( iop, flags );
294
295  return fd;
296}
297
298static const rtems_filesystem_file_handlers_r shm_handlers = {
299  .open_h = rtems_filesystem_default_open,
300  .close_h = shm_close,
301  .read_h = shm_read,
302  .write_h = rtems_filesystem_default_write,
303  .ioctl_h = rtems_filesystem_default_ioctl,
304  .lseek_h = rtems_filesystem_default_lseek,
305  .fstat_h = shm_fstat,
306  .ftruncate_h = shm_ftruncate,
307  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
308  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
309  .fcntl_h = rtems_filesystem_default_fcntl,
310  .kqfilter_h = rtems_filesystem_default_kqfilter,
311  .mmap_h = shm_mmap,
312  .poll_h = rtems_filesystem_default_poll,
313  .readv_h = rtems_filesystem_default_readv,
314  .writev_h = rtems_filesystem_default_writev
315};
Note: See TracBrowser for help on using the repository browser.