summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dircat.c99
-rw-r--r--dircat.h9
-rw-r--r--main.c41
-rw-r--r--procfs.c8
-rw-r--r--procfs.h8
-rw-r--r--proclist.c1
6 files changed, 156 insertions, 10 deletions
diff --git a/dircat.c b/dircat.c
new file mode 100644
index 00000000..857ba72b
--- /dev/null
+++ b/dircat.c
@@ -0,0 +1,99 @@
+#include <stdlib.h>
+#include <string.h>
+#include "procfs.h"
+
+struct dircat_node
+{
+ struct node **dirs;
+};
+
+static error_t
+dircat_get_contents (void *hook, void **contents, size_t *contents_len)
+{
+ struct dircat_node *dcn = hook;
+ int i, sz, pos;
+ error_t err;
+
+ pos = 0;
+ *contents = malloc (sz = 512);
+
+ for (i=0; dcn->dirs[i]; i++)
+ {
+ void *subcon;
+ size_t sublen;
+
+ err = procfs_get_contents (dcn->dirs[i], &subcon, &sublen);
+ if (err)
+ {
+ free (*contents);
+ *contents = NULL;
+ return err;
+ }
+
+ while (pos + sublen > sz)
+ *contents = realloc (*contents, sz *= 2);
+
+ memcpy (*contents + pos, subcon, sublen);
+ pos += sublen;
+ }
+
+ *contents_len = pos;
+ return 0;
+}
+
+static error_t
+dircat_lookup (void *hook, const char *name, struct node **np)
+{
+ struct dircat_node *dcn = hook;
+ error_t err;
+ int i;
+
+ err = ENOENT;
+ for (i=0; err && dcn->dirs[i]; i++)
+ err = procfs_lookup (dcn->dirs[i], name, np);
+
+ return err;
+}
+
+static void
+dircat_release_dirs (struct node **dirs)
+{
+ int i;
+
+ for (i=0; dirs[i]; i++)
+ netfs_nrele (dirs[i]);
+}
+
+static void
+dircat_cleanup (void *hook)
+{
+ struct dircat_node *dcn = hook;
+
+ dircat_release_dirs (dcn->dirs);
+ free (dcn);
+}
+
+struct node *
+dircat_make_node (struct node **dirs)
+{
+ static struct procfs_node_ops ops = {
+ .get_contents = dircat_get_contents,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ .lookup = dircat_lookup,
+ .cleanup = dircat_cleanup,
+ /* necessary so that it propagates to proclist */
+ .enable_refresh_hack_and_break_readdir = 1,
+ };
+ struct dircat_node *dcn;
+
+ dcn = malloc (sizeof *dcn);
+ if (! dcn)
+ {
+ dircat_release_dirs (dirs);
+ return NULL;
+ }
+
+ dcn->dirs = dirs;
+ return procfs_make_node (&ops, dcn);
+}
+
diff --git a/dircat.h b/dircat.h
new file mode 100644
index 00000000..cb228526
--- /dev/null
+++ b/dircat.h
@@ -0,0 +1,9 @@
+/* Append the contents of multiple directories. DIRS is a
+ NULL-terminated array of directory nodes. One reference is consumed
+ for each of them, even on ENOMEM, in which case NULL is returned.
+ DIRS has to be static data for now, or at list remain available and
+ unchanged for the duration of the created node's life. Strange
+ things will happen if they have entries with the same name or if one
+ of them is not a directory. */
+struct node *
+dircat_make_node (struct node **dirs);
diff --git a/main.c b/main.c
index 4350eff5..e08bbdb7 100644
--- a/main.c
+++ b/main.c
@@ -7,25 +7,46 @@
#include "procfs_file.h"
#include "procfs_dir.h"
#include "proclist.h"
+#include "dircat.h"
-static struct node *make_file (void *dir_hook, void *ent_hook)
+static struct node *
+make_file (void *dir_hook, void *ent_hook)
{
return procfs_file_make_node (ent_hook, -1, NULL);
}
-static struct node *make_proclist (void *dir_hook, void *ent_hook)
+error_t
+root_make_node (struct node **np)
{
- return proclist_make_node (getproc ());
+ static const struct procfs_dir_entry static_entries[] = {
+ { "hello", make_file, "Hello, World!\n" },
+ { "goodbye", make_file, "Goodbye, cruel World!\n" },
+ };
+ /* We never have two root nodes alive simultaneously, so it's ok to
+ have this as static data. */
+ static struct node *root_dirs[3];
+
+ root_dirs[0] = procfs_dir_make_node (static_entries, NULL, NULL);
+ if (! root_dirs[0])
+ return ENOMEM;
+
+ root_dirs[1] = proclist_make_node (getproc ());
+ if (! root_dirs[1])
+ {
+ netfs_nrele (root_dirs[0]);
+ return ENOMEM;
+ }
+
+ root_dirs[2] = NULL;
+ *np = dircat_make_node (root_dirs);
+ if (! *np)
+ return ENOMEM;
+
+ return 0;
}
int main (int argc, char **argv)
{
- static const struct procfs_dir_entry entries[] = {
- { "hello", make_file, "Hello, World!\n" },
- { "goodbye", make_file, "Goodbye, cruel World!\n" },
- { "proclist", make_proclist, },
- { }
- };
mach_port_t bootstrap;
argp_parse (&netfs_std_startup_argp, argc, argv, 0, 0, 0);
@@ -35,7 +56,7 @@ int main (int argc, char **argv)
error (1, 0, "Must be started as a translator");
netfs_init ();
- netfs_root_node = procfs_dir_make_node (entries, NULL, NULL);
+ root_make_node (&netfs_root_node);
netfs_startup (bootstrap, 0);
for (;;)
diff --git a/procfs.c b/procfs.c
index 755e0519..573bb72f 100644
--- a/procfs.c
+++ b/procfs.c
@@ -66,6 +66,14 @@ fail:
error_t procfs_get_contents (struct node *np, void **data, size_t *data_len)
{
+ if (np->nn->ops->enable_refresh_hack_and_break_readdir && np->nn->contents)
+ {
+ if (np->nn->ops->cleanup_contents)
+ np->nn->ops->cleanup_contents (np->nn->hook, np->nn->contents,
+ np->nn->contents_len);
+ np->nn->contents = NULL;
+ }
+
if (! np->nn->contents && np->nn->ops->get_contents)
{
void *contents;
diff --git a/procfs.h b/procfs.h
index 3cb3223d..b44db6e3 100644
--- a/procfs.h
+++ b/procfs.h
@@ -27,6 +27,14 @@ struct procfs_node_ops
/* Destroy this node. */
void (*cleanup) (void *hook);
+
+ /* FIXME: This is needed because the root node is persistent, and we
+ want the list of processes to be updated. However, this means that
+ readdir() on the root node runs the risk of returning incoherent
+ results if done in multiple runs and processes are added/removed in
+ the meantime. The right way to fix this is probably to add a
+ getroot() user hook function to libnetfs. */
+ int enable_refresh_hack_and_break_readdir;
};
/* These helper functions can be used as procfs_node_ops.cleanup_contents. */
diff --git a/proclist.c b/proclist.c
index 75b61a2e..94a7a04d 100644
--- a/proclist.c
+++ b/proclist.c
@@ -74,6 +74,7 @@ proclist_make_node (process_t process)
.lookup = proclist_lookup,
.cleanup_contents = procfs_cleanup_contents_with_free,
.cleanup = free,
+ .enable_refresh_hack_and_break_readdir = 1,
};
struct proclist_node *pl;