summaryrefslogtreecommitdiff
path: root/procfs_dir.c
blob: 4df46695014e5f5c36f1b6bc936402f641801487 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdlib.h>
#include <string.h>
#include "procfs.h"
#include "procfs_dir.h"

struct procfs_dir_node
{
  const struct procfs_dir_entry *entries;
  void *hook;
  void (*cleanup) (void *hook);
};

static error_t
procfs_dir_get_contents (void *hook, char **contents, size_t *contents_len)
{
  static const char dot_dotdot[] = ".\0..";
  struct procfs_dir_node *dn = hook;
  const struct procfs_dir_entry *ent;
  char *pos;

  *contents_len = sizeof dot_dotdot;
  for (ent = dn->entries; ent->name; ent++)
    *contents_len += strlen (ent->name) + 1;

  *contents = malloc (*contents_len);
  if (! *contents)
    return ENOMEM;

  memcpy (*contents, dot_dotdot, sizeof dot_dotdot);
  pos = *contents + sizeof dot_dotdot;
  for (ent = dn->entries; ent->name; ent++)
    {
      strcpy (pos, ent->name);
      pos += strlen (ent->name) + 1;
    }

  return 0;
}

static error_t
procfs_dir_lookup (void *hook, const char *name, struct node **np)
{
  struct procfs_dir_node *dn = hook;
  const struct procfs_dir_entry *ent;

  for (ent = dn->entries; ent->name && strcmp (name, ent->name); ent++);
  if (! ent->name)
    return ENOENT;

  *np = ent->make_node (dn->hook, ent->hook);
  if (! *np)
    return ENOMEM;

  return 0;
}

static void
procfs_dir_cleanup (void *hook)
{
  struct procfs_dir_node *dn = hook;

  if (dn->cleanup)
    dn->cleanup (dn->hook);

  free (dn);
}

struct node *
procfs_dir_make_node (const struct procfs_dir_entry *entries,
		      void *dir_hook, void (*cleanup) (void *dir_hook))
{
  static const struct procfs_node_ops ops = {
    .get_contents = procfs_dir_get_contents,
    .lookup = procfs_dir_lookup,
    .cleanup_contents = procfs_cleanup_contents_with_free,
    .cleanup = procfs_dir_cleanup,
  };
  struct procfs_dir_node *dn;

  dn = malloc (sizeof *dn);
  if (! dn)
    {
      if (cleanup)
	cleanup (dir_hook);

      return NULL;
    }

  dn->entries = entries;
  dn->hook = dir_hook;
  dn->cleanup = cleanup;

  return procfs_make_node (&ops, dn);
}