xref: /plan9/sys/src/cmd/mntgen.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 
7 static void
8 usage(void)
9 {
10 	fprint(2, "mntgen [-s srvname] [mtpt]\n");
11 	exits("usage");
12 }
13 
14 ulong time0;
15 
16 typedef struct Tab Tab;
17 struct Tab
18 {
19 	char *name;
20 	ulong qid;
21 	ulong time;
22 	int ref;
23 };
24 
25 Tab *tab;
26 int ntab;
27 int mtab;
28 ulong qidgen;
29 
30 static Tab*
31 findtab(ulong path)
32 {
33 	int i;
34 
35 	for(i=0; i<ntab; i++)
36 		if(tab[i].qid == path)
37 			return &tab[i];
38 	return nil;
39 }
40 
41 static void
42 fsopen(Req *r)
43 {
44 	if(r->ifcall.mode != OREAD)
45 		respond(r, "permission denied");
46 	else
47 		respond(r, nil);
48 }
49 
50 static int
51 dirgen(int i, Dir *d, void*)
52 {
53 	if(i >= ntab)
54 		return -1;
55 	memset(d, 0, sizeof *d);
56 	d->qid.type = QTDIR;
57 	d->uid = estrdup9p("sys");
58 	d->gid = estrdup9p("sys");
59 	d->mode = DMDIR|0555;
60 	d->length = 0;
61 	if(i == -1){
62 		d->name = estrdup9p("/");
63 		d->atime = d->mtime = time0;
64 	}else{
65 		d->qid.path = tab[i].qid;
66 		d->name = estrdup9p(tab[i].name);
67 		d->atime = d->mtime = tab[i].time;
68 	}
69 	return 0;
70 }
71 
72 static void
73 fsread(Req *r)
74 {
75 	if(r->fid->qid.path == 0)
76 		dirread9p(r, dirgen, nil);
77 	else
78 		r->ofcall.count = 0;
79 	respond(r, nil);
80 }
81 
82 static void
83 fsstat(Req *r)
84 {
85 	Tab *t;
86 	ulong qid;
87 
88 	qid = r->fid->qid.path;
89 	if(qid == 0)
90 		dirgen(-1, &r->d, nil);
91 	else{
92 		if((t = findtab(qid)) == nil){
93 			respond(r, "path not found (???)");
94 			return;
95 		}
96 		dirgen(t-tab, &r->d, nil);
97 	}
98 	respond(r, nil);
99 }
100 
101 static char*
102 fswalk1(Fid *fid, char *name, void*)
103 {
104 	int i;
105 	Tab *t;
106 
107 	if(fid->qid.path != 0){
108 		/* nothing in child directory */
109 		if(strcmp(name, "..") == 0){
110 			if((t = findtab(fid->qid.path)) != nil)
111 				t->ref--;
112 			fid->qid.path = 0;
113 			return nil;
114 		}
115 		return "path not found";
116 	}
117 	/* root */
118 	if(strcmp(name, "..") == 0)
119 		return nil;
120 	for(i=0; i<ntab; i++)
121 		if(strcmp(tab[i].name, name) == 0){
122 			tab[i].ref++;
123 			fid->qid.path = tab[i].qid;
124 			return nil;
125 		}
126 
127 	/* create it */
128 	if(ntab == mtab){
129 		if(mtab == 0)
130 			mtab = 16;
131 		else
132 			mtab *= 2;
133 		tab = erealloc9p(tab, sizeof(tab[0])*mtab);
134 	}
135 	tab[ntab].qid = ++qidgen;
136 	fid->qid.path = tab[ntab].qid;
137 	tab[ntab].name = estrdup9p(name);
138 	tab[ntab].time = time(0);
139 	tab[ntab].ref = 1;
140 	ntab++;
141 
142 	return nil;
143 }
144 
145 static char*
146 fsclone(Fid *fid, Fid*, void*)
147 {
148 	Tab *t;
149 
150 	if((t = findtab(fid->qid.path)) != nil)
151 		t->ref++;
152 	return nil;
153 }
154 
155 static void
156 fswalk(Req *r)
157 {
158 	walkandclone(r, fswalk1, fsclone, nil);
159 }
160 
161 static void
162 fsclunk(Fid *fid)
163 {
164 	Tab *t;
165 	ulong qid;
166 
167 	qid = fid->qid.path;
168 	if(qid == 0)
169 		return;
170 	if((t = findtab(qid)) == nil){
171 		fprint(2, "warning: cannot find %lux\n", qid);
172 		return;
173 	}
174 	if(--t->ref == 0){
175 		free(t->name);
176 		tab[t-tab] = tab[--ntab];
177 	}else if(t->ref < 0)
178 		fprint(2, "warning: negative ref count for %s\n", t->name);
179 }
180 
181 static void
182 fsattach(Req *r)
183 {
184 	char *spec;
185 
186 	spec = r->ifcall.aname;
187 	if(spec && spec[0]){
188 		respond(r, "invalid attach specifier");
189 		return;
190 	}
191 
192 	r->ofcall.qid = (Qid){0, 0, QTDIR};
193 	r->fid->qid = r->ofcall.qid;
194 	respond(r, nil);
195 }
196 
197 Srv fs=
198 {
199 .attach=	fsattach,
200 .open=	fsopen,
201 .read=	fsread,
202 .stat=	fsstat,
203 .walk=	fswalk,
204 .destroyfid=	fsclunk
205 };
206 
207 void
208 main(int argc, char **argv)
209 {
210 	char *service;
211 
212 	time0 = time(0);
213 	service = nil;
214 	ARGBEGIN{
215 	case 'D':
216 		chatty9p++;
217 		break;
218 	case 's':
219 		service = EARGF(usage());
220 		break;
221 	default:
222 		usage();
223 	}ARGEND
224 
225 	if(argc > 1)
226 		usage();
227 	postmountsrv(&fs, service, argc ? argv[0] : "/n", MAFTER);
228 	exits(nil);
229 }
230