Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSMedia
0007  *
0008  * @brief Media implementation.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2013 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <stdlib.h>
0037 #include <string.h>
0038 #include <assert.h>
0039 #include <unistd.h>
0040 
0041 #include <rtems/media.h>
0042 
0043 #include <rtems.h>
0044 #include <rtems/bdbuf.h>
0045 #include <rtems/blkdev.h>
0046 #include <rtems/bdpart.h>
0047 #include <rtems/libio.h>
0048 #include <rtems/dosfs.h>
0049 #include <rtems/thread.h>
0050 
0051 typedef struct {
0052   rtems_bdpart_partition *partitions;
0053   size_t *count;
0054 } partition_table;
0055 
0056 typedef struct {
0057   size_t index;
0058   rtems_blkdev_bnum begin;
0059   rtems_blkdev_bnum count;
0060 } partition;
0061 
0062 typedef struct media_item {
0063   rtems_chain_node node;
0064   struct media_item *parent;
0065   char *disk_path;
0066   char *mount_path;
0067 } media_item;
0068 
0069 typedef struct listener_item {
0070   rtems_chain_node node;
0071   rtems_media_listener listener;
0072   void *listener_arg;
0073 } listener_item;
0074 
0075 static RTEMS_CHAIN_DEFINE_EMPTY(listener_item_chain);
0076 
0077 static RTEMS_CHAIN_DEFINE_EMPTY(media_item_chain);
0078 
0079 static rtems_mutex media_mutex = RTEMS_MUTEX_INITIALIZER("Media");
0080 
0081 static void lock(void)
0082 {
0083   rtems_mutex_lock(&media_mutex);
0084 }
0085 
0086 static void unlock(void)
0087 {
0088   rtems_mutex_unlock(&media_mutex);
0089 }
0090 
0091 static listener_item *find_listener(
0092   rtems_media_listener listener,
0093   void *listener_arg
0094 )
0095 {
0096   rtems_chain_node *node = rtems_chain_first(&listener_item_chain);
0097 
0098   while (!rtems_chain_is_tail(&listener_item_chain, node)) {
0099     listener_item *item = (listener_item *) node;
0100 
0101     if (item->listener == listener && item->listener_arg == listener_arg) {
0102       return item;
0103     }
0104 
0105     node = rtems_chain_next(node);
0106   }
0107 
0108   return NULL;
0109 }
0110 
0111 rtems_status_code rtems_media_listener_add(
0112   rtems_media_listener listener,
0113   void *listener_arg
0114 )
0115 {
0116   rtems_status_code sc = RTEMS_SUCCESSFUL;
0117   listener_item *item;
0118 
0119   lock();
0120 
0121   item = find_listener(listener, listener_arg);
0122 
0123   if (item == NULL) {
0124     item = malloc(sizeof(*item));
0125     if (item != NULL) {
0126       item->listener = listener;
0127       item->listener_arg = listener_arg;
0128       rtems_chain_initialize_node(&item->node);
0129       rtems_chain_append_unprotected(&listener_item_chain, &item->node);
0130     } else {
0131       sc = RTEMS_NO_MEMORY;
0132     }
0133   } else {
0134     sc = RTEMS_TOO_MANY;
0135   }
0136 
0137   unlock();
0138 
0139   return sc;
0140 }
0141 
0142 rtems_status_code rtems_media_listener_remove(
0143   rtems_media_listener listener,
0144   void *listener_arg
0145 )
0146 {
0147   rtems_status_code sc = RTEMS_SUCCESSFUL;
0148   listener_item *item;
0149 
0150   lock();
0151 
0152   item = find_listener(listener, listener_arg);
0153 
0154   if (item != NULL) {
0155     rtems_chain_extract_unprotected(&item->node);
0156     free(item);
0157   } else {
0158     sc = RTEMS_INVALID_ID;
0159   }
0160 
0161   unlock();
0162 
0163   return sc;
0164 }
0165 
0166 static rtems_status_code notify(
0167   rtems_media_event event,
0168   rtems_media_state state,
0169   const char *src,
0170   const char *dest
0171 )
0172 {
0173   rtems_status_code sc = RTEMS_SUCCESSFUL;
0174   rtems_status_code rsc = RTEMS_SUCCESSFUL;
0175   rtems_chain_node *node = rtems_chain_first(&listener_item_chain);
0176 
0177   while (!rtems_chain_is_tail(&listener_item_chain, node)) {
0178     listener_item *item = (listener_item *) node;
0179 
0180     sc = (*item->listener)(event, state, src, dest, item->listener_arg);
0181     if (sc != RTEMS_SUCCESSFUL) {
0182       rsc = sc;
0183     }
0184 
0185     node = rtems_chain_next(node);
0186   }
0187 
0188   return rsc;
0189 }
0190 
0191 static void error(
0192   rtems_media_state state,
0193   const char *src,
0194   const char *dest
0195 )
0196 {
0197   (void) notify(RTEMS_MEDIA_EVENT_ERROR, state, src, dest);
0198 }
0199 
0200 static media_item *get_media_item(
0201   const char *disk_path,
0202   const char *mount_path
0203 )
0204 {
0205   rtems_chain_node *node = rtems_chain_first(&media_item_chain);
0206 
0207   while (!rtems_chain_is_tail(&media_item_chain, node)) {
0208     media_item *item = (media_item *) node;
0209 
0210     if (
0211       (disk_path == NULL || strcmp(disk_path, item->disk_path) == 0)
0212         && (mount_path == NULL
0213           || (item->mount_path != NULL
0214             && strcmp(mount_path, item->mount_path) == 0))
0215     ) {
0216       return item;
0217     }
0218 
0219     node = rtems_chain_next(node);
0220   }
0221 
0222   return NULL;
0223 }
0224 
0225 static void free_item(media_item *item)
0226 {
0227   rtems_chain_extract_unprotected(&item->node);
0228   free(item->mount_path);
0229   free(item);
0230 }
0231 
0232 static void create_item(
0233   media_item *parent,
0234   const char *disk_path,
0235   const char *mount_path
0236 )
0237 {
0238   size_t disk_path_size = strlen(disk_path) + 1;
0239   media_item *item = malloc(sizeof(*item) + disk_path_size);
0240 
0241   if (item != NULL) {
0242     if (mount_path != NULL) {
0243       item->mount_path = strdup(mount_path);
0244 
0245       if (item->mount_path == NULL) {
0246         free(item);
0247 
0248         return;
0249       }
0250     } else {
0251       item->mount_path = NULL;
0252     }
0253 
0254     item->parent = parent;
0255     item->disk_path = (char *) item + sizeof(*item);
0256     memcpy(item->disk_path, disk_path, disk_path_size);
0257     rtems_chain_initialize_node(&item->node);
0258     rtems_chain_append(&media_item_chain, &item->node);
0259   }
0260 }
0261 
0262 static void remove_mount_point(const char *mount_path)
0263 {
0264   media_item *item = get_media_item(NULL, mount_path);
0265 
0266   if (item != NULL) {
0267     free(item->mount_path);
0268     item->mount_path = NULL;
0269   } else {
0270     error(RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN, mount_path, NULL);
0271   }
0272 }
0273 
0274 static void remove_partition(const char *partition_path)
0275 {
0276   media_item *item = get_media_item(partition_path, NULL);
0277 
0278   if (item != NULL) {
0279     if (item->mount_path != NULL) {
0280       error(
0281         RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT,
0282         partition_path,
0283         item->mount_path
0284       );
0285     }
0286     free_item(item);
0287   } else {
0288     error(RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN, partition_path, NULL);
0289   }
0290 }
0291 
0292 static void remove_disk(const char *disk_path)
0293 {
0294   media_item *item = get_media_item(disk_path, NULL);
0295 
0296   if (item != NULL) {
0297     rtems_chain_node *node = rtems_chain_first(&media_item_chain);
0298 
0299     while (!rtems_chain_is_tail(&media_item_chain, node)) {
0300       media_item *child = (media_item *) node;
0301 
0302       node = rtems_chain_next(node);
0303 
0304       if (child->parent == item) {
0305         if (child->mount_path != NULL) {
0306           error(
0307             RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN,
0308             child->mount_path,
0309             disk_path
0310           );
0311         }
0312         error(RTEMS_MEDIA_ERROR_PARTITION_ORPHAN, child->disk_path, disk_path);
0313         free_item(child);
0314       }
0315     }
0316 
0317     free_item(item);
0318   } else {
0319     error(RTEMS_MEDIA_ERROR_DISK_UNKNOWN, disk_path, NULL);
0320   }
0321 }
0322 
0323 static void add_disk(const char *disk_path)
0324 {
0325   media_item *item = get_media_item(disk_path, NULL);
0326 
0327   if (item != NULL) {
0328     error(RTEMS_MEDIA_ERROR_DISK_EXISTS, disk_path, NULL);
0329     remove_disk(disk_path);
0330   }
0331 
0332   create_item(NULL, disk_path, NULL);
0333 }
0334 
0335 static void add_partition(const char *disk_path, const char *partition_path)
0336 {
0337   media_item *item = get_media_item(partition_path, NULL);
0338   media_item *parent = get_media_item(disk_path, NULL);
0339 
0340   if (item != NULL) {
0341     error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS, partition_path, NULL);
0342     remove_disk(partition_path);
0343   }
0344 
0345   if (parent != NULL) {
0346     create_item(parent, partition_path, NULL);
0347   } else {
0348     error(
0349       RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK,
0350       partition_path,
0351       disk_path
0352     );
0353   }
0354 }
0355 
0356 static void add_mount_point(const char *disk_path, const char *mount_path)
0357 {
0358   media_item *item = get_media_item(disk_path, NULL);
0359 
0360   if (item != NULL) {
0361     if (item->mount_path != NULL) {
0362       error(RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS, item->mount_path, NULL);
0363       free(item->mount_path);
0364     }
0365     item->mount_path = strdup(mount_path);
0366   } else {
0367     error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN, disk_path, NULL);
0368   }
0369 }
0370 
0371 static bool is_add_state(rtems_media_state state)
0372 {
0373   return state == RTEMS_MEDIA_STATE_SUCCESS;
0374 }
0375 
0376 static bool is_remove_state(rtems_media_state state)
0377 {
0378   return state == RTEMS_MEDIA_STATE_SUCCESS
0379     || state == RTEMS_MEDIA_STATE_FAILED;
0380 }
0381 
0382 static rtems_status_code remember_event(
0383   rtems_media_event event,
0384   rtems_media_state state,
0385   const char *src,
0386   const char *dest
0387 )
0388 {
0389   switch (event) {
0390     case RTEMS_MEDIA_EVENT_DISK_ATTACH:
0391       if (is_add_state(state)) {
0392         add_disk(dest);
0393       }
0394       break;
0395     case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
0396       if (is_add_state(state)) {
0397         add_partition(src, dest);
0398       }
0399       break;
0400     case RTEMS_MEDIA_EVENT_MOUNT:
0401       if (is_add_state(state)) {
0402         add_mount_point(src, dest);
0403       }
0404       break;
0405     case RTEMS_MEDIA_EVENT_UNMOUNT:
0406       if (is_remove_state(state)) {
0407         remove_mount_point(src);
0408       }
0409       break;
0410     case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
0411       if (is_remove_state(state)) {
0412         remove_partition(src);
0413       }
0414       break;
0415     case RTEMS_MEDIA_EVENT_DISK_DETACH:
0416       if (is_remove_state(state)) {
0417         remove_disk(src);
0418       }
0419       break;
0420     default:
0421       break;
0422   }
0423 
0424   return RTEMS_SUCCESSFUL;
0425 }
0426 
0427 static rtems_status_code process_event(
0428   rtems_media_event event,
0429   const char *src,
0430   char **dest_ptr,
0431   rtems_media_worker worker,
0432   void *worker_arg
0433 )
0434 {
0435   rtems_status_code sc = RTEMS_SUCCESSFUL;
0436   rtems_status_code sc_retry = RTEMS_SUCCESSFUL;
0437   rtems_media_state state;
0438   char *dest = NULL;
0439 
0440   do {
0441     sc = notify(event, RTEMS_MEDIA_STATE_INQUIRY, src, NULL);
0442     if (sc == RTEMS_SUCCESSFUL) {
0443       state = RTEMS_MEDIA_STATE_READY;
0444     } else {
0445       state = RTEMS_MEDIA_STATE_ABORTED;
0446     }
0447 
0448     sc = (*worker)(state, src, &dest, worker_arg);
0449     if (state == RTEMS_MEDIA_STATE_READY) {
0450       if (sc == RTEMS_SUCCESSFUL) {
0451         state = RTEMS_MEDIA_STATE_SUCCESS;
0452       } else {
0453         state = RTEMS_MEDIA_STATE_FAILED;
0454       }
0455     }
0456 
0457     sc_retry = notify(event, state, src, dest);
0458   } while (state == RTEMS_MEDIA_STATE_FAILED
0459     && sc_retry == RTEMS_INCORRECT_STATE);
0460   remember_event(event, state, src, dest);
0461 
0462   if (state == RTEMS_MEDIA_STATE_SUCCESS) {
0463     sc = RTEMS_SUCCESSFUL;
0464   } else if (state == RTEMS_MEDIA_STATE_ABORTED) {
0465     sc = RTEMS_UNSATISFIED;
0466   } else {
0467     sc = RTEMS_IO_ERROR;
0468   }
0469 
0470   if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
0471     *dest_ptr = dest;
0472   } else {
0473     free(dest);
0474   }
0475 
0476   return sc;
0477 }
0478 
0479 static rtems_status_code mount_worker(
0480   rtems_media_state state,
0481   const char *src,
0482   char **dest,
0483   void *worker_arg
0484 )
0485 {
0486   int rv = 0;
0487 
0488   if (state == RTEMS_MEDIA_STATE_READY) {
0489     rtems_dosfs_mount_options mount_options;
0490     char *mount_path = NULL;
0491 
0492     if (worker_arg == NULL) {
0493       mount_path = rtems_media_replace_prefix(RTEMS_MEDIA_MOUNT_BASE, src);
0494     } else {
0495       mount_path = strdup(worker_arg);
0496     }
0497 
0498     if (mount_path == NULL) {
0499       return RTEMS_IO_ERROR;
0500     }
0501 
0502     rv = rtems_mkdir(mount_path, S_IRWXU | S_IRWXG | S_IRWXO);
0503     if (rv != 0) {
0504       free(mount_path);
0505 
0506       return RTEMS_IO_ERROR;
0507     }
0508 
0509     memset(&mount_options, 0, sizeof(mount_options));
0510 
0511     /* In case this fails, we fall back to use the default converter */
0512     mount_options.converter = rtems_dosfs_create_utf8_converter("CP850");
0513 
0514     rv = mount(
0515       src,
0516       mount_path,
0517       RTEMS_FILESYSTEM_TYPE_DOSFS,
0518       RTEMS_FILESYSTEM_READ_WRITE,
0519       &mount_options
0520     );
0521     if (rv != 0) {
0522       (void) rmdir(mount_path);
0523       free(mount_path);
0524       (*mount_options.converter->handler->destroy)(mount_options.converter);
0525 
0526       return RTEMS_IO_ERROR;
0527     }
0528 
0529     *dest = mount_path;
0530   }
0531 
0532   return RTEMS_SUCCESSFUL;
0533 }
0534 
0535 static rtems_status_code do_mount(
0536   const char *src,
0537   char **dest_ptr,
0538   rtems_media_worker worker,
0539   void *worker_arg
0540 )
0541 {
0542   if (worker == NULL) {
0543     worker = mount_worker;
0544   }
0545 
0546   return process_event(
0547     RTEMS_MEDIA_EVENT_MOUNT,
0548     src,
0549     dest_ptr,
0550     worker,
0551     worker_arg
0552   );
0553 }
0554 
0555 static rtems_status_code do_partition_attach(
0556   const char *src,
0557   char **dest_ptr,
0558   rtems_media_worker worker,
0559   void *worker_arg
0560 )
0561 {
0562   rtems_status_code sc = RTEMS_SUCCESSFUL;
0563   char *part_path = NULL;
0564 
0565   if (worker != NULL) {
0566     sc = process_event(
0567       RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
0568       src,
0569       &part_path,
0570       worker,
0571       worker_arg
0572     );
0573 
0574     if (sc == RTEMS_SUCCESSFUL) {
0575       sc = do_mount(part_path, NULL, NULL, NULL);
0576     }
0577   } else {
0578     sc = RTEMS_INVALID_ADDRESS;
0579   }
0580 
0581   if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
0582     *dest_ptr = part_path;
0583   } else {
0584     free(part_path);
0585   }
0586 
0587   return sc;
0588 }
0589 
0590 static rtems_status_code partition_attach_worker(
0591   rtems_media_state state,
0592   const char *src,
0593   char **dest,
0594   void *worker_arg
0595 )
0596 {
0597   rtems_status_code sc = RTEMS_SUCCESSFUL;
0598 
0599   if (state == RTEMS_MEDIA_STATE_READY) {
0600     partition *part = worker_arg;
0601     char *part_path = rtems_media_append_minor(src, part->index);
0602 
0603     if (part_path == NULL) {
0604       return RTEMS_IO_ERROR;
0605     }
0606 
0607     sc = rtems_blkdev_create_partition(
0608       part_path,
0609       src,
0610       part->begin,
0611       part->count
0612     );
0613     if (sc != RTEMS_SUCCESSFUL) {
0614       free(part_path);
0615 
0616       return RTEMS_IO_ERROR;
0617     }
0618 
0619     *dest = part_path;
0620   }
0621 
0622   return RTEMS_SUCCESSFUL;
0623 }
0624 
0625 static rtems_status_code attach_and_mount_partitions(
0626   const char *disk_path,
0627   const rtems_bdpart_partition *partitions,
0628   size_t count
0629 )
0630 {
0631   rtems_status_code sc = RTEMS_SUCCESSFUL;
0632   size_t i = 0;
0633 
0634   for (i = 0; i < count; ++i) {
0635     partition part_desc = {
0636       .index = i,
0637       .begin = partitions [i].begin,
0638       .count = partitions [i].end - partitions [i].begin
0639     };
0640     char *part_path = NULL;
0641 
0642     sc = process_event(
0643       RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
0644       disk_path,
0645       &part_path,
0646       partition_attach_worker,
0647       &part_desc
0648     );
0649 
0650     if (sc == RTEMS_SUCCESSFUL) {
0651       sc = do_mount(part_path, NULL, NULL, NULL);
0652     }
0653 
0654     free(part_path);
0655   }
0656 
0657   return sc;
0658 }
0659 
0660 static rtems_status_code partition_inquiry_worker(
0661   rtems_media_state state,
0662   const char *src,
0663   char **dest RTEMS_UNUSED,
0664   void *worker_arg
0665 )
0666 {
0667   rtems_status_code sc = RTEMS_SUCCESSFUL;
0668 
0669   if (state == RTEMS_MEDIA_STATE_READY) {
0670     partition_table *pt = worker_arg;
0671     rtems_bdpart_format format;
0672 
0673     sc = rtems_bdpart_read(src, &format, pt->partitions, pt->count);
0674     if (sc != RTEMS_SUCCESSFUL || *pt->count == 0) {
0675       return RTEMS_IO_ERROR;
0676     }
0677   }
0678 
0679   return RTEMS_SUCCESSFUL;
0680 }
0681 
0682 static rtems_status_code do_partition_inquiry(
0683   const char *src,
0684   char **dest_ptr,
0685   rtems_media_worker worker,
0686   void *worker_arg
0687 )
0688 {
0689   rtems_status_code sc = RTEMS_SUCCESSFUL;
0690 
0691   if (worker == NULL) {
0692     rtems_bdpart_partition partitions [RTEMS_BDPART_PARTITION_NUMBER_HINT];
0693     size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT;
0694     partition_table pt = {
0695      .partitions = partitions,
0696      .count = &count
0697     };
0698 
0699     sc = process_event(
0700       RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
0701       src,
0702       dest_ptr,
0703       partition_inquiry_worker,
0704       &pt
0705     );
0706 
0707     if (sc == RTEMS_SUCCESSFUL) {
0708       sc = attach_and_mount_partitions(src, partitions, count);
0709     }
0710   } else {
0711     sc = process_event(
0712       RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
0713       src,
0714       dest_ptr,
0715       worker,
0716       worker_arg
0717     );
0718   }
0719 
0720   return sc;
0721 }
0722 
0723 static rtems_status_code do_disk_attach(
0724   const char *src,
0725   char **dest_ptr,
0726   rtems_media_worker worker,
0727   void *worker_arg
0728 )
0729 {
0730   rtems_status_code sc = RTEMS_SUCCESSFUL;
0731   rtems_status_code rsc = RTEMS_SUCCESSFUL;
0732   char *disk_path = NULL;
0733 
0734   if (worker != NULL) {
0735     rsc = process_event(
0736       RTEMS_MEDIA_EVENT_DISK_ATTACH,
0737       src,
0738       &disk_path,
0739       worker,
0740       worker_arg
0741     );
0742     
0743     if (rsc == RTEMS_SUCCESSFUL) {
0744       sc = do_mount(disk_path, NULL, NULL, NULL);
0745 
0746       if (sc != RTEMS_SUCCESSFUL) {
0747         do_partition_inquiry(disk_path, NULL, NULL, NULL);
0748       }
0749     }
0750   } else {
0751     rsc = RTEMS_INVALID_ADDRESS;
0752   }
0753 
0754   if (dest_ptr != NULL && rsc == RTEMS_SUCCESSFUL) {
0755     *dest_ptr = disk_path;
0756   } else {
0757     free(disk_path);
0758   }
0759 
0760   return rsc;
0761 }
0762 
0763 static rtems_status_code unmount_worker(
0764   rtems_media_state state,
0765   const char *src,
0766   char **dest RTEMS_UNUSED,
0767   void *worker_arg RTEMS_UNUSED
0768 )
0769 {
0770   rtems_status_code sc = RTEMS_SUCCESSFUL;
0771 
0772   if (state == RTEMS_MEDIA_STATE_READY) {
0773     int rv = unmount(src);
0774 
0775     if (rv == 0) {
0776       rv = rmdir(src);
0777       if (rv != 0) {
0778         sc = RTEMS_IO_ERROR;
0779       }
0780     } else {
0781       sc = RTEMS_IO_ERROR;
0782     }
0783   }
0784 
0785   return sc;
0786 }
0787 
0788 static rtems_status_code do_unmount(
0789   const char *src,
0790   char **dest_ptr,
0791   rtems_media_worker worker,
0792   void *worker_arg
0793 )
0794 {
0795   if (worker == NULL) {
0796     worker = unmount_worker;
0797     worker_arg = NULL;
0798   }
0799 
0800   return process_event(
0801     RTEMS_MEDIA_EVENT_UNMOUNT,
0802     src,
0803     dest_ptr,
0804     worker,
0805     worker_arg
0806   );
0807 }
0808 
0809 static rtems_status_code disk_detach_worker(
0810   rtems_media_state state,
0811   const char *src,
0812   char **dest RTEMS_UNUSED,
0813   void *worker_arg RTEMS_UNUSED
0814 )
0815 {
0816   rtems_status_code rsc = RTEMS_SUCCESSFUL;
0817 
0818   if (state == RTEMS_MEDIA_STATE_READY) {
0819     int rv = unlink(src);
0820 
0821     if (rv != 0) {
0822       rsc = RTEMS_IO_ERROR;
0823     }
0824   }
0825 
0826   return rsc;
0827 }
0828 
0829 static rtems_status_code detach_item(rtems_media_event event, media_item *item)
0830 {
0831   rtems_status_code sc = RTEMS_SUCCESSFUL;
0832   rtems_status_code rsc = RTEMS_SUCCESSFUL;
0833 
0834   if (item->mount_path != NULL) {
0835     sc = do_unmount(item->mount_path, NULL, NULL, NULL);
0836     if (sc != RTEMS_SUCCESSFUL) {
0837       rsc = RTEMS_IO_ERROR;
0838     }
0839   }
0840 
0841   sc = process_event(event, item->disk_path, NULL, disk_detach_worker, NULL);
0842   if (sc != RTEMS_SUCCESSFUL) {
0843     rsc = RTEMS_IO_ERROR;
0844   }
0845 
0846   return rsc;
0847 }
0848 
0849 static rtems_status_code detach_parent_item(media_item *parent)
0850 {
0851   rtems_status_code sc = RTEMS_SUCCESSFUL;
0852   rtems_status_code rsc = RTEMS_SUCCESSFUL;
0853 
0854   rtems_chain_node *node = rtems_chain_first(&media_item_chain);
0855 
0856   while (!rtems_chain_is_tail(&media_item_chain, node)) {
0857     media_item *child = (media_item *) node;
0858 
0859     node = rtems_chain_next(node);
0860 
0861     if (child->parent == parent) {
0862       sc = detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, child);
0863       if (sc != RTEMS_SUCCESSFUL) {
0864         rsc = RTEMS_IO_ERROR;
0865       }
0866     }
0867   }
0868 
0869   sc = detach_item(RTEMS_MEDIA_EVENT_DISK_DETACH, parent);
0870   if (sc != RTEMS_SUCCESSFUL) {
0871     rsc = RTEMS_IO_ERROR;
0872   }
0873 
0874   return rsc;
0875 }
0876 
0877 static rtems_status_code do_disk_detach(
0878   const char *src,
0879   char **dest_ptr,
0880   rtems_media_worker worker,
0881   void *worker_arg
0882 )
0883 {
0884   if (worker == NULL) {
0885     media_item *parent = get_media_item(src, NULL);
0886 
0887     if (parent != NULL) {
0888       return detach_parent_item(parent);
0889     }
0890 
0891     worker = disk_detach_worker;
0892     worker_arg = NULL;
0893   }
0894 
0895   return process_event(
0896     RTEMS_MEDIA_EVENT_DISK_DETACH,
0897     src,
0898     dest_ptr,
0899     worker,
0900     worker_arg
0901   );
0902 }
0903 
0904 static rtems_status_code do_partition_detach(
0905   const char *src,
0906   char **dest_ptr,
0907   rtems_media_worker worker,
0908   void *worker_arg
0909 )
0910 {
0911   if (worker == NULL) {
0912     media_item *item = get_media_item(src, NULL);
0913 
0914     if (item != NULL) {
0915       return detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, item);
0916     }
0917 
0918     worker = disk_detach_worker;
0919     worker_arg = NULL;
0920   }
0921 
0922   return process_event(
0923     RTEMS_MEDIA_EVENT_PARTITION_DETACH,
0924     src,
0925     dest_ptr,
0926     worker,
0927     worker_arg
0928   );
0929 }
0930 
0931 rtems_status_code rtems_media_post_event(
0932   rtems_media_event event,
0933   const char *src,
0934   char **dest_ptr,
0935   rtems_media_worker worker,
0936   void *worker_arg
0937 )
0938 {
0939   rtems_status_code sc = RTEMS_SUCCESSFUL;
0940 
0941   lock();
0942 
0943   switch (event) {
0944     case RTEMS_MEDIA_EVENT_DISK_ATTACH:
0945       sc = do_disk_attach(src, dest_ptr, worker, worker_arg);
0946       break;
0947     case RTEMS_MEDIA_EVENT_DISK_DETACH:
0948       sc = do_disk_detach(src, dest_ptr, worker, worker_arg);
0949       break;
0950     case RTEMS_MEDIA_EVENT_MOUNT:
0951       sc = do_mount(src, dest_ptr, worker, worker_arg);
0952       break;
0953     case RTEMS_MEDIA_EVENT_UNMOUNT:
0954       sc = do_unmount(src, dest_ptr, worker, worker_arg);
0955       break;
0956     case RTEMS_MEDIA_EVENT_PARTITION_INQUIRY:
0957       sc = do_partition_inquiry(src, dest_ptr, worker, worker_arg);
0958       break;
0959     case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
0960       sc = do_partition_attach(src, dest_ptr, worker, worker_arg);
0961       break;
0962     case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
0963       sc = do_partition_detach(src, dest_ptr, worker, worker_arg);
0964       break;
0965     default:
0966       sc = RTEMS_INVALID_ID;
0967       break;
0968   }
0969 
0970   unlock();
0971 
0972   return sc;
0973 }