| 1 | /*
 | 
|---|
| 2 |  * Copyright (c) 2025 Jiri Svoboda
 | 
|---|
| 3 |  * All rights reserved.
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  * Redistribution and use in source and binary forms, with or without
 | 
|---|
| 6 |  * modification, are permitted provided that the following conditions
 | 
|---|
| 7 |  * are met:
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * - Redistributions of source code must retain the above copyright
 | 
|---|
| 10 |  *   notice, this list of conditions and the following disclaimer.
 | 
|---|
| 11 |  * - Redistributions in binary form must reproduce the above copyright
 | 
|---|
| 12 |  *   notice, this list of conditions and the following disclaimer in the
 | 
|---|
| 13 |  *   documentation and/or other materials provided with the distribution.
 | 
|---|
| 14 |  * - The name of the author may not be used to endorse or promote products
 | 
|---|
| 15 |  *   derived from this software without specific prior written permission.
 | 
|---|
| 16 |  *
 | 
|---|
| 17 |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
|---|
| 18 |  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
|---|
| 19 |  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
|---|
| 20 |  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
|---|
| 21 |  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
|---|
| 22 |  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
|---|
| 23 |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
|---|
| 24 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
|---|
| 25 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
|---|
| 26 |  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
|---|
| 27 |  */
 | 
|---|
| 28 | 
 | 
|---|
| 29 | /** @addtogroup sysinst
 | 
|---|
| 30 |  * @{
 | 
|---|
| 31 |  */
 | 
|---|
| 32 | /** @file RAM disk image manipulation
 | 
|---|
| 33 |  */
 | 
|---|
| 34 | 
 | 
|---|
| 35 | #include <errno.h>
 | 
|---|
| 36 | #include <fibril.h>
 | 
|---|
| 37 | #include <io/log.h>
 | 
|---|
| 38 | #include <stdio.h>
 | 
|---|
| 39 | #include <stdlib.h>
 | 
|---|
| 40 | #include <str.h>
 | 
|---|
| 41 | #include <task.h>
 | 
|---|
| 42 | #include <vfs/vfs.h>
 | 
|---|
| 43 | #include <vol.h>
 | 
|---|
| 44 | 
 | 
|---|
| 45 | #include "rdimg.h"
 | 
|---|
| 46 | 
 | 
|---|
| 47 | #define FILE_BD "/srv/bd/file_bd"
 | 
|---|
| 48 | #define RD_SVC "bd/iird"
 | 
|---|
| 49 | #define RD_LABEL "HelenOS-rd"
 | 
|---|
| 50 | 
 | 
|---|
| 51 | /** Find volume by volume label. */
 | 
|---|
| 52 | static errno_t rd_img_part_by_label(vol_t *vol, const char *label,
 | 
|---|
| 53 |     service_id_t *rid)
 | 
|---|
| 54 | {
 | 
|---|
| 55 |         vol_part_info_t vinfo;
 | 
|---|
| 56 |         service_id_t *part_ids = NULL;
 | 
|---|
| 57 |         size_t nparts;
 | 
|---|
| 58 |         size_t i;
 | 
|---|
| 59 |         errno_t rc;
 | 
|---|
| 60 | 
 | 
|---|
| 61 |         rc = vol_get_parts(vol, &part_ids, &nparts);
 | 
|---|
| 62 |         if (rc != EOK) {
 | 
|---|
| 63 |                 log_msg(LOG_DEFAULT, LVL_ERROR,
 | 
|---|
| 64 |                     "Error getting list of volumes.");
 | 
|---|
| 65 |                 goto out;
 | 
|---|
| 66 |         }
 | 
|---|
| 67 | 
 | 
|---|
| 68 |         for (i = 0; i < nparts; i++) {
 | 
|---|
| 69 |                 rc = vol_part_info(vol, part_ids[i], &vinfo);
 | 
|---|
| 70 |                 if (rc != EOK) {
 | 
|---|
| 71 |                         log_msg(LOG_DEFAULT, LVL_ERROR,
 | 
|---|
| 72 |                             "Error getting volume information.");
 | 
|---|
| 73 |                         rc = EIO;
 | 
|---|
| 74 |                         goto out;
 | 
|---|
| 75 |                 }
 | 
|---|
| 76 | 
 | 
|---|
| 77 |                 if (str_cmp(vinfo.label, label) == 0) {
 | 
|---|
| 78 |                         *rid = part_ids[i];
 | 
|---|
| 79 |                         rc = EOK;
 | 
|---|
| 80 |                         goto out;
 | 
|---|
| 81 |                 }
 | 
|---|
| 82 |         }
 | 
|---|
| 83 | 
 | 
|---|
| 84 |         rc = ENOENT;
 | 
|---|
| 85 | out:
 | 
|---|
| 86 |         free(part_ids);
 | 
|---|
| 87 |         return rc;
 | 
|---|
| 88 | }
 | 
|---|
| 89 | 
 | 
|---|
| 90 | /** Open RAM disk image.
 | 
|---|
| 91 |  *
 | 
|---|
| 92 |  * @param imgpath Image path
 | 
|---|
| 93 |  * @param rpath Place to store pointer to newly allocated string, the path to
 | 
|---|
| 94 |  *              the mounted RAM disk.
 | 
|---|
| 95 |  * @param rimg Place to store pointer to newly allocated object.
 | 
|---|
| 96 |  *
 | 
|---|
| 97 |  * @return EOK on success or an error code
 | 
|---|
| 98 |  */
 | 
|---|
| 99 | errno_t rd_img_open(const char *imgpath, char **rpath, rd_img_t **rimg)
 | 
|---|
| 100 | {
 | 
|---|
| 101 |         rd_img_t *img = NULL;
 | 
|---|
| 102 |         char *rdpath = NULL;
 | 
|---|
| 103 |         errno_t rc;
 | 
|---|
| 104 |         task_id_t id;
 | 
|---|
| 105 |         task_wait_t wait;
 | 
|---|
| 106 |         task_exit_t texit;
 | 
|---|
| 107 |         vfs_stat_t stat;
 | 
|---|
| 108 |         int retval;
 | 
|---|
| 109 |         int cnt;
 | 
|---|
| 110 | 
 | 
|---|
| 111 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_open: begin");
 | 
|---|
| 112 | 
 | 
|---|
| 113 |         rdpath = str_dup("/vol/" RD_LABEL);
 | 
|---|
| 114 |         if (rdpath == NULL) {
 | 
|---|
| 115 |                 rc = ENOMEM;
 | 
|---|
| 116 |                 goto error;
 | 
|---|
| 117 |         }
 | 
|---|
| 118 | 
 | 
|---|
| 119 |         img = calloc(1, sizeof(rd_img_t));
 | 
|---|
| 120 |         if (img == NULL) {
 | 
|---|
| 121 |                 rc = ENOMEM;
 | 
|---|
| 122 |                 goto error;
 | 
|---|
| 123 |         }
 | 
|---|
| 124 | 
 | 
|---|
| 125 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_open: spawn file_bd");
 | 
|---|
| 126 |         rc = task_spawnl(&id, &wait, FILE_BD, FILE_BD, imgpath, RD_SVC, NULL);
 | 
|---|
| 127 |         if (rc != EOK) {
 | 
|---|
| 128 |                 rc = EIO;
 | 
|---|
| 129 |                 goto error;
 | 
|---|
| 130 |         }
 | 
|---|
| 131 | 
 | 
|---|
| 132 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_open: wait for file_bd");
 | 
|---|
| 133 |         rc = task_wait(&wait, &texit, &retval);
 | 
|---|
| 134 |         if (rc != EOK || texit != TASK_EXIT_NORMAL) {
 | 
|---|
| 135 |                 rc = EIO;
 | 
|---|
| 136 |                 goto error;
 | 
|---|
| 137 |         }
 | 
|---|
| 138 | 
 | 
|---|
| 139 |         /* Wait for the RAM disk to become available */
 | 
|---|
| 140 |         log_msg(LOG_DEFAULT, LVL_NOTE,
 | 
|---|
| 141 |             "rd_img_open: wait for RAM disk to be mounted");
 | 
|---|
| 142 |         cnt = 10;
 | 
|---|
| 143 |         while (cnt > 0) {
 | 
|---|
| 144 |                 rc = vfs_stat_path(rdpath, &stat);
 | 
|---|
| 145 |                 if (rc == EOK)
 | 
|---|
| 146 |                         break;
 | 
|---|
| 147 | 
 | 
|---|
| 148 |                 fibril_sleep(1);
 | 
|---|
| 149 |                 --cnt;
 | 
|---|
| 150 |         }
 | 
|---|
| 151 | 
 | 
|---|
| 152 |         if (cnt == 0) {
 | 
|---|
| 153 |                 log_msg(LOG_DEFAULT, LVL_ERROR, "rd_img_open: ran out of time");
 | 
|---|
| 154 |                 rc = EIO;
 | 
|---|
| 155 |                 goto error;
 | 
|---|
| 156 |         }
 | 
|---|
| 157 | 
 | 
|---|
| 158 |         img->filebd_tid = id;
 | 
|---|
| 159 |         *rimg = img;
 | 
|---|
| 160 |         *rpath = rdpath;
 | 
|---|
| 161 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_open: success");
 | 
|---|
| 162 |         return EOK;
 | 
|---|
| 163 | error:
 | 
|---|
| 164 |         if (rdpath != NULL)
 | 
|---|
| 165 |                 free(rdpath);
 | 
|---|
| 166 |         if (img != NULL)
 | 
|---|
| 167 |                 free(img);
 | 
|---|
| 168 |         return rc;
 | 
|---|
| 169 | }
 | 
|---|
| 170 | 
 | 
|---|
| 171 | /** Close RAM disk image.
 | 
|---|
| 172 |  *
 | 
|---|
| 173 |  */
 | 
|---|
| 174 | errno_t rd_img_close(rd_img_t *img)
 | 
|---|
| 175 | {
 | 
|---|
| 176 |         errno_t rc;
 | 
|---|
| 177 |         service_id_t rd_svcid;
 | 
|---|
| 178 |         vol_t *vol = NULL;
 | 
|---|
| 179 | 
 | 
|---|
| 180 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_close: begin");
 | 
|---|
| 181 | 
 | 
|---|
| 182 |         rc = vol_create(&vol);
 | 
|---|
| 183 |         if (rc != EOK) {
 | 
|---|
| 184 |                 log_msg(LOG_DEFAULT, LVL_ERROR,
 | 
|---|
| 185 |                     "Error opening volume management service.");
 | 
|---|
| 186 |                 rc = EIO;
 | 
|---|
| 187 |                 goto error;
 | 
|---|
| 188 |         }
 | 
|---|
| 189 | 
 | 
|---|
| 190 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_close: Find RAM disk volume.");
 | 
|---|
| 191 |         rc = rd_img_part_by_label(vol, RD_LABEL, &rd_svcid);
 | 
|---|
| 192 |         if (rc != EOK) {
 | 
|---|
| 193 |                 log_msg(LOG_DEFAULT, LVL_ERROR,
 | 
|---|
| 194 |                     "Error getting RAM disk service ID.");
 | 
|---|
| 195 |                 rc = EIO;
 | 
|---|
| 196 |                 goto error;
 | 
|---|
| 197 |         }
 | 
|---|
| 198 | 
 | 
|---|
| 199 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_close: eject RAM disk volume");
 | 
|---|
| 200 |         rc = vol_part_eject(vol, rd_svcid, vef_none);
 | 
|---|
| 201 |         if (rc != EOK) {
 | 
|---|
| 202 |                 log_msg(LOG_DEFAULT, LVL_ERROR,
 | 
|---|
| 203 |                     "Error ejecting RAM disk volume.");
 | 
|---|
| 204 |                 rc = EIO;
 | 
|---|
| 205 |                 goto error;
 | 
|---|
| 206 |         }
 | 
|---|
| 207 | 
 | 
|---|
| 208 |         vol_destroy(vol);
 | 
|---|
| 209 | 
 | 
|---|
| 210 |         rc = task_kill(img->filebd_tid);
 | 
|---|
| 211 |         if (rc != EOK) {
 | 
|---|
| 212 |                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error killing file_bd.");
 | 
|---|
| 213 |                 rc = EIO;
 | 
|---|
| 214 |                 goto error;
 | 
|---|
| 215 |         }
 | 
|---|
| 216 | 
 | 
|---|
| 217 |         free(img);
 | 
|---|
| 218 |         log_msg(LOG_DEFAULT, LVL_NOTE, "rd_img_close: success");
 | 
|---|
| 219 |         return EOK;
 | 
|---|
| 220 | error:
 | 
|---|
| 221 |         free(img);
 | 
|---|
| 222 |         if (vol != NULL)
 | 
|---|
| 223 |                 vol_destroy(vol);
 | 
|---|
| 224 |         return rc;
 | 
|---|
| 225 | }
 | 
|---|
| 226 | 
 | 
|---|
| 227 | /** @}
 | 
|---|
| 228 |  */
 | 
|---|