[07a3253d] | 1 | /* |
---|
| 2 | * mount() |
---|
| 3 | * |
---|
| 4 | * XXX |
---|
| 5 | * |
---|
[50f32b11] | 6 | * XXX make sure no required ops are NULL |
---|
| 7 | * XXX make sure no optional ops you are using are NULL |
---|
[07a3253d] | 8 | * XXX unmount should be required. |
---|
| 9 | * |
---|
[08311cc3] | 10 | * COPYRIGHT (c) 1989-1999. |
---|
[07a3253d] | 11 | * On-Line Applications Research Corporation (OAR). |
---|
| 12 | * |
---|
[00bf6744] | 13 | * Copyright (c) 2010 embedded brains GmbH. |
---|
| 14 | * |
---|
[07a3253d] | 15 | * The license and distribution terms for this file may be |
---|
| 16 | * found in the file LICENSE in this distribution or at |
---|
[0eae36c7] | 17 | * http://www.rtems.com/license/LICENSE. |
---|
[07a3253d] | 18 | * |
---|
| 19 | * $Id$ |
---|
| 20 | */ |
---|
| 21 | |
---|
[9c49db4] | 22 | #if HAVE_CONFIG_H |
---|
| 23 | #include "config.h" |
---|
| 24 | #endif |
---|
| 25 | |
---|
[07a3253d] | 26 | #include <sys/types.h> |
---|
| 27 | #include <sys/stat.h> |
---|
[ebbe119e] | 28 | #include <rtems/chain.h> |
---|
[00bf6744] | 29 | #include <rtems/seterr.h> |
---|
[07a3253d] | 30 | #include <fcntl.h> |
---|
| 31 | #include <unistd.h> |
---|
| 32 | #include <errno.h> |
---|
| 33 | #include <stdlib.h> |
---|
| 34 | #include <string.h> |
---|
| 35 | #include <assert.h> |
---|
| 36 | |
---|
[3ba74c73] | 37 | #include <rtems/libio_.h> |
---|
[07a3253d] | 38 | |
---|
[29e92b0] | 39 | /* |
---|
| 40 | * Mount table list. |
---|
| 41 | */ |
---|
[00bf6744] | 42 | RTEMS_CHAIN_DEFINE_EMPTY(rtems_filesystem_mount_table_control); |
---|
[07a3253d] | 43 | |
---|
[29e92b0] | 44 | /* |
---|
| 45 | * Default pathconfs. |
---|
| 46 | */ |
---|
| 47 | const rtems_filesystem_limits_and_options_t rtems_filesystem_default_pathconf = { |
---|
| 48 | 5, /* link_max: count */ |
---|
| 49 | 128, /* max_canon: max formatted input line size */ |
---|
| 50 | 7, /* max_input: max input line size */ |
---|
| 51 | 255, /* name_max: max name */ |
---|
| 52 | 255, /* path_max: max path */ |
---|
| 53 | 1024, /* pipe_buf: pipe buffer size */ |
---|
| 54 | 0, /* posix_async_io: async IO supported on fs, 0=no, 1=yes */ |
---|
| 55 | 0 , /* posix_chown_restrictions: can chown: 0=no, 1=yes */ |
---|
| 56 | 1, /* posix_no_trunc: error on filenames > max name, 0=no, 1=yes */ |
---|
| 57 | 0, /* posix_prio_io: priority IO, 0=no, 1=yes */ |
---|
| 58 | 0, /* posix_sync_io: file can be sync'ed, 0=no, 1=yes */ |
---|
| 59 | 0 /* posix_vdisable: special char processing, 0=no, 1=yes */ |
---|
| 60 | }; |
---|
[07a3253d] | 61 | |
---|
| 62 | /* |
---|
[29e92b0] | 63 | * Is_node_fs_root |
---|
| 64 | * |
---|
| 65 | * This routine will run through the entries that currently exist in the |
---|
| 66 | * mount table chain. For each entry in the mount table chain it will |
---|
| 67 | * compare the mount tables root node to the node describing the selected |
---|
| 68 | * mount point. If any match is found true is returned else false is |
---|
| 69 | * returned. |
---|
| 70 | * |
---|
[07a3253d] | 71 | */ |
---|
| 72 | |
---|
[29e92b0] | 73 | static bool Is_node_fs_root( |
---|
[00bf6744] | 74 | rtems_filesystem_location_info_t *loc |
---|
[29e92b0] | 75 | ) |
---|
| 76 | { |
---|
[00bf6744] | 77 | rtems_chain_node *node = NULL; |
---|
[29e92b0] | 78 | |
---|
| 79 | /* |
---|
| 80 | * For each mount table entry |
---|
| 81 | */ |
---|
[00bf6744] | 82 | for ( node = rtems_chain_first( &rtems_filesystem_mount_table_control ); |
---|
| 83 | !rtems_chain_is_tail( &rtems_filesystem_mount_table_control, node ); |
---|
| 84 | node = rtems_chain_next( node ) ) { |
---|
| 85 | rtems_filesystem_mount_table_entry_t *mount_table_entry = |
---|
| 86 | (rtems_filesystem_mount_table_entry_t *) node; |
---|
| 87 | |
---|
| 88 | if ( mount_table_entry->mt_fs_root.node_access == loc->node_access ) |
---|
| 89 | return true; |
---|
[29e92b0] | 90 | } |
---|
[00bf6744] | 91 | |
---|
[29e92b0] | 92 | return false; |
---|
| 93 | } |
---|
[07a3253d] | 94 | |
---|
[00bf6744] | 95 | static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry( |
---|
| 96 | const char *source, |
---|
| 97 | const char *target, |
---|
| 98 | const char *filesystemtype, |
---|
| 99 | size_t *target_length_ptr |
---|
| 100 | ) |
---|
| 101 | { |
---|
| 102 | const char *target_str = target ? target : "/"; |
---|
| 103 | size_t filesystemtype_size = strlen( filesystemtype ) + 1; |
---|
| 104 | size_t source_size = source ? strlen( source ) + 1 : 0; |
---|
| 105 | size_t target_length = strlen( target_str ); |
---|
| 106 | size_t size = sizeof( rtems_filesystem_mount_table_entry_t ) |
---|
| 107 | + filesystemtype_size + source_size + target_length + 1; |
---|
| 108 | rtems_filesystem_mount_table_entry_t *mt_entry = calloc( 1, size ); |
---|
| 109 | |
---|
| 110 | if ( mt_entry ) { |
---|
| 111 | char *str = (char *) mt_entry + sizeof( *mt_entry ); |
---|
| 112 | |
---|
| 113 | mt_entry->type = str; |
---|
| 114 | strcpy( str, filesystemtype ); |
---|
| 115 | |
---|
| 116 | if ( source ) { |
---|
| 117 | str += filesystemtype_size; |
---|
| 118 | mt_entry->dev = str; |
---|
| 119 | strcpy( str, source ); |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | str += source_size; |
---|
| 123 | mt_entry->target = str; |
---|
| 124 | strcpy( str, target ); |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | *target_length_ptr = target_length; |
---|
| 128 | |
---|
| 129 | return mt_entry; |
---|
| 130 | } |
---|
| 131 | |
---|
[07a3253d] | 132 | /* |
---|
| 133 | * mount |
---|
| 134 | * |
---|
[50f32b11] | 135 | * This routine will attempt to mount a new file system at the specified |
---|
| 136 | * mount point. A series of tests will be run to determine if any of the |
---|
[07a3253d] | 137 | * following reasons exist to prevent the mount operation: |
---|
| 138 | * |
---|
| 139 | * 1) The file system type or options are not valid |
---|
| 140 | * 2) No new file system root node is specified |
---|
| 141 | * 3) The selected file system has already been mounted |
---|
| 142 | * 4) The mount point exists with the proper permissions to allow mounting |
---|
| 143 | * 5) The selected mount point already has a file system mounted to it |
---|
| 144 | * |
---|
| 145 | */ |
---|
| 146 | |
---|
| 147 | int mount( |
---|
[29e92b0] | 148 | const char *source, |
---|
| 149 | const char *target, |
---|
| 150 | const char *filesystemtype, |
---|
| 151 | rtems_filesystem_options_t options, |
---|
| 152 | const void *data |
---|
[00bf6744] | 153 | ) |
---|
[07a3253d] | 154 | { |
---|
[00bf6744] | 155 | rtems_filesystem_fsmount_me_t mount_h = NULL; |
---|
[d71fcab] | 156 | rtems_filesystem_location_info_t loc; |
---|
[29e92b0] | 157 | rtems_filesystem_mount_table_entry_t *mt_entry = NULL; |
---|
[04df848] | 158 | rtems_filesystem_location_info_t *loc_to_free = NULL; |
---|
[00bf6744] | 159 | bool has_target = target != NULL; |
---|
| 160 | size_t target_length = 0; |
---|
[07a3253d] | 161 | |
---|
| 162 | /* |
---|
[2f87c843] | 163 | * Are the file system options valid? |
---|
[07a3253d] | 164 | */ |
---|
| 165 | |
---|
[50f32b11] | 166 | if ( options != RTEMS_FILESYSTEM_READ_ONLY && |
---|
[00bf6744] | 167 | options != RTEMS_FILESYSTEM_READ_WRITE ) |
---|
| 168 | rtems_set_errno_and_return_minus_one( EINVAL ); |
---|
[dae3dd1] | 169 | |
---|
[29e92b0] | 170 | /* |
---|
[00bf6744] | 171 | * Get mount handler |
---|
[29e92b0] | 172 | */ |
---|
[00bf6744] | 173 | mount_h = rtems_filesystem_get_mount_handler( filesystemtype ); |
---|
| 174 | if ( !mount_h ) |
---|
| 175 | rtems_set_errno_and_return_minus_one( EINVAL ); |
---|
[dae3dd1] | 176 | |
---|
[07a3253d] | 177 | /* |
---|
[50f32b11] | 178 | * Allocate a mount table entry |
---|
[07a3253d] | 179 | */ |
---|
[00bf6744] | 180 | mt_entry = alloc_mount_table_entry( |
---|
| 181 | source, |
---|
| 182 | target, |
---|
| 183 | filesystemtype, |
---|
| 184 | &target_length |
---|
| 185 | ); |
---|
| 186 | if ( !mt_entry ) |
---|
| 187 | rtems_set_errno_and_return_minus_one( ENOMEM ); |
---|
[07a3253d] | 188 | |
---|
[29e92b0] | 189 | mt_entry->mt_fs_root.mt_entry = mt_entry; |
---|
| 190 | mt_entry->options = options; |
---|
| 191 | mt_entry->pathconf_limits_and_options = rtems_filesystem_default_pathconf; |
---|
[07a3253d] | 192 | |
---|
| 193 | /* |
---|
| 194 | * The mount_point should be a directory with read/write/execute |
---|
[50f32b11] | 195 | * permissions in the existing tree. |
---|
[07a3253d] | 196 | */ |
---|
| 197 | |
---|
[00bf6744] | 198 | if ( has_target ) { |
---|
[50f32b11] | 199 | if ( rtems_filesystem_evaluate_path( |
---|
[00bf6744] | 200 | target, target_length, RTEMS_LIBIO_PERMS_RWX, &loc, true ) == -1 ) |
---|
[04df848] | 201 | goto cleanup_and_bail; |
---|
| 202 | |
---|
[8860f103] | 203 | loc_to_free = &loc; |
---|
| 204 | |
---|
[bf61751c] | 205 | /* |
---|
| 206 | * Test for node_type_h |
---|
| 207 | */ |
---|
| 208 | |
---|
| 209 | if (!loc.ops->node_type_h) { |
---|
| 210 | errno = ENOTSUP; |
---|
| 211 | goto cleanup_and_bail; |
---|
| 212 | } |
---|
| 213 | |
---|
[50f32b11] | 214 | /* |
---|
[04df848] | 215 | * Test to see if it is a directory |
---|
| 216 | */ |
---|
| 217 | |
---|
[9c3fa30] | 218 | if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { |
---|
[50f32b11] | 219 | errno = ENOTDIR; |
---|
[04df848] | 220 | goto cleanup_and_bail; |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | /* |
---|
| 224 | * You can only mount one file system onto a single mount point. |
---|
| 225 | */ |
---|
| 226 | |
---|
[4b0d1ab] | 227 | if ( Is_node_fs_root( &loc ) ){ |
---|
[04df848] | 228 | errno = EBUSY; |
---|
| 229 | goto cleanup_and_bail; |
---|
| 230 | } |
---|
[50f32b11] | 231 | |
---|
[04df848] | 232 | /* |
---|
| 233 | * This must be a good mount point, so move the location information |
---|
| 234 | * into the allocated mount entry. Note: the information that |
---|
[50f32b11] | 235 | * may have been allocated in loc should not be sent to freenode |
---|
[04df848] | 236 | * until the system is unmounted. It may be needed to correctly |
---|
| 237 | * traverse the tree. |
---|
| 238 | */ |
---|
| 239 | |
---|
[29e92b0] | 240 | mt_entry->mt_point_node.node_access = loc.node_access; |
---|
| 241 | mt_entry->mt_point_node.handlers = loc.handlers; |
---|
| 242 | mt_entry->mt_point_node.ops = loc.ops; |
---|
| 243 | mt_entry->mt_point_node.mt_entry = loc.mt_entry; |
---|
[00bf6744] | 244 | |
---|
[50f32b11] | 245 | /* |
---|
| 246 | * This link to the parent is only done when we are dealing with system |
---|
| 247 | * below the base file system |
---|
[04df848] | 248 | */ |
---|
| 249 | |
---|
[9c3fa30] | 250 | if ( !loc.ops->mount_h ){ |
---|
[04df848] | 251 | errno = ENOTSUP; |
---|
| 252 | goto cleanup_and_bail; |
---|
| 253 | } |
---|
| 254 | |
---|
[29e92b0] | 255 | if ( loc.ops->mount_h( mt_entry ) ) { |
---|
[04df848] | 256 | goto cleanup_and_bail; |
---|
| 257 | } |
---|
| 258 | } else { |
---|
[29e92b0] | 259 | /* |
---|
| 260 | * Do we already have a base file system ? |
---|
| 261 | */ |
---|
| 262 | if ( !rtems_chain_is_empty( &rtems_filesystem_mount_table_control ) ) { |
---|
| 263 | errno = EINVAL; |
---|
| 264 | goto cleanup_and_bail; |
---|
| 265 | } |
---|
[00bf6744] | 266 | |
---|
[50f32b11] | 267 | /* |
---|
| 268 | * This is a mount of the base file system --> The |
---|
[00bf6744] | 269 | * mt_point_node.node_access will be left to null to indicate that this |
---|
[04df848] | 270 | * is the root of the entire file system. |
---|
| 271 | */ |
---|
[07a3253d] | 272 | } |
---|
| 273 | |
---|
[00bf6744] | 274 | if ( (*mount_h)( mt_entry, data ) ) { |
---|
[29e92b0] | 275 | /* |
---|
| 276 | * Try to undo the mount operation |
---|
| 277 | */ |
---|
| 278 | if ( loc.ops->unmount_h ) { |
---|
| 279 | loc.ops->unmount_h( mt_entry ); |
---|
[dae3dd1] | 280 | } |
---|
[04df848] | 281 | goto cleanup_and_bail; |
---|
[07a3253d] | 282 | } |
---|
| 283 | |
---|
| 284 | /* |
---|
[50f32b11] | 285 | * Add the mount table entry to the mount table chain |
---|
[07a3253d] | 286 | */ |
---|
[72d2ec4d] | 287 | rtems_chain_append( &rtems_filesystem_mount_table_control, |
---|
[29e92b0] | 288 | &mt_entry->Node ); |
---|
[07a3253d] | 289 | |
---|
[00bf6744] | 290 | if ( !has_target ) |
---|
[29e92b0] | 291 | rtems_filesystem_root = mt_entry->mt_fs_root; |
---|
[d71fcab] | 292 | |
---|
[07a3253d] | 293 | return 0; |
---|
| 294 | |
---|
| 295 | cleanup_and_bail: |
---|
| 296 | |
---|
[29e92b0] | 297 | free( mt_entry ); |
---|
[50f32b11] | 298 | |
---|
[04df848] | 299 | if ( loc_to_free ) |
---|
| 300 | rtems_filesystem_freenode( loc_to_free ); |
---|
| 301 | |
---|
[07a3253d] | 302 | return -1; |
---|
| 303 | } |
---|
| 304 | |
---|
[00bf6744] | 305 | /* |
---|
| 306 | * Get the first entry in the mount table. |
---|
| 307 | */ |
---|
| 308 | rtems_filesystem_mount_table_entry_t * |
---|
| 309 | rtems_filesystem_mounts_first( |
---|
| 310 | void |
---|
| 311 | ) |
---|
| 312 | { |
---|
| 313 | rtems_filesystem_mount_table_entry_t *entry = NULL; |
---|
| 314 | |
---|
| 315 | if ( !rtems_chain_is_empty( &rtems_filesystem_mount_table_control ) ) |
---|
| 316 | entry = (rtems_filesystem_mount_table_entry_t *) |
---|
| 317 | rtems_chain_first( &rtems_filesystem_mount_table_control ); |
---|
| 318 | |
---|
| 319 | return entry; |
---|
| 320 | } |
---|
| 321 | |
---|
| 322 | /* |
---|
| 323 | * Get the next entry in the mount table. |
---|
| 324 | */ |
---|
| 325 | rtems_filesystem_mount_table_entry_t * |
---|
| 326 | rtems_filesystem_mounts_next( |
---|
| 327 | rtems_filesystem_mount_table_entry_t *entry |
---|
| 328 | ) |
---|
| 329 | { |
---|
| 330 | if ( !entry ) |
---|
| 331 | return NULL; |
---|
| 332 | return (rtems_filesystem_mount_table_entry_t *) |
---|
| 333 | rtems_chain_next( &entry->Node ); |
---|
| 334 | } |
---|