source: rtems/cpukit/posix/src/shmopen.c

Last change on this file was 380fb9f, checked in by Joel Sherrill <joel@…>, on 02/16/22 at 22:32:05

cpukit/posix/src/[p-z]*.c: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 */
6
7/*
8 * Copyright (c) 2016 Gedare Bloom.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <sys/mman.h>
37#include <errno.h>
38#include <unistd.h>
39#include <fcntl.h>
40#include <sys/stat.h>
41
42#include <rtems/libio_.h>
43#include <rtems/seterr.h>
44
45#include <rtems/posix/shmimpl.h>
46#include <rtems/score/wkspace.h>
47#include <rtems/sysinit.h>
48
49static const rtems_filesystem_file_handlers_r shm_handlers;
50
51static int shm_fstat(
52  const rtems_filesystem_location_info_t *loc,
53  struct stat *buf
54)
55{
56  POSIX_Shm_Control *shm = loc_to_shm( loc );
57
58  if ( shm == NULL )
59    rtems_set_errno_and_return_minus_one( EIO );
60
61  /* mandatory for shm objects */
62  buf->st_uid = shm->uid;
63  buf->st_gid = shm->gid;
64  buf->st_size = shm->shm_object.size;
65  buf->st_mode = shm->mode;
66
67  /* optional for shm objects */
68  buf->st_atime = shm->atime;
69  buf->st_mtime = shm->mtime;
70  buf->st_ctime = shm->ctime;
71
72  return 0;
73}
74
75/* read() is unspecified for shared memory objects */
76static ssize_t shm_read( rtems_libio_t *iop, void *buffer, size_t count )
77{
78  ssize_t bytes_read;
79  POSIX_Shm_Control *shm = iop_to_shm( iop );
80
81  _Objects_Allocator_lock();
82  bytes_read = (*shm->shm_object.ops->object_read)(
83      &shm->shm_object,
84      buffer,
85      count
86  );
87  _POSIX_Shm_Update_atime( shm );
88
89  _Objects_Allocator_unlock();
90  return bytes_read;
91}
92
93static int shm_ftruncate( rtems_libio_t *iop, off_t length )
94{
95  int err;
96  POSIX_Shm_Control *shm = iop_to_shm( iop );
97
98  _Objects_Allocator_lock();
99
100  err = (*shm->shm_object.ops->object_resize)( &shm->shm_object, length );
101
102  if ( err != 0 ) {
103    _Objects_Allocator_unlock();
104    rtems_set_errno_and_return_minus_one( err );
105  }
106
107  _POSIX_Shm_Update_mtime_ctime( shm );
108
109  _Objects_Allocator_unlock();
110  return 0;
111}
112
113static int shm_close( rtems_libio_t *iop )
114{
115  POSIX_Shm_Control *shm = iop_to_shm( iop );
116  int err;
117
118  err = 0;
119
120  POSIX_Shm_Attempt_delete(shm);
121  iop->pathinfo.node_access = NULL;
122
123  if ( err != 0 ) {
124    rtems_set_errno_and_return_minus_one( err );
125  }
126  return 0;
127}
128
129static int shm_mmap(
130  rtems_libio_t *iop,
131  void** addr,
132  size_t len,
133  int prot,
134  off_t off
135)
136{
137  POSIX_Shm_Control *shm = iop_to_shm( iop );
138
139  _Objects_Allocator_lock();
140
141  *addr = (*shm->shm_object.ops->object_mmap)( &shm->shm_object, len, prot, off);
142  if ( *addr != NULL ) {
143    /* Keep a reference in the shared memory to prevent its removal. */
144    ++shm->reference_count;
145
146    /* Update atime */
147    _POSIX_Shm_Update_atime(shm);
148  } else {
149    _Objects_Allocator_unlock();
150    rtems_set_errno_and_return_minus_one( ENOMEM );
151  }
152
153  _Objects_Allocator_unlock();
154
155  return 0;
156}
157
158static inline POSIX_Shm_Control *shm_allocate(
159  const char *name_arg,
160  size_t name_len,
161  int oflag,
162  mode_t mode,
163  int *error
164)
165{
166  POSIX_Shm_Control *shm;
167  char *name;
168  struct timeval tv;
169
170  /* Reject any name without a leading slash. */
171  if ( name_arg[0] != '/' ) {
172    *error = EINVAL;
173    return NULL;
174  }
175
176  /* Only create the object if requested. */
177  if ( ( oflag & O_CREAT ) != O_CREAT ) {
178    *error = ENOENT;
179    return NULL;
180  }
181
182  name = _Workspace_String_duplicate( name_arg, name_len );
183  if ( name == NULL ) {
184    *error = ENOSPC;
185    return NULL;
186  }
187
188  shm = _POSIX_Shm_Allocate_unprotected();
189  if ( shm == NULL ) {
190    _Workspace_Free( name );
191    *error = ENFILE;
192    return NULL;
193  }
194
195  gettimeofday( &tv, 0 );
196
197  shm->reference_count = 1;
198  shm->shm_object.handle = NULL;
199  shm->shm_object.size = 0;
200  shm->shm_object.ops = &_POSIX_Shm_Object_operations;
201  shm->mode = mode & ~rtems_filesystem_umask;
202  shm->oflag = oflag;
203  shm->uid = geteuid();
204  shm->gid = getegid();
205  shm->atime = (time_t) tv.tv_sec;
206  shm->mtime = (time_t) tv.tv_sec;
207  shm->ctime = (time_t) tv.tv_sec;
208
209  _Objects_Open_string( &_POSIX_Shm_Information, &shm->Object, name );
210
211  return shm;
212}
213
214static inline bool shm_access_ok( POSIX_Shm_Control *shm, int oflag )
215{
216  int flags;
217
218  if ( (oflag & O_ACCMODE) == O_RDONLY ) {
219    flags = RTEMS_FS_PERMS_READ;
220  } else {
221    flags = RTEMS_FS_PERMS_WRITE;
222  }
223  return rtems_filesystem_check_access( flags, shm->mode, shm->uid, shm->gid );
224}
225
226static inline int shm_check_oflag( int oflag )
227{
228  if ( ( oflag & O_ACCMODE ) != O_RDONLY && ( oflag & O_ACCMODE ) != O_RDWR ) {
229    rtems_set_errno_and_return_minus_one( EACCES );
230  }
231
232  if ( ( oflag & ~( O_RDONLY | O_RDWR | O_CREAT | O_EXCL | O_TRUNC ) ) != 0 ) {
233    rtems_set_errno_and_return_minus_one( EACCES );
234  }
235
236  if ( ( oflag & O_TRUNC ) != 0 && ( oflag & O_ACCMODE ) != O_RDWR ) {
237    rtems_set_errno_and_return_minus_one( EACCES );
238  }
239  return 0;
240}
241
242int shm_open( const char *name, int oflag, mode_t mode )
243{
244  int err = 0;
245  int fd;
246  rtems_libio_t *iop;
247  POSIX_Shm_Control *shm;
248  size_t len;
249  Objects_Get_by_name_error obj_err;
250  unsigned int flags;
251
252  if ( shm_check_oflag( oflag ) != 0 ) {
253    return -1;
254  }
255
256  iop = rtems_libio_allocate();
257  if ( iop == NULL ) {
258    rtems_set_errno_and_return_minus_one( EMFILE );
259  }
260
261  _Objects_Allocator_lock();
262  shm = _POSIX_Shm_Get_by_name( name, &len, &obj_err );
263
264  if ( shm == NULL ) {
265    switch ( obj_err ) {
266      case OBJECTS_GET_BY_NAME_INVALID_NAME:
267        err = EINVAL;
268        break;
269
270      case OBJECTS_GET_BY_NAME_NAME_TOO_LONG:
271        err = ENAMETOOLONG;
272        break;
273
274      case OBJECTS_GET_BY_NAME_NO_OBJECT:
275      default:
276        shm = shm_allocate(name, len, oflag, mode, &err);
277        break;
278    }
279  } else { /* shm exists */
280    if ( ( oflag & ( O_EXCL | O_CREAT ) ) == ( O_EXCL | O_CREAT ) ) {
281      /* Request to create failed. */
282      err = EEXIST;
283    } else if ( !shm_access_ok( shm, oflag ) ) {
284      err = EACCES;
285    } else {
286      ++shm->reference_count;
287    }
288  }
289  _Objects_Allocator_unlock();
290  if ( err != 0 ) {
291    rtems_libio_free( iop );
292    rtems_set_errno_and_return_minus_one( err );
293  }
294
295  if ( oflag & O_TRUNC ) {
296    err = shm_ftruncate( iop, 0 );
297    (void) err; /* ignore truncate error */
298  }
299
300  fd = rtems_libio_iop_to_descriptor( iop );
301  iop->data0 = fd;
302  iop->data1 = shm;
303  iop->pathinfo.node_access = shm;
304  iop->pathinfo.handlers = &shm_handlers;
305  iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
306  rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo );
307
308  flags = LIBIO_FLAGS_OPEN | LIBIO_FLAGS_CLOSE_ON_EXEC;
309  if ( (oflag & O_ACCMODE) == O_RDONLY ) {
310    flags |= LIBIO_FLAGS_READ;
311  } else {
312    flags |= LIBIO_FLAGS_READ_WRITE;
313  }
314
315  rtems_libio_iop_flags_set( iop, flags );
316
317  return fd;
318}
319
320static const rtems_filesystem_file_handlers_r shm_handlers = {
321  .open_h = rtems_filesystem_default_open,
322  .close_h = shm_close,
323  .read_h = shm_read,
324  .write_h = rtems_filesystem_default_write,
325  .ioctl_h = rtems_filesystem_default_ioctl,
326  .lseek_h = rtems_filesystem_default_lseek,
327  .fstat_h = shm_fstat,
328  .ftruncate_h = shm_ftruncate,
329  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
330  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
331  .fcntl_h = rtems_filesystem_default_fcntl,
332  .kqfilter_h = rtems_filesystem_default_kqfilter,
333  .mmap_h = shm_mmap,
334  .poll_h = rtems_filesystem_default_poll,
335  .readv_h = rtems_filesystem_default_readv,
336  .writev_h = rtems_filesystem_default_writev
337};
338
339static void _POSIX_Shm_Manager_initialization( void )
340{
341  _Objects_Initialize_information( &_POSIX_Shm_Information );
342}
343
344RTEMS_SYSINIT_ITEM(
345  _POSIX_Shm_Manager_initialization,
346  RTEMS_SYSINIT_POSIX_SHM,
347  RTEMS_SYSINIT_ORDER_MIDDLE
348);
Note: See TracBrowser for help on using the repository browser.