ia64/xen-unstable

view tools/ioemu/path.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 8e5fc5fe636c
children
line source
1 /* Code to mangle pathnames into those matching a given prefix.
2 eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
4 The assumption is that this area does not change.
5 */
6 #include <sys/types.h>
7 #include <dirent.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <stdio.h>
13 #include "qemu.h"
15 struct pathelem
16 {
17 /* Name of this, eg. lib */
18 char *name;
19 /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
20 char *pathname;
21 struct pathelem *parent;
22 /* Children */
23 unsigned int num_entries;
24 struct pathelem *entries[0];
25 };
27 static struct pathelem *base;
29 /* First N chars of S1 match S2, and S2 is N chars long. */
30 static int strneq(const char *s1, unsigned int n, const char *s2)
31 {
32 unsigned int i;
34 for (i = 0; i < n; i++)
35 if (s1[i] != s2[i])
36 return 0;
37 return s2[i] == 0;
38 }
40 static struct pathelem *add_entry(struct pathelem *root, const char *name);
42 static struct pathelem *new_entry(const char *root,
43 struct pathelem *parent,
44 const char *name)
45 {
46 struct pathelem *new = malloc(sizeof(*new));
47 new->name = strdup(name);
48 asprintf(&new->pathname, "%s/%s", root, name);
49 new->num_entries = 0;
50 return new;
51 }
53 #define streq(a,b) (strcmp((a), (b)) == 0)
55 static struct pathelem *add_dir_maybe(struct pathelem *path)
56 {
57 DIR *dir;
59 if ((dir = opendir(path->pathname)) != NULL) {
60 struct dirent *dirent;
62 while ((dirent = readdir(dir)) != NULL) {
63 if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
64 path = add_entry(path, dirent->d_name);
65 }
66 }
67 closedir(dir);
68 }
69 return path;
70 }
72 static struct pathelem *add_entry(struct pathelem *root, const char *name)
73 {
74 root->num_entries++;
76 root = realloc(root, sizeof(*root)
77 + sizeof(root->entries[0])*root->num_entries);
79 root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
80 root->entries[root->num_entries-1]
81 = add_dir_maybe(root->entries[root->num_entries-1]);
82 return root;
83 }
85 /* This needs to be done after tree is stabalized (ie. no more reallocs!). */
86 static void set_parents(struct pathelem *child, struct pathelem *parent)
87 {
88 unsigned int i;
90 child->parent = parent;
91 for (i = 0; i < child->num_entries; i++)
92 set_parents(child->entries[i], child);
93 }
95 void init_paths(const char *prefix)
96 {
97 if (prefix[0] != '/' ||
98 prefix[0] == '\0' ||
99 !strcmp(prefix, "/"))
100 return;
102 base = new_entry("", NULL, prefix+1);
103 base = add_dir_maybe(base);
104 if (base->num_entries == 0) {
105 free (base);
106 base = NULL;
107 } else {
108 set_parents(base, base);
109 }
110 }
112 /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
113 static const char *
114 follow_path(const struct pathelem *cursor, const char *name)
115 {
116 unsigned int i, namelen;
118 name += strspn(name, "/");
119 namelen = strcspn(name, "/");
121 if (namelen == 0)
122 return cursor->pathname;
124 if (strneq(name, namelen, ".."))
125 return follow_path(cursor->parent, name + namelen);
127 if (strneq(name, namelen, "."))
128 return follow_path(cursor, name + namelen);
130 for (i = 0; i < cursor->num_entries; i++)
131 if (strneq(name, namelen, cursor->entries[i]->name))
132 return follow_path(cursor->entries[i], name + namelen);
134 /* Not found */
135 return NULL;
136 }
138 /* Look for path in emulation dir, otherwise return name. */
139 const char *path(const char *name)
140 {
141 /* Only do absolute paths: quick and dirty, but should mostly be OK.
142 Could do relative by tracking cwd. */
143 if (!base || name[0] != '/')
144 return name;
146 return follow_path(base, name) ?: name;
147 }