Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/nfs.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright © 2003 Russ Cox, MIT; see /sys/src/libsunrpc/COPYING */
2
#include <u.h>
3
#include <libc.h>
4
#include <bio.h>
5
#include <fcall.h>
6
#include <thread.h>
7
#include <9p.h>
8
#include <sunrpc.h>
9
#include <nfs3.h>
10
 
11
SunClient *nfscli;
12
SunClient *mntcli;
13
char *defaultpath = "/";
14
Channel *fschan;
15
char *sys;
16
int verbose;
17
int readplus = 0;
18
 
19
 
20
typedef struct Auth Auth;
21
struct Auth
22
{
23
	int ref;
24
	uchar *data;
25
	int ndata;
26
};
27
 
28
typedef struct FidAux FidAux;
29
struct FidAux
30
{
31
	Nfs3Handle handle;
32
 
33
	u64int cookie;	/* for continuing directory reads */
34
	char *name;	/* botch: for remove and rename */
35
	Nfs3Handle parent;	/* botch: for remove and rename */
36
	char err[ERRMAX];	/* for walk1 */
37
	Auth *auth;
38
};
39
 
40
/*
41
 * various RPCs.  here is where we'd insert support for NFS v2
42
 */
43
 
44
void
45
portCall(SunCall *c, PortCallType type)
46
{
47
	c->rpc.prog = PortProgram;
48
	c->rpc.vers = PortVersion;
49
	c->rpc.proc = type>>1;
50
	c->rpc.iscall = !(type&1);
51
	c->type = type;
52
}
53
 
54
int
55
getport(SunClient *client, uint prog, uint vers, uint prot, uint *port)
56
{
57
	PortTGetport tx;
58
	PortRGetport rx;
59
 
60
	memset(&tx, 0, sizeof tx);
61
	portCall(&tx.call, PortCallTGetport);
62
	tx.map.prog = prog;
63
	tx.map.vers = vers;
64
	tx.map.prot = prot;
65
 
66
	memset(&rx, 0, sizeof rx);
67
	portCall(&rx.call, PortCallRGetport);
68
 
69
	if(sunClientRpc(client, 0, &tx.call, &rx.call, nil) < 0)
70
		return -1;
71
	*port = rx.port;
72
	return 0;
73
}
74
 
75
void
76
mountCall(Auth *a, SunCall *c, NfsMount3CallType type)
77
{
78
	c->rpc.iscall = !(type&1);
79
	c->rpc.proc = type>>1;
80
	c->rpc.prog = NfsMount3Program;
81
	c->rpc.vers = NfsMount3Version;
82
	if(c->rpc.iscall && a){
83
		c->rpc.cred.flavor = SunAuthSys;
84
		c->rpc.cred.data = a->data;
85
		c->rpc.cred.ndata = a->ndata;
86
	}
87
	c->type = type;
88
}
89
 
90
int
91
mountNull(ulong tag)
92
{
93
	NfsMount3TNull tx;
94
	NfsMount3RNull rx;
95
 
96
	memset(&tx, 0, sizeof tx);
97
	mountCall(nil, &tx.call, NfsMount3CallTNull);
98
 
99
	memset(&rx, 0, sizeof rx);
100
	mountCall(nil, &rx.call, NfsMount3CallTNull);
101
 
102
	return sunClientRpc(mntcli, tag, &tx.call, &rx.call, nil);
103
}
104
 
105
int
106
mountMnt(Auth *a, ulong tag, char *path, Nfs3Handle *h)
107
{
108
	uchar *freeme;
109
	NfsMount3TMnt tx;
110
	NfsMount3RMnt rx;
111
 
112
	memset(&tx, 0, sizeof tx);
113
	mountCall(a, &tx.call, NfsMount3CallTMnt);
114
	tx.path = path;
115
 
116
	memset(&rx, 0, sizeof rx);
117
	mountCall(a, &rx.call, NfsMount3CallRMnt);
118
	if(sunClientRpc(mntcli, tag, &tx.call, &rx.call, &freeme) < 0)
119
		return -1;
120
	if(rx.status != Nfs3Ok){
121
		nfs3Errstr(rx.status);
122
		return -1;
123
	}
124
if(verbose)print("handle %.*H\n", rx.len, rx.handle);
125
	if(rx.len >= Nfs3MaxHandleSize){
126
		free(freeme);
127
		werrstr("server-returned handle too long");
128
		return -1;
129
	}
130
	memmove(h->h, rx.handle, rx.len);
131
	h->len = rx.len;
132
	free(freeme);
133
	return 0;
134
}
135
 
136
void
137
nfs3Call(Auth *a, SunCall *c, Nfs3CallType type)
138
{
139
	c->rpc.iscall = !(type&1);
140
	c->rpc.proc = type>>1;
141
	c->rpc.prog = Nfs3Program;
142
	c->rpc.vers = Nfs3Version;
143
	if(c->rpc.iscall && a){
144
		c->rpc.cred.flavor = SunAuthSys;
145
		c->rpc.cred.data = a->data;
146
		c->rpc.cred.ndata = a->ndata;
147
	}
148
	c->type = type;
149
}
150
 
151
int
152
nfsNull(ulong tag)
153
{
154
	Nfs3TNull tx;
155
	Nfs3RNull rx;
156
 
157
	memset(&tx, 0, sizeof tx);
158
	nfs3Call(nil, &tx.call, Nfs3CallTNull);
159
 
160
	memset(&rx, 0, sizeof rx);
161
	nfs3Call(nil, &rx.call, Nfs3CallTNull);
162
 
163
	return sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil);
164
}
165
 
166
int
167
nfsGetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3Attr *attr)
168
{
169
	Nfs3TGetattr tx;
170
	Nfs3RGetattr rx;
171
 
172
	memset(&tx, 0, sizeof tx);
173
	nfs3Call(a, &tx.call, Nfs3CallTGetattr);
174
	tx.handle = *h;	
175
 
176
	memset(&rx, 0, sizeof rx);
177
	nfs3Call(a, &rx.call, Nfs3CallRGetattr);
178
 
179
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
180
		return -1;
181
	if(rx.status != Nfs3Ok){
182
		nfs3Errstr(rx.status);
183
		return -1;
184
	}
185
 
186
	*attr = rx.attr;
187
	return 0;
188
}
189
 
190
int
191
nfsAccess(Auth *a, ulong tag, Nfs3Handle *h, ulong want, ulong *got, u1int *have, Nfs3Attr *attr)
192
{
193
	Nfs3TAccess tx;
194
	Nfs3RAccess rx;
195
 
196
	memset(&tx, 0, sizeof tx);
197
	nfs3Call(a, &tx.call, Nfs3CallTAccess);
198
	tx.handle = *h;
199
	tx.access = want;
200
 
201
	memset(&rx, 0, sizeof rx);
202
	nfs3Call(a, &rx.call, Nfs3CallRAccess);
203
 
204
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
205
		return -1;
206
	if(rx.status != Nfs3Ok){
207
		nfs3Errstr(rx.status);
208
		return -1;
209
	}
210
 
211
	*got = rx.access;
212
 
213
	*have = rx.haveAttr;
214
	if(rx.haveAttr)
215
		*attr = rx.attr;
216
	return 0;
217
}
218
 
219
int
220
nfsMkdir(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
221
	u1int *have, Nfs3Attr *attr)
222
{
223
	Nfs3TMkdir tx;
224
	Nfs3RMkdir rx;
225
 
226
	memset(&tx, 0, sizeof tx);
227
	nfs3Call(a, &tx.call, Nfs3CallTMkdir);
228
	tx.handle = *h;
229
	tx.name = name;
230
	tx.attr.setMode = 1;
231
	tx.attr.mode = mode;
232
	tx.attr.setGid = 1;
233
	tx.attr.gid = gid;
234
 
235
	memset(&rx, 0, sizeof rx);
236
	nfs3Call(a, &rx.call, Nfs3CallRMkdir);
237
 
238
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
239
		return -1;
240
	if(rx.status != Nfs3Ok){
241
		nfs3Errstr(rx.status);
242
		return -1;
243
	}
244
 
245
	if(!rx.haveHandle){
246
		werrstr("nfs mkdir did not return handle");
247
		return -1;
248
	}
249
	*nh = rx.handle;
250
 
251
	*have = rx.haveAttr;
252
	if(rx.haveAttr)
253
		*attr = rx.attr;
254
	return 0;
255
}
256
 
257
int
258
nfsCreate(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
259
	u1int *have, Nfs3Attr *attr)
260
{
261
	Nfs3TCreate tx;
262
	Nfs3RCreate rx;
263
 
264
	memset(&tx, 0, sizeof tx);
265
	nfs3Call(a, &tx.call, Nfs3CallTCreate);
266
	tx.handle = *h;
267
	tx.name = name;
268
	tx.attr.setMode = 1;
269
	tx.attr.mode = mode;
270
	tx.attr.setGid = 1;
271
	tx.attr.gid = gid;
272
 
273
	memset(&rx, 0, sizeof rx);
274
	nfs3Call(a, &rx.call, Nfs3CallRCreate);
275
 
276
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
277
		return -1;
278
	if(rx.status != Nfs3Ok){
279
		nfs3Errstr(rx.status);
280
		return -1;
281
	}
282
 
283
	if(!rx.haveHandle){
284
		werrstr("nfs create did not return handle");
285
		return -1;
286
	}
287
	*nh = rx.handle;
288
 
289
	*have = rx.haveAttr;
290
	if(rx.haveAttr)
291
		*attr = rx.attr;
292
	return 0;
293
}
294
 
295
int
296
nfsRead(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int offset,
297
	uchar **pp, u32int *pcount, uchar **pfreeme)
298
{
299
	uchar *freeme;
300
	Nfs3TRead tx;
301
	Nfs3RRead rx;
302
 
303
	memset(&tx, 0, sizeof tx);
304
	nfs3Call(a, &tx.call, Nfs3CallTRead);
305
	tx.handle = *h;
306
	tx.count = count;
307
	tx.offset = offset;
308
 
309
	memset(&rx, 0, sizeof rx);
310
	nfs3Call(a, &rx.call, Nfs3CallRRead);
311
 
312
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, &freeme) < 0)
313
		return -1;
314
	if(rx.status != Nfs3Ok){
315
		nfs3Errstr(rx.status);
316
		return -1;
317
	}
318
	if(rx.count != rx.ndata){
319
		werrstr("nfs read returned count=%ud ndata=%ud", (uint)rx.count, (uint)rx.ndata);
320
		free(freeme);
321
		return -1;
322
	}
323
	*pfreeme = freeme;
324
	*pcount = rx.count;
325
	*pp = rx.data;
326
	return 0;
327
}
328
 
329
int
330
nfsWrite(Auth *a, ulong tag, Nfs3Handle *h, uchar *data, u32int count, u64int offset, u32int *pcount)
331
{
332
	Nfs3TWrite tx;
333
	Nfs3RWrite rx;
334
 
335
	memset(&tx, 0, sizeof tx);
336
	nfs3Call(a, &tx.call, Nfs3CallTWrite);
337
	tx.handle = *h;
338
	tx.count = count;
339
	tx.offset = offset;
340
	tx.data = data;
341
	tx.ndata = count;
342
 
343
	memset(&rx, 0, sizeof rx);
344
	nfs3Call(a, &rx.call, Nfs3CallRWrite);
345
 
346
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
347
		return -1;
348
	if(rx.status != Nfs3Ok){
349
		nfs3Errstr(rx.status);
350
		return -1;
351
	}
352
 
353
	*pcount = rx.count;
354
	return 0;
355
}
356
 
357
int
358
nfsRmdir(Auth *a, ulong tag, Nfs3Handle *h, char *name)
359
{
360
	Nfs3TRmdir tx;
361
	Nfs3RRmdir rx;
362
 
363
	memset(&tx, 0, sizeof tx);
364
	nfs3Call(a, &tx.call, Nfs3CallTRmdir);
365
	tx.handle = *h;
366
	tx.name = name;
367
 
368
	memset(&rx, 0, sizeof rx);
369
	nfs3Call(a, &rx.call, Nfs3CallRRmdir);
370
 
371
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
372
		return -1;
373
	if(rx.status != Nfs3Ok){
374
		nfs3Errstr(rx.status);
375
		return -1;
376
	}
377
	return 0;
378
}
379
 
380
int
381
nfsRemove(Auth *a, ulong tag, Nfs3Handle *h, char *name)
382
{
383
	Nfs3TRemove tx;
384
	Nfs3RRemove rx;
385
 
386
	memset(&tx, 0, sizeof tx);
387
	nfs3Call(a, &tx.call, Nfs3CallTRemove);
388
	tx.handle = *h;
389
	tx.name = name;
390
 
391
	memset(&rx, 0, sizeof rx);
392
	nfs3Call(a, &rx.call, Nfs3CallRRemove);
393
 
394
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
395
		return -1;
396
	if(rx.status != Nfs3Ok){
397
		nfs3Errstr(rx.status);
398
		return -1;
399
	}
400
	return 0;
401
}
402
 
403
int
404
nfsRename(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *th, char *tname)
405
{
406
	Nfs3TRename tx;
407
	Nfs3RRename rx;
408
 
409
	memset(&tx, 0, sizeof tx);
410
	nfs3Call(a, &tx.call, Nfs3CallTRename);
411
	tx.from.handle = *h;
412
	tx.from.name = name;
413
	tx.to.handle = *th;
414
	tx.to.name = tname;
415
 
416
	memset(&rx, 0, sizeof rx);
417
	nfs3Call(a, &rx.call, Nfs3CallRRename);
418
 
419
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
420
		return -1;
421
	if(rx.status != Nfs3Ok){
422
		nfs3Errstr(rx.status);
423
		return -1;
424
	}
425
	return 0;
426
}
427
 
428
int
429
nfsSetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3SetAttr *attr)
430
{
431
	Nfs3TSetattr tx;
432
	Nfs3RSetattr rx;
433
 
434
	memset(&tx, 0, sizeof tx);
435
	nfs3Call(a, &tx.call, Nfs3CallTSetattr);
436
	tx.handle = *h;
437
	tx.attr = *attr;
438
 
439
	memset(&rx, 0, sizeof rx);
440
	nfs3Call(a, &rx.call, Nfs3CallRSetattr);
441
 
442
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
443
		return -1;
444
	if(rx.status != Nfs3Ok){
445
		nfs3Errstr(rx.status);
446
		return -1;
447
	}
448
	return 0;
449
}
450
 
451
int
452
nfsCommit(Auth *a, ulong tag, Nfs3Handle *h)
453
{
454
	Nfs3TCommit tx;
455
	Nfs3RCommit rx;
456
 
457
	memset(&tx, 0, sizeof tx);
458
	nfs3Call(a, &tx.call, Nfs3CallTCommit);
459
	tx.handle = *h;
460
 
461
	memset(&rx, 0, sizeof rx);
462
	nfs3Call(a, &rx.call, Nfs3CallRCommit);
463
 
464
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
465
		return -1;
466
 
467
	if(rx.status != Nfs3Ok){
468
		nfs3Errstr(rx.status);
469
		return -1;
470
	}
471
	return 0;
472
}
473
 
474
int
475
nfsLookup(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, u1int *have, Nfs3Attr *attr)
476
{
477
	Nfs3TLookup tx;
478
	Nfs3RLookup rx;
479
 
480
	memset(&tx, 0, sizeof tx);
481
	nfs3Call(a, &tx.call, Nfs3CallTLookup);
482
	tx.handle = *h;
483
	tx.name = name;
484
 
485
	memset(&rx, 0, sizeof rx);
486
	nfs3Call(a, &rx.call, Nfs3CallRLookup);
487
 
488
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
489
		return -1;
490
 
491
	if(rx.status != Nfs3Ok){
492
		nfs3Errstr(rx.status);
493
		return -1;
494
	}
495
	*nh = rx.handle;
496
	*have = rx.haveAttr;
497
	if(rx.haveAttr)
498
		*attr = rx.attr;
499
	return 0;
500
}
501
 
502
int
503
nfsReadDirPlus(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
504
	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
505
{
506
	Nfs3TReadDirPlus tx;
507
	Nfs3RReadDirPlus rx;
508
 
509
	memset(&tx, 0, sizeof tx);
510
	nfs3Call(a, &tx.call, Nfs3CallTReadDirPlus);
511
	tx.handle = *h;
512
	tx.maxCount = count;
513
	tx.dirCount = 1000;
514
	tx.cookie = cookie;
515
 
516
	memset(&rx, 0, sizeof rx);
517
	nfs3Call(a, &rx.call, Nfs3CallRReadDirPlus);
518
 
519
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
520
		return -1;
521
	if(rx.status != Nfs3Ok){
522
		free(*pfreeme);
523
		*pfreeme = 0;
524
		nfs3Errstr(rx.status);
525
		return -1;
526
	}
527
 
528
	*unpack = nfs3EntryPlusUnpack;
529
	*pcount = rx.count;
530
	*pp = rx.data;
531
	return 0;
532
}
533
 
534
int
535
nfsReadDir(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
536
	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
537
{
538
	/* BUG: try readdirplus */
539
	char e[ERRMAX];
540
	Nfs3TReadDir tx;
541
	Nfs3RReadDir rx;
542
 
543
	if(readplus!=-1){
544
		if(nfsReadDirPlus(a, tag, h, count, cookie, pp, pcount, unpack, pfreeme) == 0){
545
			readplus = 1;
546
			return 0;
547
		}
548
		if(readplus == 0){
549
			rerrstr(e, sizeof e);
550
			if(strstr(e, "procedure unavailable") || strstr(e, "not supported"))
551
				readplus = -1;
552
		}
553
		if(readplus == 0)
554
			fprint(2, "readdirplus: %r\n");
555
	}
556
	if(readplus == 1)
557
		return -1;
558
 
559
	memset(&tx, 0, sizeof tx);
560
	nfs3Call(a, &tx.call, Nfs3CallTReadDir);
561
	tx.handle = *h;
562
	tx.count = count;
563
	tx.cookie = cookie;
564
 
565
	memset(&rx, 0, sizeof rx);
566
	nfs3Call(a, &rx.call, Nfs3CallRReadDir);
567
 
568
	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
569
		return -1;
570
	if(rx.status != Nfs3Ok){
571
		free(*pfreeme);
572
		*pfreeme = 0;
573
		nfs3Errstr(rx.status);
574
		return -1;
575
	}
576
 
577
	/* readplus failed but read succeeded */
578
	readplus = -1;
579
 
580
	*unpack = nfs3EntryUnpack;
581
	*pcount = rx.count;
582
	*pp = rx.data;
583
	return 0;
584
}
585
 
586
/*
587
 * name <-> int translation
588
 */
589
typedef struct Map Map;
590
typedef struct User User;
591
typedef struct Group Group;
592
 
593
Map *map;
594
Map emptymap;
595
 
596
struct User
597
{
598
	char *name;
599
	uint uid;
600
	uint gid;
601
	uint g[16];
602
	uint ng;
603
	uchar *auth;
604
	int nauth;
605
};
606
 
607
struct Group
608
{
609
	char *name;	/* same pos as in User struct */
610
	uint gid;	/* same pos as in User struct */
611
};
612
 
613
struct Map
614
{
615
	int nuser;
616
	int ngroup;
617
	User *user;
618
	User **ubyname;
619
	User **ubyid;
620
	Group *group;
621
	Group **gbyname;
622
	Group **gbyid;
623
};
624
 
625
User*
626
finduser(User **u, int nu, char *s)
627
{
628
	int lo, hi, mid, n;
629
 
630
	hi = nu;
631
	lo = 0;
632
	while(hi > lo){
633
		mid = (lo+hi)/2;
634
		n = strcmp(u[mid]->name, s);
635
		if(n == 0)
636
			return u[mid];
637
		if(n < 0)
638
			lo = mid+1;
639
		else
640
			hi = mid;
641
	}
642
	return nil;
643
}
644
 
645
int
646
strtoid(User **u, int nu, char *s, u32int *id)
647
{
648
	u32int x;
649
	char *p;
650
	User *uu;
651
 
652
	x = strtoul(s, &p, 10);
653
	if(*s != 0 && *p == 0){
654
		*id = x;
655
		return 0;
656
	}
657
 
658
	uu = finduser(u, nu, s);
659
	if(uu == nil)
660
		return -1;
661
	*id = uu->uid;
662
	return 0;
663
}
664
 
665
char*
666
idtostr(User **u, int nu, u32int id)
667
{
668
	char buf[32];
669
	int lo, hi, mid;
670
 
671
	hi = nu;
672
	lo = 0;
673
	while(hi > lo){
674
		mid = (lo+hi)/2;
675
		if(u[mid]->uid == id)
676
			return estrdup9p(u[mid]->name);
677
		if(u[mid]->uid < id)
678
			lo = mid+1;
679
		else
680
			hi = mid;
681
	}
682
	snprint(buf, sizeof buf, "%ud", id);	
683
	return estrdup9p(buf);
684
}		
685
char*
686
uidtostr(u32int uid)
687
{
688
	return idtostr(map->ubyid, map->nuser, uid);
689
}
690
 
691
char*
692
gidtostr(u32int gid)
693
{
694
	return idtostr((User**)map->gbyid, map->ngroup, gid);
695
}
696
 
697
int
698
strtouid(char *s, u32int *id)
699
{
700
	return strtoid(map->ubyname, map->nuser, s, id);
701
}
702
 
703
int
704
strtogid(char *s, u32int *id)
705
{
706
	return strtoid((User**)map->gbyid, map->ngroup, s, id);
707
}
708
 
709
 
710
int
711
idcmp(const void *va, const void *vb)
712
{
713
	User **a, **b;
714
 
715
	a = (User**)va;
716
	b = (User**)vb;
717
	return (*a)->uid - (*b)->uid;
718
}
719
 
720
int
721
namecmp(const void *va, const void *vb)
722
{
723
	User **a, **b;
724
 
725
	a = (User**)va;
726
	b = (User**)vb;
727
	return strcmp((*a)->name, (*b)->name);
728
}
729
 
730
void
731
closemap(Map *m)
732
{
733
	int i;
734
 
735
	for(i=0; i<m->nuser; i++){
736
		free(m->user[i].name);
737
		free(m->user[i].auth);
738
	}
739
	for(i=0; i<m->ngroup; i++)
740
		free(m->group[i].name);
741
	free(m->user);
742
	free(m->group);
743
	free(m->ubyid);
744
	free(m->ubyname);
745
	free(m->gbyid);
746
	free(m->gbyname);
747
	free(m);
748
}
749
 
750
Map*
751
readmap(char *passwd, char *group)
752
{
753
	char *s, *f[10], *p, *nextp, *name;
754
	uchar *q, *eq;
755
	int i, n, nf, line, uid, gid;
756
	Biobuf *b;
757
	Map *m;
758
	User *u;
759
	Group *g;
760
	SunAuthUnix au;
761
 
762
	m = emalloc(sizeof(Map));
763
 
764
	if((b = Bopen(passwd, OREAD)) == nil){
765
		free(m);
766
		return nil;
767
	}
768
	line = 0;
769
	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
770
		line++;
771
		if(s[0] == '#')
772
			continue;
773
		nf = getfields(s, f, nelem(f), 0, ":");
774
		if(nf < 4)
775
			continue;
776
		name = f[0];
777
		uid = strtol(f[2], &p, 10);
778
		if(f[2][0] == 0 || *p != 0){
779
			fprint(2, "%s:%d: non-numeric id in third field\n", passwd, line);
780
			continue;
781
		}
782
		gid = strtol(f[3], &p, 10);
783
		if(f[3][0] == 0 || *p != 0){
784
			fprint(2, "%s:%d: non-numeric id in fourth field\n", passwd, line);
785
			continue;
786
		}
787
		if(m->nuser%32 == 0)
788
			m->user = erealloc(m->user, (m->nuser+32)*sizeof(m->user[0]));
789
		u = &m->user[m->nuser++];
790
		u->name = estrdup9p(name);
791
		u->uid = uid;
792
		u->gid = gid;
793
		u->ng = 0;
794
		u->auth = 0;
795
		u->nauth = 0;
796
	}
797
	Bterm(b);
798
	m->ubyname = emalloc(m->nuser*sizeof(User*));
799
	m->ubyid = emalloc(m->nuser*sizeof(User*));
800
	for(i=0; i<m->nuser; i++){
801
		m->ubyname[i] = &m->user[i];
802
		m->ubyid[i] = &m->user[i];
803
	}
804
	qsort(m->ubyname, m->nuser, sizeof(m->ubyname[0]), namecmp);
805
	qsort(m->ubyid, m->nuser, sizeof(m->ubyid[0]), idcmp);
806
 
807
	if((b = Bopen(group, OREAD)) == nil){
808
		closemap(m);
809
		return nil;
810
	}
811
	line = 0;
812
	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
813
		line++;
814
		if(s[0] == '#')
815
			continue;
816
		nf = getfields(s, f, nelem(f), 0, ":");
817
		if(nf < 4)
818
			continue;
819
		name = f[0];
820
		gid = strtol(f[2], &p, 10);
821
		if(f[2][0] == 0 || *p != 0){
822
			fprint(2, "%s:%d: non-numeric id in third field\n", group, line);
823
			continue;
824
		}
825
		if(m->ngroup%32 == 0)
826
			m->group = erealloc(m->group, (m->ngroup+32)*sizeof(m->group[0]));
827
		g = &m->group[m->ngroup++];
828
		g->name = estrdup9p(name);
829
		g->gid = gid;
830
 
831
		for(p=f[3]; *p; p=nextp){
832
			if((nextp = strchr(p, ',')) != nil)
833
				*nextp++ = 0;
834
			else
835
				nextp = p+strlen(p);
836
			u = finduser(m->ubyname, m->nuser, p);
837
			if(u == nil){
838
				if(verbose)
839
					fprint(2, "%s:%d: unknown user %s\n", group, line, p);
840
				continue;
841
			}
842
			if(u->ng >= nelem(u->g)){
843
				fprint(2, "%s:%d: user %s is in too many groups; ignoring %s\n", group, line, p, name);
844
				continue;
845
			}
846
			u->g[u->ng++] = gid;
847
		}
848
	}
849
	Bterm(b);
850
	m->gbyname = emalloc(m->ngroup*sizeof(Group*));
851
	m->gbyid = emalloc(m->ngroup*sizeof(Group*));
852
	for(i=0; i<m->ngroup; i++){
853
		m->gbyname[i] = &m->group[i];
854
		m->gbyid[i] = &m->group[i];
855
	}
856
	qsort(m->gbyname, m->ngroup, sizeof(m->gbyname[0]), namecmp);
857
	qsort(m->gbyid, m->ngroup, sizeof(m->gbyid[0]), idcmp);
858
 
859
	for(i=0; i<m->nuser; i++){
860
		au.stamp = 0;
861
		au.sysname = sys;
862
		au.uid = m->user[i].uid;
863
		au.gid = m->user[i].gid;
864
		memmove(au.g, m->user[i].g, sizeof au.g);
865
		au.ng = m->user[i].ng;
866
		n = sunAuthUnixSize(&au);
867
		q = emalloc(n);
868
		eq = q+n;
869
		m->user[i].auth = q;
870
		m->user[i].nauth = n;
871
		if(sunAuthUnixPack(q, eq, &q, &au) < 0 || q != eq){
872
			fprint(2, "sunAuthUnixPack failed for %s\n", m->user[i].name);
873
			free(m->user[i].auth);
874
			m->user[i].auth = 0;
875
			m->user[i].nauth = 0;
876
		}
877
	}
878
 
879
	return m;
880
}
881
 
882
Auth*
883
mkauth(char *user)
884
{
885
	Auth *a;
886
	uchar *p;
887
	int n;
888
	SunAuthUnix au;
889
	User *u;
890
 
891
	u = finduser(map->ubyname, map->nuser, user);
892
	if(u == nil || u->nauth == 0){
893
		/* nobody */
894
		au.stamp = 0;
895
		au.uid = -1;
896
		au.gid = -1;
897
		au.ng = 0;
898
		au.sysname = sys;
899
		n = sunAuthUnixSize(&au);
900
		a = emalloc(sizeof(Auth)+n);
901
		a->data = (uchar*)&a[1];
902
		a->ndata = n;
903
		if(sunAuthUnixPack(a->data, a->data+a->ndata, &p, &au) < 0
904
		|| p != a->data+a->ndata){
905
			free(a);
906
			return nil;
907
		}
908
		a->ref = 1;
909
if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
910
		return a;
911
	}
912
 
913
	a = emalloc(sizeof(Auth)+u->nauth);
914
	a->data = (uchar*)&a[1];
915
	a->ndata = u->nauth;
916
	memmove(a->data, u->auth, a->ndata);
917
	a->ref = 1;
918
if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
919
	return a;
920
}
921
 
922
void
923
freeauth(Auth *a)
924
{
925
	if(--a->ref > 0)
926
		return;
927
	free(a);
928
}
929
 
930
/*
931
 * 9P server
932
 */
933
void
934
responderrstr(Req *r)
935
{
936
	char e[ERRMAX];
937
 
938
	rerrstr(e, sizeof e);
939
	respond(r, e);
940
}
941
 
942
void
943
fsdestroyfid(Fid *fid)
944
{
945
	FidAux *aux;
946
 
947
	aux = fid->aux;
948
	if(aux == nil)
949
		return;
950
	freeauth(aux->auth);
951
	free(aux->name);
952
	free(aux);
953
}
954
 
955
void
956
attrToQid(Nfs3Attr *attr, Qid *qid)
957
{
958
	qid->path = attr->fileid;
959
	qid->vers = attr->mtime.sec;
960
	qid->type = 0;
961
	if(attr->type == Nfs3FileDir)
962
		qid->type |= QTDIR;
963
}
964
 
965
void
966
attrToDir(Nfs3Attr *attr, Dir *d)
967
{
968
	d->mode = attr->mode & 0777;
969
	if(attr->type == Nfs3FileDir)
970
		d->mode |= DMDIR;
971
	d->uid = uidtostr(attr->uid);
972
	d->gid = gidtostr(attr->gid);
973
	d->length = attr->size;
974
	attrToQid(attr, &d->qid);
975
	d->mtime = attr->mtime.sec;
976
	d->atime = attr->atime.sec;
977
	d->muid = nil;
978
}
979
 
980
void
981
fsattach(Req *r)
982
{
983
	char *path;
984
	Auth *auth;
985
	FidAux *aux;
986
	Nfs3Attr attr;
987
	Nfs3Handle h;
988
 
989
	path = r->ifcall.aname;
990
	if(path==nil || path[0]==0)
991
		path = defaultpath;
992
 
993
	auth = mkauth(r->ifcall.uname);
994
 
995
	if(mountMnt(auth, r->tag, path, &h) < 0
996
	|| nfsGetattr(auth, r->tag, &h, &attr) < 0){
997
		freeauth(auth);
998
		responderrstr(r);
999
		return;
1000
	}
1001
 
1002
	aux = emalloc(sizeof(FidAux));
1003
	aux->auth = auth;
1004
	aux->handle = h;
1005
	aux->cookie = 0;
1006
	aux->name = nil;
1007
	memset(&aux->parent, 0, sizeof aux->parent);
1008
	r->fid->aux = aux;
1009
	attrToQid(&attr, &r->fid->qid);
1010
	r->ofcall.qid = r->fid->qid;
1011
	respond(r, nil);
1012
}
1013
 
1014
void
1015
fsopen(Req *r)
1016
{
1017
	FidAux *aux;
1018
	Nfs3Attr attr;
1019
	Nfs3SetAttr sa;
1020
	u1int have;
1021
	ulong a, b;
1022
 
1023
	aux = r->fid->aux;
1024
	a = 0;
1025
	switch(r->ifcall.mode&OMASK){
1026
	case OREAD:
1027
		a = 0x0001;
1028
		break;
1029
	case OWRITE:
1030
		a = 0x0004;
1031
		break;
1032
	case ORDWR:
1033
		a = 0x0001|0x0004;
1034
		break;
1035
	case OEXEC:
1036
		a = 0x20;
1037
		break;
1038
	}
1039
	if(r->ifcall.mode&OTRUNC)
1040
		a |= 0x0004;
1041
 
1042
	if(nfsAccess(aux->auth, r->tag, &aux->handle, a, &b, &have, &attr) < 0
1043
	|| (!have && nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0)){
1044
    Error:
1045
		responderrstr(r);
1046
		return;
1047
	}
1048
	if(a != b){
1049
		respond(r, "permission denied");
1050
		return;
1051
	}
1052
	if(r->ifcall.mode&OTRUNC){
1053
		memset(&sa, 0, sizeof sa);
1054
		sa.setSize = 1;
1055
		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &sa) < 0)
1056
			goto Error;
1057
	}
1058
	attrToQid(&attr, &r->fid->qid);
1059
	r->ofcall.qid = r->fid->qid;
1060
	respond(r, nil);
1061
}
1062
 
1063
void
1064
fscreate(Req *r)
1065
{
1066
	FidAux *aux;
1067
	u1int have;
1068
	Nfs3Attr attr;
1069
	Nfs3Handle h;
1070
	ulong mode;
1071
	uint gid;
1072
	int (*mk)(Auth*, ulong, Nfs3Handle*, char*, Nfs3Handle*, ulong, uint, u1int*, Nfs3Attr*);
1073
 
1074
	aux = r->fid->aux;
1075
 
1076
	/*
1077
	 * Plan 9 has no umask, so let's use the
1078
	 * parent directory bits like Plan 9 does.
1079
	 * What the heck, let's inherit the group too.
1080
	 * (Unix will let us set the group to anything
1081
	 * since we're the owner!)
1082
	 */
1083
	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1084
		responderrstr(r);
1085
		return;
1086
	}
1087
	mode = r->ifcall.perm&0777;
1088
	if(r->ifcall.perm&DMDIR)
1089
		mode &= (attr.mode&0666) | ~0666;
1090
	else
1091
		mode &= (attr.mode&0777) | ~0777;
1092
	gid = attr.gid;
1093
 
1094
	if(r->ifcall.perm&DMDIR)
1095
		mk = nfsMkdir;
1096
	else
1097
		mk = nfsCreate;
1098
 
1099
	if((*mk)(aux->auth, r->tag, &aux->handle, r->ifcall.name, &h, mode, gid, &have, &attr) < 0
1100
	|| (!have && nfsGetattr(aux->auth, r->tag, &h, &attr) < 0)){
1101
		responderrstr(r);
1102
		return;
1103
	}
1104
	attrToQid(&attr, &r->fid->qid);
1105
	aux->parent = aux->handle;
1106
	aux->handle = h;
1107
	free(aux->name);
1108
	aux->name = estrdup9p(r->ifcall.name);
1109
	r->ofcall.qid = r->fid->qid;
1110
	respond(r, nil);
1111
}
1112
 
1113
void
1114
fsreaddir(Req *r)
1115
{
1116
	FidAux *aux;
1117
	uchar *p, *freeme, *ep, *p9, *ep9;
1118
	char *s;
1119
	uint count;
1120
	int n, (*unpack)(uchar*, uchar*, uchar**, Nfs3Entry*);
1121
	Nfs3Entry e;
1122
	u64int cookie;
1123
	Dir d;
1124
 
1125
	aux = r->fid->aux;
1126
	/*
1127
	 * r->ifcall.count seems a reasonable estimate to
1128
	 * how much NFS entry data we want.  is it?
1129
	 */
1130
	if(r->ifcall.offset)
1131
		cookie = aux->cookie;
1132
	else
1133
		cookie = 0;
1134
	if(nfsReadDir(aux->auth, r->tag, &aux->handle, r->ifcall.count, cookie,
1135
		&p, &count, &unpack, &freeme) < 0){
1136
		responderrstr(r);
1137
		return;
1138
	}
1139
	ep = p+count;
1140
 
1141
	p9 = (uchar*)r->ofcall.data;
1142
	ep9 = p9+r->ifcall.count;
1143
 
1144
	/*
1145
	 * BUG: Issue all of the stat requests in parallel.
1146
	 */
1147
	while(p < ep && p9 < ep9){
1148
		if((*unpack)(p, ep, &p, &e) < 0)
1149
			break;
1150
		aux->cookie = e.cookie;
1151
		if(strcmp(e.name, ".") == 0 || strcmp(e.name, "..") == 0)
1152
			continue;
1153
		for(s=e.name; (uchar)*s >= ' '; s++)
1154
			;
1155
		if(*s != 0)	/* bad character in name */
1156
			continue;
1157
		if(!e.haveAttr && !e.haveHandle)
1158
			if(nfsLookup(aux->auth, r->tag, &aux->handle, e.name, &e.handle, &e.haveAttr, &e.attr) < 0)
1159
				continue;
1160
		if(!e.haveAttr)
1161
			if(nfsGetattr(aux->auth, r->tag, &e.handle, &e.attr) < 0)
1162
				continue;
1163
		memset(&d, 0, sizeof d);
1164
		attrToDir(&e.attr, &d);
1165
		d.name = e.name;
1166
		if((n = convD2M(&d, p9, ep9-p9)) <= BIT16SZ)
1167
			break;
1168
		p9 += n;
1169
	}
1170
	free(freeme);
1171
	r->ofcall.count = p9 - (uchar*)r->ofcall.data;
1172
	respond(r, nil);
1173
}
1174
 
1175
void
1176
fsread(Req *r)
1177
{
1178
	uchar *p, *freeme;
1179
	uint count;
1180
	FidAux *aux;
1181
 
1182
	if(r->fid->qid.type&QTDIR){
1183
		fsreaddir(r);
1184
		return;
1185
	}
1186
 
1187
	aux = r->fid->aux;
1188
	if(nfsRead(aux->auth, r->tag, &aux->handle, r->ifcall.count, r->ifcall.offset, &p, &count, &freeme) < 0){
1189
		responderrstr(r);
1190
		return;
1191
	}
1192
	r->ofcall.data = (char*)p;
1193
	r->ofcall.count = count;
1194
	respond(r, nil);
1195
	free(freeme);
1196
}
1197
 
1198
void
1199
fswrite(Req *r)
1200
{
1201
	uint count;
1202
	FidAux *aux;
1203
 
1204
	aux = r->fid->aux;
1205
	if(nfsWrite(aux->auth, r->tag, &aux->handle, (uchar*)r->ifcall.data, r->ifcall.count, r->ifcall.offset, &count) < 0){
1206
		responderrstr(r);
1207
		return;
1208
	}
1209
	r->ofcall.count = count;
1210
	respond(r, nil);
1211
}
1212
 
1213
void
1214
fsremove(Req *r)
1215
{
1216
	int n;
1217
	FidAux *aux;
1218
 
1219
	aux = r->fid->aux;
1220
	if(aux->name == nil){
1221
		respond(r, "nfs3client botch -- don't know parent handle in remove");
1222
		return;
1223
	}
1224
	if(r->fid->qid.type&QTDIR)
1225
		n = nfsRmdir(aux->auth, r->tag, &aux->parent, aux->name);
1226
	else
1227
		n = nfsRemove(aux->auth, r->tag, &aux->parent, aux->name);
1228
	if(n < 0){
1229
		responderrstr(r);
1230
		return;
1231
	}
1232
	respond(r, nil);
1233
}
1234
 
1235
void
1236
fsstat(Req *r)
1237
{
1238
	FidAux *aux;
1239
	Nfs3Attr attr;
1240
 
1241
	aux = r->fid->aux;
1242
	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1243
		responderrstr(r);
1244
		return;
1245
	}
1246
	memset(&r->d, 0, sizeof r->d);
1247
	attrToDir(&attr, &r->d);
1248
	r->d.name = estrdup9p(aux->name ? aux->name : "???");
1249
	respond(r, nil);
1250
}
1251
 
1252
void
1253
fswstat(Req *r)
1254
{
1255
	int op, sync;
1256
	FidAux *aux;
1257
	Nfs3SetAttr attr;
1258
 
1259
	memset(&attr, 0, sizeof attr);
1260
	aux = r->fid->aux;
1261
 
1262
	/* Fill out stat first to catch errors */
1263
	op = 0;
1264
	sync = 1;
1265
	if(~r->d.mode){
1266
		if(r->d.mode&(DMAPPEND|DMEXCL)){
1267
			respond(r, "wstat -- DMAPPEND and DMEXCL bits not supported");
1268
			return;
1269
		}
1270
		op = 1;
1271
		sync = 0;
1272
		attr.setMode = 1;
1273
		attr.mode = r->d.mode & 0777;
1274
	}
1275
	if(r->d.uid && r->d.uid[0]){
1276
		attr.setUid = 1;
1277
		if(strtouid(r->d.uid, &attr.uid) < 0){
1278
			respond(r, "wstat -- unknown uid");
1279
			return;
1280
		}
1281
		op = 1;
1282
		sync = 0;
1283
	}
1284
	if(r->d.gid && r->d.gid[0]){
1285
		attr.setGid = 1;
1286
		if(strtogid(r->d.gid, &attr.gid) < 0){
1287
			respond(r, "wstat -- unknown gid");
1288
			return;
1289
		}
1290
		op = 1;
1291
		sync = 0;
1292
	}
1293
	if(~r->d.length){
1294
		attr.setSize = 1;
1295
		attr.size = r->d.length;
1296
		op = 1;
1297
		sync = 0;
1298
	}
1299
	if(~r->d.mtime){
1300
		attr.setMtime = Nfs3SetTimeClient;
1301
		attr.mtime.sec = r->d.mtime;
1302
		op = 1;
1303
		sync = 0;
1304
	}
1305
	if(~r->d.atime){
1306
		attr.setAtime = Nfs3SetTimeClient;
1307
		attr.atime.sec = r->d.atime;
1308
		op = 1;
1309
		sync = 0;
1310
	}
1311
 
1312
	/* Try rename first because it's more likely to fail (?) */
1313
	if(r->d.name && r->d.name[0]){
1314
		if(aux->name == nil){
1315
			respond(r, "nfsclient botch -- don't know parent handle in rename");
1316
			return;
1317
		}
1318
		if(nfsRename(aux->auth, r->tag, &aux->parent, aux->name, &aux->parent, r->d.name) < 0){
1319
			responderrstr(r);
1320
			return;
1321
		}
1322
		free(aux->name);
1323
		aux->name = estrdup9p(r->d.name);
1324
		sync = 0;
1325
	}
1326
 
1327
	/*
1328
	 * Now we have a problem.  The rename succeeded
1329
	 * but the setattr could fail.  Sic transit atomicity.
1330
	 */
1331
	if(op){
1332
		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1333
			responderrstr(r);
1334
			return;
1335
		}
1336
	}
1337
 
1338
	if(sync){
1339
		/* NFS commit */
1340
		if(nfsCommit(aux->auth, r->tag, &aux->handle) < 0){
1341
			responderrstr(r);
1342
			return;
1343
		}
1344
	}
1345
 
1346
	respond(r, nil);
1347
}
1348
 
1349
char*
1350
fswalk1(Fid *fid, char *name, void *v)
1351
{
1352
	u1int have;
1353
	ulong tag;
1354
	FidAux *aux;
1355
	Nfs3Attr attr;
1356
	Nfs3Handle h;
1357
 
1358
	tag = *(ulong*)v;
1359
	aux = fid->aux;
1360
 
1361
	if(nfsLookup(aux->auth, tag, &aux->handle, name, &h, &have, &attr) < 0
1362
	|| (!have && nfsGetattr(aux->auth, tag, &h, &attr) < 0)){
1363
		rerrstr(aux->err, sizeof aux->err);
1364
		return aux->err;
1365
	}
1366
 
1367
	aux->parent = aux->handle;
1368
	aux->handle = h;
1369
	free(aux->name);
1370
	if(strcmp(name, "..") == 0)
1371
		aux->name = nil;
1372
	else
1373
		aux->name = estrdup9p(name);
1374
	attrToQid(&attr, &fid->qid);
1375
	return nil;
1376
}
1377
 
1378
char*
1379
fsclone(Fid *fid, Fid *newfid, void*)
1380
{
1381
	FidAux *a, *na;
1382
 
1383
	a = fid->aux;
1384
	na = emalloc9p(sizeof(FidAux));
1385
	*na = *a;
1386
	if(na->name)
1387
		na->name = estrdup9p(na->name);
1388
	newfid->aux = na;
1389
	if(na->auth)
1390
		na->auth->ref++;
1391
	return nil;
1392
}
1393
 
1394
void
1395
fswalk(Req *r)
1396
{
1397
	walkandclone(r, fswalk1, fsclone, &r->tag);
1398
}
1399
 
1400
void
1401
fsflush(Req *r)
1402
{
1403
	Req *or;
1404
 
1405
	/*
1406
	 * Send on the flush channel(s).
1407
	 * The library will make sure the response
1408
	 * is delayed as necessary.
1409
	 */
1410
	or = r->oldreq;
1411
	if(nfscli)
1412
		sendul(nfscli->flushchan, (ulong)or->tag);
1413
	if(mntcli)
1414
		sendul(mntcli->flushchan, (ulong)or->tag);
1415
	respond(r, nil);
1416
}
1417
 
1418
void
1419
fsdispatch(void *v)
1420
{
1421
	Req *r;
1422
 
1423
	r = v;
1424
	switch(r->ifcall.type){
1425
	default:	respond(r, "unknown type");	break;
1426
	case Tattach:	fsattach(r);	break;
1427
	case Topen:	fsopen(r);	break;
1428
	case Tcreate:	fscreate(r);	break;
1429
	case Tread:	fsread(r);	break;
1430
	case Twrite:	fswrite(r);	break;
1431
	case Tremove:	fsremove(r);	break;
1432
	case Tflush:	fsflush(r);	break;
1433
	case Tstat:	fsstat(r);	break;
1434
	case Twstat:	fswstat(r);	break;
1435
	case Twalk:	fswalk(r);	break;
1436
	}
1437
}
1438
 
1439
void
1440
fsthread(void*)
1441
{
1442
	Req *r;
1443
 
1444
	while((r = recvp(fschan)) != nil)
1445
		threadcreate(fsdispatch, r, SunStackSize);
1446
}
1447
 
1448
void
1449
fssend(Req *r)
1450
{
1451
	sendp(fschan, r);
1452
}
1453
 
1454
void
1455
fsdie(Srv*)
1456
{
1457
	threadexitsall(nil);
1458
}
1459
 
1460
Srv fs =
1461
{
1462
.destroyfid =	fsdestroyfid,
1463
.attach=		fssend,
1464
.open=		fssend,
1465
.create=		fssend,
1466
.read=		fssend,
1467
.write=		fssend,
1468
.remove=		fssend,
1469
.flush=		fssend,
1470
.stat=		fssend,
1471
.wstat=		fssend,
1472
.walk=		fssend,
1473
.end=		fsdie
1474
};
1475
 
1476
void
1477
usage(void)
1478
{
1479
	fprint(2, "usage: nfs [-DRv] [-p perm] [-s srvname] [-u passwd group] addr [addr]\n");
1480
	fprint(2, "\taddr - address of portmapper server\n");
1481
	fprint(2, "\taddr addr - addresses of mount server and nfs server\n");
1482
	exits("usage");
1483
}
1484
 
1485
char*
1486
netchangeport(char *addr, uint port, char *buf, uint nbuf)
1487
{
1488
	char *r;
1489
 
1490
	strecpy(buf, buf+nbuf, addr);
1491
	r = strrchr(buf, '!');
1492
	if(r == nil)
1493
		return nil;
1494
	r++;
1495
	seprint(r, buf+nbuf, "%ud", port);
1496
	return buf;
1497
}
1498
 
1499
char mbuf[256], nbuf[256];
1500
char *mountaddr, *nfsaddr;
1501
Channel *csync;
1502
int chattyrpc;
1503
void dialproc(void*);
1504
 
1505
void
1506
threadmain(int argc, char **argv)
1507
{
1508
	char *srvname, *passwd, *group, *addr, *p;
1509
	SunClient *cli;
1510
	int proto;
1511
	uint mport, nport;
1512
	ulong perm;
1513
	Dir d;
1514
 
1515
	perm = 0600;
1516
	passwd = nil;
1517
	group = nil;
1518
	srvname = nil;
1519
	sys = sysname();
1520
	if(sys == nil)
1521
		sys = "plan9";
1522
	ARGBEGIN{
1523
	default:
1524
		usage();
1525
	case 'D':
1526
		chatty9p++;
1527
		break;
1528
	case 'R':
1529
		chattyrpc++;
1530
		break;
1531
	case 'p':
1532
		perm = strtol(EARGF(usage()), &p, 8);
1533
		if(perm==0 || *p != 0)
1534
			usage();
1535
		break;
1536
	case 's':
1537
		srvname = EARGF(usage());
1538
		break;
1539
	case 'u':
1540
		passwd = EARGF(usage());
1541
		group = EARGF(usage());
1542
		break;
1543
	case 'v':
1544
		verbose++;
1545
		break;
1546
	}ARGEND
1547
 
1548
	if(argc != 1 && argc != 2)
1549
		usage();
1550
 
1551
	if(srvname == nil)
1552
		srvname = argv[0];
1553
 
1554
	fmtinstall('B', sunRpcFmt);
1555
	fmtinstall('C', sunCallFmt);
1556
	fmtinstall('H', encodefmt);
1557
	sunFmtInstall(&portProg);
1558
	sunFmtInstall(&nfs3Prog);
1559
	sunFmtInstall(&nfsMount3Prog);
1560
 
1561
	if(passwd && (map = readmap(passwd, group)) == nil)
1562
		fprint(2, "warning: reading %s and %s: %r\n", passwd, group);
1563
 
1564
	if(map == nil)
1565
		map = &emptymap;
1566
 
1567
	if(argc == 1){
1568
		addr = netmkaddr(argv[0], "udp", "portmap");
1569
		if((cli = sunDial(addr)) == nil)
1570
			sysfatal("dial %s: %r", addr);
1571
		cli->chatty = chattyrpc;
1572
		sunClientProg(cli, &portProg);
1573
		if(strstr(addr, "udp!"))
1574
			proto = PortProtoUdp;
1575
		else
1576
			proto = PortProtoTcp;
1577
		if(getport(cli, NfsMount3Program, NfsMount3Version, proto, &mport) < 0)
1578
			sysfatal("lookup mount program port: %r");
1579
		if(getport(cli, Nfs3Program, Nfs3Version, proto, &nport) < 0)
1580
			sysfatal("lookup nfs program port: %r");
1581
		sunClientClose(cli);
1582
		mountaddr = netchangeport(addr, mport, mbuf, sizeof mbuf);
1583
		nfsaddr = netchangeport(addr, nport, nbuf, sizeof nbuf);
1584
		strcat(mountaddr, "!r");
1585
		strcat(nfsaddr, "!r");
1586
		if(verbose)
1587
			fprint(2, "nfs %s %s\n", mountaddr, nfsaddr);
1588
	}else{
1589
		mountaddr = argv[0];
1590
		nfsaddr = argv[1];
1591
	}
1592
 
1593
	/* have to dial in another proc because it creates threads */
1594
	csync = chancreate(sizeof(void*), 0);
1595
	proccreate(dialproc, nil, SunStackSize);
1596
	recvp(csync);
1597
 
1598
	threadpostmountsrv(&fs, srvname, nil, 0);
1599
	if(perm != 0600){
1600
		p = smprint("/srv/%s", srvname);
1601
		if(p){
1602
			nulldir(&d);
1603
			d.mode = perm;
1604
			dirwstat(p, &d);
1605
		}
1606
	}
1607
	threadexits(nil);
1608
}
1609
 
1610
void
1611
dialproc(void*)
1612
{
1613
	rfork(RFNAMEG);
1614
	rfork(RFNOTEG);
1615
	if((mntcli = sunDial(mountaddr)) == nil)
1616
		sysfatal("dial mount program at %s: %r", mountaddr);
1617
	mntcli->chatty = chattyrpc;
1618
	sunClientProg(mntcli, &nfsMount3Prog);
1619
	if(mountNull(0) < 0)
1620
		sysfatal("execute nop with mnt server at %s: %r", mountaddr);
1621
 
1622
	if((nfscli = sunDial(nfsaddr)) == nil)
1623
		sysfatal("dial nfs program at %s: %r", nfsaddr);
1624
	nfscli->chatty = chattyrpc;
1625
	sunClientProg(nfscli, &nfs3Prog);
1626
	if(nfsNull(0) < 0)
1627
		sysfatal("execute nop with nfs server at %s: %r", nfsaddr);
1628
 
1629
	fschan = chancreate(sizeof(Req*), 0);
1630
	threadcreate(fsthread, nil, SunStackSize);
1631
	sendp(csync, 0);
1632
}