summaryrefslogtreecommitdiff
path: root/acpi/acpifs.c
diff options
context:
space:
mode:
Diffstat (limited to 'acpi/acpifs.c')
-rw-r--r--acpi/acpifs.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/acpi/acpifs.c b/acpi/acpifs.c
new file mode 100644
index 00000000..e779e0f9
--- /dev/null
+++ b/acpi/acpifs.c
@@ -0,0 +1,265 @@
+/*
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.
+*/
+
+/* ACPI Filesystem implementation */
+
+#include <acpifs.h>
+
+#include <error.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <hurd/netfs.h>
+
+#include <ncache.h>
+#include <func_files.h>
+
+static error_t
+create_dir_entry (char *name, struct acpi_table *t,
+ struct acpifs_dirent *parent, io_statbuf_t stat,
+ struct node *node, struct acpifs_dirent *entry)
+{
+ uint16_t parent_num_entries;
+
+ strncpy (entry->name, name, NAME_SIZE);
+ entry->acpitable = t;
+ entry->parent = parent;
+ entry->stat = stat;
+ entry->dir = 0;
+ entry->node = node;
+
+ /* Update parent's child list */
+ if (entry->parent)
+ {
+ if (!entry->parent->dir)
+ {
+ /* First child */
+ entry->parent->dir = calloc (1, sizeof (struct acpifs_dir));
+ if (!entry->parent->dir)
+ return ENOMEM;
+ }
+
+ parent_num_entries = entry->parent->dir->num_entries++;
+ entry->parent->dir->entries = realloc (entry->parent->dir->entries,
+ entry->parent->dir->num_entries *
+ sizeof (struct acpifs_dirent *));
+ if (!entry->parent->dir->entries)
+ return ENOMEM;
+ entry->parent->dir->entries[parent_num_entries] = entry;
+ }
+
+ return 0;
+}
+
+error_t
+alloc_file_system (struct acpifs **fs)
+{
+ *fs = calloc (1, sizeof (struct acpifs));
+ if (!*fs)
+ return ENOMEM;
+
+ return 0;
+}
+
+error_t
+init_file_system (file_t underlying_node, struct acpifs *fs)
+{
+ error_t err;
+ struct node *np;
+ io_statbuf_t underlying_node_stat;
+
+ /* Initialize status from underlying node. */
+ err = io_stat (underlying_node, &underlying_node_stat);
+ if (err)
+ return err;
+
+ np = netfs_make_node_alloc (sizeof (struct netnode));
+ if (!np)
+ return ENOMEM;
+ np->nn_stat = underlying_node_stat;
+ np->nn_stat.st_fsid = getpid ();
+ np->nn_stat.st_mode =
+ S_IFDIR | S_IROOT | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH |
+ S_IXOTH;
+ np->nn_translated = np->nn_stat.st_mode;
+
+ /* Set times to now */
+ fshelp_touch (&np->nn_stat, TOUCH_ATIME | TOUCH_MTIME | TOUCH_CTIME,
+ acpifs_maptime);
+
+ fs->entries = calloc (1, sizeof (struct acpifs_dirent));
+ if (!fs->entries)
+ {
+ free (fs->entries);
+ return ENOMEM;
+ }
+
+ /* Create the root entry */
+ err = create_dir_entry ("", 0, 0, np->nn_stat, np, fs->entries);
+
+ fs->num_entries = 1;
+ fs->root = netfs_root_node = np;
+ fs->root->nn->ln = fs->entries;
+ pthread_mutex_init (&fs->node_cache_lock, 0);
+
+ return 0;
+}
+
+error_t
+create_fs_tree (struct acpifs *fs)
+{
+ error_t err = 0;
+ int i;
+ size_t nentries, ntables = 0;
+ struct acpifs_dirent *e, *list, *parent;
+ struct stat e_stat;
+ char entry_name[NAME_SIZE];
+ struct acpi_table *iter = NULL;
+
+ /* Copy the root stat */
+ e_stat = fs->entries->stat;
+
+ err = acpi_get_num_tables(&ntables);
+ if (err)
+ return err;
+
+ /* Allocate enough for / + "tables"/ + each table */
+ nentries = ntables + 2;
+
+ list = realloc (fs->entries, nentries * sizeof (struct acpifs_dirent));
+ if (!list) {
+ if (fs->entries)
+ free(fs->entries);
+ return ENOMEM;
+ }
+
+ e = list + 1;
+ parent = list;
+ e_stat.st_mode &= ~S_IROOT; /* Remove the root mode */
+ memset (entry_name, 0, NAME_SIZE);
+ strncpy (entry_name, DIR_TABLES_NAME, NAME_SIZE);
+
+ err = create_dir_entry (entry_name, 0, parent, e_stat, 0, e);
+ if (err)
+ return err;
+
+ parent = e;
+
+ /* Remove all permissions to others */
+ e_stat.st_mode &= ~(S_IROTH | S_IWOTH | S_IXOTH);
+
+ /* Change mode to a regular read-only file */
+ e_stat.st_mode &= ~(S_IFDIR | S_IXUSR | S_IXGRP | S_IWUSR | S_IWGRP);
+ e_stat.st_mode |= S_IFREG;
+
+ /* Get all ACPI tables */
+ err = acpi_get_tables(&iter);
+ if (err)
+ return err;
+
+ for (i = 0; i < ntables; i++, iter++)
+ {
+ e_stat.st_size = iter->datalen;
+
+ // Create ACPI table entry
+ memset (entry_name, 0, NAME_SIZE);
+
+ snprintf (entry_name, NAME_SIZE, "%c%c%c%c",
+ iter->h.signature[0],
+ iter->h.signature[1],
+ iter->h.signature[2],
+ iter->h.signature[3]);
+ e++;
+ err = create_dir_entry (entry_name, iter, parent, e_stat, 0, e);
+ if (err)
+ return err;
+ }
+
+ /* The root node points to the first element of the entry list */
+ fs->entries = list;
+ fs->num_entries = nentries;
+ fs->root->nn->ln = fs->entries;
+
+ return err;
+}
+
+error_t
+entry_check_perms (struct iouser *user, struct acpifs_dirent *e, int flags)
+{
+ error_t err = 0;
+
+ if (!err && (flags & O_READ))
+ err = fshelp_access (&e->stat, S_IREAD, user);
+ if (!err && (flags & O_WRITE))
+ err = fshelp_access (&e->stat, S_IWRITE, user);
+ if (!err && (flags & O_EXEC))
+ err = fshelp_access (&e->stat, S_IEXEC, user);
+
+ return err;
+}
+
+/* Set default permissions to the given entry */
+static void
+entry_default_perms (struct acpifs *fs, struct acpifs_dirent *e)
+{
+ /* Set default owner and group */
+ UPDATE_OWNER (e, fs->root->nn->ln->stat.st_uid);
+ UPDATE_GROUP (e, fs->root->nn->ln->stat.st_gid);
+
+ /* Update ctime */
+ UPDATE_TIMES (e, TOUCH_CTIME);
+
+ return;
+}
+
+static void
+entry_set_perms (struct acpifs *fs, struct acpifs_dirent *e)
+{
+ struct acpifs_perm *perm = &fs->perm;
+ if (perm->uid >= 0)
+ UPDATE_OWNER (e, perm->uid);
+ if (perm->gid >= 0)
+ UPDATE_GROUP (e, perm->gid);
+
+ /* Update ctime */
+ UPDATE_TIMES (e, TOUCH_CTIME);
+
+ return;
+}
+
+/* Update all entries' permissions */
+error_t
+fs_set_permissions (struct acpifs *fs)
+{
+ int i;
+ struct acpifs_dirent *e;
+
+ for (i = 0, e = fs->entries; i < fs->num_entries; i++, e++)
+ {
+ /* Restore default perms, as this may be called from fsysopts */
+ entry_default_perms (fs, e);
+
+ /* Set new permissions, if any */
+ entry_set_perms (fs, e);
+ }
+
+ return 0;
+}