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