Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:22

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  */
0006 
0007 /*
0008  * Copyright (c) 2016 Gedare Bloom.
0009  *
0010  * Redistribution and use in source and binary forms, with or without
0011  * modification, are permitted provided that the following conditions
0012  * are met:
0013  * 1. Redistributions of source code must retain the above copyright
0014  *    notice, this list of conditions and the following disclaimer.
0015  * 2. Redistributions in binary form must reproduce the above copyright
0016  *    notice, this list of conditions and the following disclaimer in the
0017  *    documentation and/or other materials provided with the distribution.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0020  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0022  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0023  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0024  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0025  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0026  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0027  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0028  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0029  * POSSIBILITY OF SUCH DAMAGE.
0030  */
0031 
0032 #ifdef HAVE_CONFIG_H
0033 #include "config.h"
0034 #endif
0035 
0036 #include <sys/mman.h>
0037 #include <errno.h>
0038 #include <unistd.h>
0039 #include <fcntl.h>
0040 #include <sys/stat.h>
0041 
0042 #include <rtems/libio_.h>
0043 #include <rtems/seterr.h>
0044 
0045 #include <rtems/posix/shmimpl.h>
0046 #include <rtems/score/wkspace.h>
0047 #include <rtems/sysinit.h>
0048 
0049 static const rtems_filesystem_file_handlers_r shm_handlers;
0050 
0051 static int shm_fstat(
0052   const rtems_filesystem_location_info_t *loc,
0053   struct stat *buf
0054 )
0055 {
0056   POSIX_Shm_Control *shm = loc_to_shm( loc );
0057 
0058   if ( shm == NULL )
0059     rtems_set_errno_and_return_minus_one( EIO );
0060 
0061   /* mandatory for shm objects */
0062   buf->st_uid = shm->uid;
0063   buf->st_gid = shm->gid;
0064   buf->st_size = shm->shm_object.size;
0065   buf->st_mode = shm->mode;
0066 
0067   /* optional for shm objects */
0068   buf->st_atime = shm->atime;
0069   buf->st_mtime = shm->mtime;
0070   buf->st_ctime = shm->ctime;
0071 
0072   return 0;
0073 }
0074 
0075 /* read() is unspecified for shared memory objects */
0076 static ssize_t shm_read( rtems_libio_t *iop, void *buffer, size_t count )
0077 {
0078   ssize_t bytes_read;
0079   POSIX_Shm_Control *shm = iop_to_shm( iop );
0080 
0081   _Objects_Allocator_lock();
0082   bytes_read = (*shm->shm_object.ops->object_read)(
0083       &shm->shm_object,
0084       buffer,
0085       count
0086   );
0087   _POSIX_Shm_Update_atime( shm );
0088 
0089   _Objects_Allocator_unlock();
0090   return bytes_read;
0091 }
0092 
0093 static int shm_ftruncate( rtems_libio_t *iop, off_t length )
0094 {
0095   int err;
0096   POSIX_Shm_Control *shm = iop_to_shm( iop );
0097 
0098   _Objects_Allocator_lock();
0099 
0100   err = (*shm->shm_object.ops->object_resize)( &shm->shm_object, length );
0101 
0102   if ( err != 0 ) {
0103     _Objects_Allocator_unlock();
0104     rtems_set_errno_and_return_minus_one( err );
0105   }
0106 
0107   _POSIX_Shm_Update_mtime_ctime( shm );
0108 
0109   _Objects_Allocator_unlock();
0110   return 0;
0111 }
0112 
0113 static int shm_close( rtems_libio_t *iop )
0114 {
0115   POSIX_Shm_Control *shm = iop_to_shm( iop );
0116   int err;
0117 
0118   err = 0;
0119 
0120   POSIX_Shm_Attempt_delete(shm);
0121   iop->pathinfo.node_access = NULL;
0122 
0123   if ( err != 0 ) {
0124     rtems_set_errno_and_return_minus_one( err );
0125   }
0126   return 0;
0127 }
0128 
0129 static int shm_mmap(
0130   rtems_libio_t *iop,
0131   void** addr,
0132   size_t len,
0133   int prot,
0134   off_t off
0135 )
0136 {
0137   POSIX_Shm_Control *shm = iop_to_shm( iop );
0138 
0139   _Objects_Allocator_lock();
0140 
0141   *addr = (*shm->shm_object.ops->object_mmap)( &shm->shm_object, len, prot, off);
0142   if ( *addr != NULL ) {
0143     /* Keep a reference in the shared memory to prevent its removal. */
0144     ++shm->reference_count;
0145 
0146     /* Update atime */
0147     _POSIX_Shm_Update_atime(shm);
0148   } else {
0149     _Objects_Allocator_unlock();
0150     rtems_set_errno_and_return_minus_one( ENOMEM );
0151   }
0152 
0153   _Objects_Allocator_unlock();
0154 
0155   return 0;
0156 }
0157 
0158 static inline POSIX_Shm_Control *shm_allocate(
0159   const char *name_arg,
0160   size_t name_len,
0161   int oflag,
0162   mode_t mode,
0163   int *error
0164 )
0165 {
0166   POSIX_Shm_Control *shm;
0167   char *name;
0168   struct timeval tv;
0169 
0170   /* Reject any name without a leading slash. */
0171   if ( name_arg[0] != '/' ) {
0172     *error = EINVAL;
0173     return NULL;
0174   }
0175 
0176   /* Only create the object if requested. */
0177   if ( ( oflag & O_CREAT ) != O_CREAT ) {
0178     *error = ENOENT;
0179     return NULL;
0180   }
0181 
0182   name = _Workspace_String_duplicate( name_arg, name_len );
0183   if ( name == NULL ) {
0184     *error = ENOSPC;
0185     return NULL;
0186   }
0187 
0188   shm = _POSIX_Shm_Allocate_unprotected();
0189   if ( shm == NULL ) {
0190     _Workspace_Free( name );
0191     *error = ENFILE;
0192     return NULL;
0193   }
0194 
0195   gettimeofday( &tv, 0 );
0196 
0197   shm->reference_count = 1;
0198   shm->shm_object.handle = NULL;
0199   shm->shm_object.size = 0;
0200   shm->shm_object.ops = &_POSIX_Shm_Object_operations;
0201   shm->mode = mode & ~rtems_filesystem_umask;
0202   shm->oflag = oflag;
0203   shm->uid = geteuid();
0204   shm->gid = getegid();
0205   shm->atime = (time_t) tv.tv_sec;
0206   shm->mtime = (time_t) tv.tv_sec;
0207   shm->ctime = (time_t) tv.tv_sec;
0208 
0209   _Objects_Open_string( &_POSIX_Shm_Information, &shm->Object, name );
0210 
0211   return shm;
0212 }
0213 
0214 static inline bool shm_access_ok( POSIX_Shm_Control *shm, int oflag )
0215 {
0216   int flags;
0217 
0218   if ( (oflag & O_ACCMODE) == O_RDONLY ) {
0219     flags = RTEMS_FS_PERMS_READ;
0220   } else {
0221     flags = RTEMS_FS_PERMS_WRITE;
0222   }
0223   return rtems_filesystem_check_access( flags, shm->mode, shm->uid, shm->gid );
0224 }
0225 
0226 static inline int shm_check_oflag( int oflag )
0227 {
0228   if ( ( oflag & O_ACCMODE ) != O_RDONLY && ( oflag & O_ACCMODE ) != O_RDWR ) {
0229     rtems_set_errno_and_return_minus_one( EACCES );
0230   }
0231 
0232   if ( ( oflag & ~( O_RDONLY | O_RDWR | O_CREAT | O_EXCL | O_TRUNC ) ) != 0 ) {
0233     rtems_set_errno_and_return_minus_one( EACCES );
0234   }
0235 
0236   if ( ( oflag & O_TRUNC ) != 0 && ( oflag & O_ACCMODE ) != O_RDWR ) {
0237     rtems_set_errno_and_return_minus_one( EACCES );
0238   }
0239   return 0;
0240 }
0241 
0242 int shm_open( const char *name, int oflag, mode_t mode )
0243 {
0244   int err = 0;
0245   int fd;
0246   rtems_libio_t *iop;
0247   POSIX_Shm_Control *shm;
0248   size_t len;
0249   Objects_Get_by_name_error obj_err;
0250   unsigned int flags;
0251 
0252   if ( shm_check_oflag( oflag ) != 0 ) {
0253     return -1;
0254   }
0255 
0256   iop = rtems_libio_allocate();
0257   if ( iop == NULL ) {
0258     rtems_set_errno_and_return_minus_one( EMFILE );
0259   }
0260 
0261   _Objects_Allocator_lock();
0262   shm = _POSIX_Shm_Get_by_name( name, &len, &obj_err );
0263 
0264   if ( shm == NULL ) {
0265     switch ( obj_err ) {
0266       case OBJECTS_GET_BY_NAME_INVALID_NAME:
0267         err = EINVAL;
0268         break;
0269 
0270       case OBJECTS_GET_BY_NAME_NAME_TOO_LONG:
0271         err = ENAMETOOLONG;
0272         break;
0273 
0274       case OBJECTS_GET_BY_NAME_NO_OBJECT:
0275       default:
0276         shm = shm_allocate(name, len, oflag, mode, &err);
0277         break;
0278     }
0279   } else { /* shm exists */
0280     if ( ( oflag & ( O_EXCL | O_CREAT ) ) == ( O_EXCL | O_CREAT ) ) {
0281       /* Request to create failed. */
0282       err = EEXIST;
0283     } else if ( !shm_access_ok( shm, oflag ) ) {
0284       err = EACCES;
0285     } else {
0286       ++shm->reference_count;
0287     }
0288   }
0289   _Objects_Allocator_unlock();
0290   if ( err != 0 ) {
0291     rtems_libio_free( iop );
0292     rtems_set_errno_and_return_minus_one( err );
0293   }
0294 
0295   if ( oflag & O_TRUNC ) {
0296     err = shm_ftruncate( iop, 0 );
0297     (void) err; /* ignore truncate error */
0298   }
0299 
0300   fd = rtems_libio_iop_to_descriptor( iop );
0301   iop->data0 = fd;
0302   iop->data1 = shm;
0303   iop->pathinfo.node_access = shm;
0304   iop->pathinfo.handlers = &shm_handlers;
0305   iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
0306   rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo );
0307 
0308   flags = LIBIO_FLAGS_OPEN | LIBIO_FLAGS_CLOSE_ON_EXEC;
0309   if ( (oflag & O_ACCMODE) == O_RDONLY ) {
0310     flags |= LIBIO_FLAGS_READ;
0311   } else {
0312     flags |= LIBIO_FLAGS_READ_WRITE;
0313   }
0314 
0315   rtems_libio_iop_flags_set( iop, flags );
0316 
0317   return fd;
0318 }
0319 
0320 static const rtems_filesystem_file_handlers_r shm_handlers = {
0321   .open_h = rtems_filesystem_default_open,
0322   .close_h = shm_close,
0323   .read_h = shm_read,
0324   .write_h = rtems_filesystem_default_write,
0325   .ioctl_h = rtems_filesystem_default_ioctl,
0326   .lseek_h = rtems_filesystem_default_lseek,
0327   .fstat_h = shm_fstat,
0328   .ftruncate_h = shm_ftruncate,
0329   .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
0330   .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0331   .fcntl_h = rtems_filesystem_default_fcntl,
0332   .kqfilter_h = rtems_filesystem_default_kqfilter,
0333   .mmap_h = shm_mmap,
0334   .poll_h = rtems_filesystem_default_poll,
0335   .readv_h = rtems_filesystem_default_readv,
0336   .writev_h = rtems_filesystem_default_writev
0337 };
0338 
0339 static void _POSIX_Shm_Manager_initialization( void )
0340 {
0341   _Objects_Initialize_information( &_POSIX_Shm_Information );
0342 }
0343 
0344 RTEMS_SYSINIT_ITEM(
0345   _POSIX_Shm_Manager_initialization,
0346   RTEMS_SYSINIT_POSIX_SHM,
0347   RTEMS_SYSINIT_ORDER_MIDDLE
0348 );