285 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is part of MultiROM.
 | 
						|
 *
 | 
						|
 * MultiROM is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * MultiROM is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with MultiROM.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <sys/mount.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <dirent.h>
 | 
						|
 | 
						|
#include "fstab.h"
 | 
						|
#include "util.h"
 | 
						|
#include "log.h"
 | 
						|
 | 
						|
// flags from system/core/fs_mgr/fs_mgr.c
 | 
						|
struct flag_list {
 | 
						|
    const char *name;
 | 
						|
    unsigned flag;
 | 
						|
};
 | 
						|
 | 
						|
static struct flag_list mount_flags[] = {
 | 
						|
    { "noatime",    MS_NOATIME },
 | 
						|
    { "noexec",     MS_NOEXEC },
 | 
						|
    { "nosuid",     MS_NOSUID },
 | 
						|
    { "nodev",      MS_NODEV },
 | 
						|
    { "nodiratime", MS_NODIRATIME },
 | 
						|
    { "ro",         MS_RDONLY },
 | 
						|
    { "rw",         0 },
 | 
						|
    { "remount",    MS_REMOUNT },
 | 
						|
    { "bind",       MS_BIND },
 | 
						|
    { "rec",        MS_REC },
 | 
						|
    { "unbindable", MS_UNBINDABLE },
 | 
						|
    { "private",    MS_PRIVATE },
 | 
						|
    { "slave",      MS_SLAVE },
 | 
						|
    { "shared",     MS_SHARED },
 | 
						|
    { "sync",       MS_SYNCHRONOUS },
 | 
						|
    { "defaults",   0 },
 | 
						|
    { 0,            0 },
 | 
						|
};
 | 
						|
 | 
						|
struct fstab *fstab_load(const char *path)
 | 
						|
{
 | 
						|
    FILE *f = fopen(path, "r");
 | 
						|
    if(!f)
 | 
						|
    {
 | 
						|
        ERROR("Failed to open fstab %s\n", path);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    struct fstab *t = mzalloc(sizeof(struct fstab));
 | 
						|
    t->version = -1;
 | 
						|
 | 
						|
    const char *delim = " \t";
 | 
						|
    char *saveptr = NULL;
 | 
						|
    char *p;
 | 
						|
    char line[1024];
 | 
						|
    int len;
 | 
						|
    struct fstab_part *part = NULL;
 | 
						|
    while((p = fgets(line, sizeof(line), f)))
 | 
						|
    {
 | 
						|
        len = strlen(line);
 | 
						|
        if(line[len-1] == '\n')
 | 
						|
            line[len-1] = 0;
 | 
						|
 | 
						|
        while(isspace(*p))
 | 
						|
            ++p;
 | 
						|
 | 
						|
        if(*p == '#' || *p == 0)
 | 
						|
            continue;
 | 
						|
 | 
						|
        part = mzalloc(sizeof(struct fstab_part));
 | 
						|
 | 
						|
        if(!(p = strtok_r(line, delim, &saveptr)))
 | 
						|
        {
 | 
						|
            ERROR("Error first token\n");
 | 
						|
            goto fail;
 | 
						|
        }
 | 
						|
 | 
						|
        if(t->version == -1)
 | 
						|
        {
 | 
						|
            if(strstr(p, "/dev/") == p) t->version = 2;
 | 
						|
            else                        t->version = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if(t->version == 2)
 | 
						|
            part->device = readlink_recursive(p);
 | 
						|
        else
 | 
						|
            part->path = strdup (p);
 | 
						|
 | 
						|
        if(!(p = strtok_r(NULL, delim, &saveptr)))
 | 
						|
        {
 | 
						|
            ERROR("Error second token\n");
 | 
						|
            goto fail;
 | 
						|
        }
 | 
						|
 | 
						|
        if(t->version == 2)
 | 
						|
            part->path = strdup(p);
 | 
						|
        else
 | 
						|
            part->type = strdup(p);
 | 
						|
 | 
						|
        if(!(p = strtok_r(NULL, delim, &saveptr)))
 | 
						|
        {
 | 
						|
            ERROR("Error third token\n");
 | 
						|
            goto fail;
 | 
						|
        }
 | 
						|
 | 
						|
        if(t->version == 2)
 | 
						|
            part->type = strdup(p);
 | 
						|
        else
 | 
						|
            part->device = readlink_recursive(p);
 | 
						|
 | 
						|
        if((p = strtok_r(NULL, delim, &saveptr)))
 | 
						|
            fstab_parse_options(p, part);
 | 
						|
 | 
						|
        if((p = strtok_r(NULL, delim, &saveptr)))
 | 
						|
            part->options2 = strdup(p);
 | 
						|
 | 
						|
        // Check device
 | 
						|
        if(!part->device)
 | 
						|
        {
 | 
						|
            ERROR("fstab: device for part %s does not exist!\n", part->path);
 | 
						|
            fstab_destroy_part(part);
 | 
						|
            part = NULL;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        list_add(part, &t->parts);
 | 
						|
        ++t->count;
 | 
						|
        part = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return t;
 | 
						|
 | 
						|
fail:
 | 
						|
    fclose(f);
 | 
						|
    free(part);
 | 
						|
    fstab_destroy(t);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void fstab_destroy(struct fstab *f)
 | 
						|
{
 | 
						|
    list_clear(&f->parts, fstab_destroy_part);
 | 
						|
    free(f);
 | 
						|
}
 | 
						|
 | 
						|
void fstab_destroy_part(struct fstab_part *p)
 | 
						|
{
 | 
						|
    free(p->path);
 | 
						|
    free(p->type);
 | 
						|
    free(p->device);
 | 
						|
    free(p->options);
 | 
						|
    free(p->options2);
 | 
						|
    free(p);
 | 
						|
}
 | 
						|
 | 
						|
void fstab_dump(struct fstab *f)
 | 
						|
{
 | 
						|
    INFO("Dumping fstab:\n");
 | 
						|
    INFO("version: %d\n", f->version);
 | 
						|
    INFO("count: %d\n", f->count);
 | 
						|
 | 
						|
    int i;
 | 
						|
    for(i = 0; i < f->count; ++i)
 | 
						|
    {
 | 
						|
        INFO("Partition %d:\n", i);
 | 
						|
        INFO("    path: %s\n", f->parts[i]->path);
 | 
						|
        INFO("    device: %s\n", f->parts[i]->device);
 | 
						|
        INFO("    type: %s\n", f->parts[i]->type);
 | 
						|
        INFO("    mountflags: 0x%lX\n", f->parts[i]->mountflags);
 | 
						|
        INFO("    options: %s\n", f->parts[i]->options);
 | 
						|
        INFO("    options2: %s\n", f->parts[i]->options2);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
struct fstab_part *fstab_find_by_path(struct fstab *f, const char *path)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    for(i = 0; i < f->count; ++i)
 | 
						|
        if(strcmp(f->parts[i]->path, path) == 0)
 | 
						|
            return f->parts[i];
 | 
						|
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void fstab_parse_options(char *opt, struct fstab_part *part)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    char *p;
 | 
						|
    char *saveptr = NULL;
 | 
						|
 | 
						|
    part->options = malloc(strlen(opt) + 2); // NULL and possible trailing comma
 | 
						|
    part->options[0] = 0;
 | 
						|
 | 
						|
    p = strtok_r(opt, ",", &saveptr);
 | 
						|
    while(p)
 | 
						|
    {
 | 
						|
        for(i = 0; mount_flags[i].name; ++i)
 | 
						|
        {
 | 
						|
            if(strcmp(mount_flags[i].name, p) == 0)
 | 
						|
            {
 | 
						|
                part->mountflags |= mount_flags[i].flag;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if(!mount_flags[i].name)
 | 
						|
        {
 | 
						|
            strcat(part->options, p);
 | 
						|
            strcat(part->options, ",");
 | 
						|
        }
 | 
						|
 | 
						|
        p = strtok_r(NULL, ",", &saveptr);
 | 
						|
    }
 | 
						|
 | 
						|
    int len = strlen(part->options);
 | 
						|
    if(len != 0)
 | 
						|
    {
 | 
						|
        part->options[len-1] = 0; // remove trailing comma
 | 
						|
        part->options = realloc(part->options, len);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        free(part->options);
 | 
						|
        part->options = NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
struct fstab *fstab_auto_load(void)
 | 
						|
{
 | 
						|
    char path[64];
 | 
						|
    path[0] = 0;
 | 
						|
 | 
						|
    if(access("/mrom.fstab", F_OK) >= 0)
 | 
						|
        strcpy(path, "/mrom.fstab");
 | 
						|
    else
 | 
						|
    {
 | 
						|
        DIR *d = opendir("/");
 | 
						|
        if(!d)
 | 
						|
        {
 | 
						|
            ERROR("Failed to open /\n");
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        struct dirent *dt;
 | 
						|
        while((dt = readdir(d)))
 | 
						|
        {
 | 
						|
            if(dt->d_type != DT_REG)
 | 
						|
                continue;
 | 
						|
 | 
						|
            if(strncmp(dt->d_name, "fstab.", sizeof("fstab.")-1) == 0)
 | 
						|
            {
 | 
						|
                strcpy(path, "/");
 | 
						|
                strcat(path, dt->d_name);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        closedir(d);
 | 
						|
    }
 | 
						|
 | 
						|
    if(path[0] == 0)
 | 
						|
    {
 | 
						|
        ERROR("Failed to find fstab!\n");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    ERROR("Loading fstab \"%s\"...\n", path);
 | 
						|
    return fstab_load(path);
 | 
						|
}
 |