diff options
Diffstat (limited to 'mtdutils/mounts.c')
-rw-r--r-- | mtdutils/mounts.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/mtdutils/mounts.c b/mtdutils/mounts.c new file mode 100644 index 0000000..2ab3ff6 --- /dev/null +++ b/mtdutils/mounts.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/mount.h> + +#include "mounts.h" + +struct MountedVolume { + const char *device; + const char *mount_point; + const char *filesystem; + const char *flags; +}; + +typedef struct { + MountedVolume *volumes; + int volumes_allocd; + int volume_count; +} MountsState; + +static MountsState g_mounts_state = { + NULL, // volumes + 0, // volumes_allocd + 0 // volume_count +}; + +static inline void +free_volume_internals(const MountedVolume *volume, int zero) +{ + free((char *)volume->device); + free((char *)volume->mount_point); + free((char *)volume->filesystem); + free((char *)volume->flags); + if (zero) { + memset((void *)volume, 0, sizeof(*volume)); + } +} + +#define PROC_MOUNTS_FILENAME "/proc/mounts" + +int +scan_mounted_volumes() +{ + char buf[2048]; + const char *bufp; + int fd; + ssize_t nbytes; + + if (g_mounts_state.volumes == NULL) { + const int numv = 32; + MountedVolume *volumes = malloc(numv * sizeof(*volumes)); + if (volumes == NULL) { + errno = ENOMEM; + return -1; + } + g_mounts_state.volumes = volumes; + g_mounts_state.volumes_allocd = numv; + memset(volumes, 0, numv * sizeof(*volumes)); + } else { + /* Free the old volume strings. + */ + int i; + for (i = 0; i < g_mounts_state.volume_count; i++) { + free_volume_internals(&g_mounts_state.volumes[i], 1); + } + } + g_mounts_state.volume_count = 0; + + /* Open and read the file contents. + */ + fd = open(PROC_MOUNTS_FILENAME, O_RDONLY); + if (fd < 0) { + goto bail; + } + nbytes = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (nbytes < 0) { + goto bail; + } + buf[nbytes] = '\0'; + + /* Parse the contents of the file, which looks like: + * + * # cat /proc/mounts + * rootfs / rootfs rw 0 0 + * /dev/pts /dev/pts devpts rw 0 0 + * /proc /proc proc rw 0 0 + * /sys /sys sysfs rw 0 0 + * /dev/block/mtdblock4 /system yaffs2 rw,nodev,noatime,nodiratime 0 0 + * /dev/block/mtdblock5 /data yaffs2 rw,nodev,noatime,nodiratime 0 0 + * /dev/block/mmcblk0p1 /sdcard vfat rw,sync,dirsync,fmask=0000,dmask=0000,codepage=cp437,iocharset=iso8859-1,utf8 0 0 + * + * The zeroes at the end are dummy placeholder fields to make the + * output match Linux's /etc/mtab, but don't represent anything here. + */ + bufp = buf; + while (nbytes > 0) { + char device[64]; + char mount_point[64]; + char filesystem[64]; + char flags[128]; + int matches; + + /* %as is a gnu extension that malloc()s a string for each field. + */ + matches = sscanf(bufp, "%63s %63s %63s %127s", + device, mount_point, filesystem, flags); + + if (matches == 4) { + device[sizeof(device)-1] = '\0'; + mount_point[sizeof(mount_point)-1] = '\0'; + filesystem[sizeof(filesystem)-1] = '\0'; + flags[sizeof(flags)-1] = '\0'; + + MountedVolume *v = + &g_mounts_state.volumes[g_mounts_state.volume_count++]; + v->device = strdup(device); + v->mount_point = strdup(mount_point); + v->filesystem = strdup(filesystem); + v->flags = strdup(flags); + } else { +printf("matches was %d on <<%.40s>>\n", matches, bufp); + } + + /* Eat the line. + */ + while (nbytes > 0 && *bufp != '\n') { + bufp++; + nbytes--; + } + if (nbytes > 0) { + bufp++; + nbytes--; + } + } + + return 0; + +bail: +//TODO: free the strings we've allocated. + g_mounts_state.volume_count = 0; + return -1; +} + +const MountedVolume * +find_mounted_volume_by_device(const char *device) +{ + if (g_mounts_state.volumes != NULL) { + int i; + for (i = 0; i < g_mounts_state.volume_count; i++) { + MountedVolume *v = &g_mounts_state.volumes[i]; + /* May be null if it was unmounted and we haven't rescanned. + */ + if (v->device != NULL) { + if (strcmp(v->device, device) == 0) { + return v; + } + } + } + } + return NULL; +} + +const MountedVolume * +find_mounted_volume_by_mount_point(const char *mount_point) +{ + if (g_mounts_state.volumes != NULL) { + int i; + for (i = 0; i < g_mounts_state.volume_count; i++) { + MountedVolume *v = &g_mounts_state.volumes[i]; + /* May be null if it was unmounted and we haven't rescanned. + */ + if (v->mount_point != NULL) { + if (strcmp(v->mount_point, mount_point) == 0) { + return v; + } + } + } + } + return NULL; +} + +int +unmount_mounted_volume(const MountedVolume *volume) +{ + /* Intentionally pass NULL to umount if the caller tries + * to unmount a volume they already unmounted using this + * function. + */ + int ret = umount(volume->mount_point); + if (ret == 0) { + free_volume_internals(volume, 1); + return 0; + } + return ret; +} |