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

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-vt/sys/src/cmd/unix/u9fs/u9fs.c – Rev 67

Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */
2
/* plan9.h is first to get the large file support definitions as early as possible */
3
#include <plan9.h>
4
#include <sys/stat.h>	/* for stat, umask */
5
#include <stdlib.h>	/* for malloc */
6
#include <string.h>	/* for strcpy, memmove */
7
#include <pwd.h>	/* for getpwnam, getpwuid */
8
#include <grp.h>	/* for getgrnam, getgrgid */
9
#include <unistd.h>	/* for gethostname, pread, pwrite, read, write */
10
#include <utime.h>	/* for utime */
11
#include <dirent.h>	/* for readdir */
12
#include <errno.h>	/* for errno */
13
#include <stdio.h>	/* for remove [sic] */
14
#include <fcntl.h>	/* for O_RDONLY, etc. */
15
 
16
#include <sys/socket.h>	/* various networking crud */
17
#include <netinet/in.h>
18
#include <netdb.h>
19
 
20
#include <fcall.h>
21
#include <oldfcall.h>
22
#include <u9fs.h>
23
 
24
/* #ifndef because can be given in makefile */
25
#ifndef DEFAULTLOG
26
#define DEFAULTLOG "/tmp/u9fs.log"
27
#endif
28
 
67 7u83 29
 
2 - 30
char *logfile = DEFAULTLOG;
31
 
32
#define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m))
33
 
34
enum {
35
	Tdot = 1,
36
	Tdotdot
37
};
38
 
39
enum {
40
	P9P1,
41
	P9P2000
42
};
43
 
44
typedef struct User User;
45
struct User {
46
	int id;
47
	gid_t defaultgid;
48
	char *name;
49
	char **mem;	/* group members */
50
	int nmem;
51
	User *next;
52
};
53
 
54
struct Fid {
55
	int fid;
56
	char *path;
57
	struct stat st;
58
	User *u;
59
	int omode;
60
	DIR *dir;
61
	int diroffset;
62
	int fd;
63
	struct dirent *dirent;
64
	int direof;
65
	Fid *next;
66
	Fid *prev;
67
	int auth;
68
	void *authmagic;
69
};
70
 
71
void*	emalloc(size_t);
72
void*	erealloc(void*, size_t);
73
char*	estrdup(char*);
74
char*	estrpath(char*, char*, int);
75
void	sysfatal(char*, ...);
76
int	okuser(char*);
77
 
78
void	rversion(Fcall*, Fcall*);
79
void	rauth(Fcall*, Fcall*);
80
void	rattach(Fcall*, Fcall*);
81
void	rflush(Fcall*, Fcall*);
82
void	rclone(Fcall*, Fcall*);
83
void	rwalk(Fcall*, Fcall*);
84
void	ropen(Fcall*, Fcall*);
85
void	rcreate(Fcall*, Fcall*);
86
void	rread(Fcall*, Fcall*);
87
void	rwrite(Fcall*, Fcall*);
88
void	rclunk(Fcall*, Fcall*);
89
void	rstat(Fcall*, Fcall*);
90
void	rwstat(Fcall*, Fcall*);
91
void	rclwalk(Fcall*, Fcall*);
92
void	rremove(Fcall*, Fcall*);
93
 
94
User*	uname2user(char*);
95
User*	gname2user(char*);
96
User*	uid2user(int);
97
User*	gid2user(int);
98
 
99
Fid*	newfid(int, char**);
100
Fid*	oldfidex(int, int, char**);
101
Fid*	oldfid(int, char**);
102
int	fidstat(Fid*, char**);
103
void	freefid(Fid*);
104
 
105
int	userchange(User*, char**);
106
int	userwalk(User*, char**, char*, Qid*, char**);
107
int	useropen(Fid*, int, char**);
108
int	usercreate(Fid*, char*, int, long, char**);
109
int	userremove(Fid*, char**);
110
int	userperm(User*, char*, int, int);
111
int	useringroup(User*, User*);
112
 
113
Qid	stat2qid(struct stat*);
114
 
115
void	getfcallold(int, Fcall*, int);
116
void	putfcallold(int, Fcall*);
117
 
118
char	Eauth[] =	"authentication failed";
119
char	Ebadfid[] =	"fid unknown or out of range";
120
char	Ebadoffset[] =	"bad offset in directory read";
121
char	Ebadusefid[] =	"bad use of fid";
122
char	Edirchange[] =	"wstat can't convert between files and directories";
123
char	Eexist[] =	"file or directory already exists";
124
char	Efidactive[] =	"fid already in use";
125
char	Enotdir[] =	"not a directory";
126
char	Enotingroup[] =	"not a member of proposed group";
127
char	Enotowner[] = 	"only owner can change group in wstat";
128
char	Eperm[] =	"permission denied";
129
char	Especial0[] =	"already attached without access to special files";
130
char	Especial1[] =	"already attached with access to special files";
131
char	Especial[] =	"no access to special file";
132
char	Etoolarge[] =	"i/o count too large";
133
char	Eunknowngroup[] = "unknown group";
134
char	Eunknownuser[] = "unknown user";
135
char	Ewstatbuffer[] = "bogus wstat buffer";
136
 
137
ulong	msize = IOHDRSZ+8192;
138
uchar*	rxbuf;
139
uchar*	txbuf;
140
void*	databuf;
141
int	connected;
142
int	devallowed;
143
char*	autharg;
144
char*	defaultuser;
145
char	hostname[256];
146
char	remotehostname[256];
147
int	chatty9p = 0;
148
int	network = 1;
149
int	old9p = -1;
150
int	authed;
151
User*	none;
152
 
153
Auth *authmethods[] = {	/* first is default */
154
	&authrhosts,
155
	&authp9any,
156
	&authnone,
157
};
158
 
159
Auth *auth;
160
 
67 7u83 161
 
162
 
2 - 163
/*
164
 * frogs: characters not valid in plan9
165
 * filenames, keep this list in sync with
166
 * /sys/src/9/port/chan.c:1656
167
 */
168
char isfrog[256]={
169
	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
170
	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
171
	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
172
	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
173
	['/']	1,
174
	[0x7f]	1,
175
};
176
 
67 7u83 177
int groupchange(User *u, User *g, char **ep);
178
 
179
 
180
 
2 - 181
void
182
getfcallnew(int fd, Fcall *fc, int have)
183
{
184
	int len;
185
 
186
	if(have > BIT32SZ)
187
		sysfatal("cannot happen");
188
 
189
	if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have)
190
		sysfatal("couldn't read message");
191
 
192
	len = GBIT32(rxbuf);
193
	if(len <= BIT32SZ)
194
		sysfatal("bogus message");
195
 
196
	len -= BIT32SZ;
197
	if(readn(fd, rxbuf+BIT32SZ, len) != len)
198
		sysfatal("short message");
199
 
200
	if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ)
201
		sysfatal("badly sized message type %d", rxbuf[0]);
202
}
203
 
204
void
205
getfcallold(int fd, Fcall *fc, int have)
206
{
207
	int len, n;
208
 
209
	if(have > 3)
210
		sysfatal("cannot happen");
211
 
212
	if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have)
213
		sysfatal("couldn't read message");
214
 
215
	len = oldhdrsize(rxbuf[0]);
216
	if(len < 3)
217
		sysfatal("bad message %d", rxbuf[0]);
218
	if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3)
219
		sysfatal("couldn't read message");
220
 
221
	n = iosize(rxbuf);
222
	if(readn(fd, rxbuf+len, n) != n)
223
		sysfatal("couldn't read message");
224
	len += n;
225
 
226
	if(convM2Sold(rxbuf, len, fc) != len)
227
		sysfatal("badly sized message type %d", rxbuf[0]);
228
}
229
 
230
void
231
putfcallnew(int wfd, Fcall *tx)
232
{
233
	uint n;
234
 
235
	if((n = convS2M(tx, txbuf, msize)) == 0)
236
		sysfatal("couldn't format message type %d", tx->type);
237
	if(write(wfd, txbuf, n) != n)
238
		sysfatal("couldn't send message");
239
}
240
 
241
void
242
putfcallold(int wfd, Fcall *tx)
243
{
244
	uint n;
245
 
246
	if((n = convS2Mold(tx, txbuf, msize)) == 0)
247
		sysfatal("couldn't format message type %d", tx->type);
248
	if(write(wfd, txbuf, n) != n)
249
		sysfatal("couldn't send message");
250
}
251
 
252
void
253
getfcall(int fd, Fcall *fc)
254
{
255
	if(old9p == 1){
256
		getfcallold(fd, fc, 0);
257
		return;
258
	}
259
	if(old9p == 0){
260
		getfcallnew(fd, fc, 0);
261
		return;
262
	}
263
 
264
	/* auto-detect */
265
	if(readn(fd, rxbuf, 3) != 3)
266
		sysfatal("couldn't read message");
267
 
268
	/* is it an old (9P1) message? */
269
	if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){
270
		old9p = 1;
271
		getfcallold(fd, fc, 3);
272
		return;
273
	}
274
 
275
	getfcallnew(fd, fc, 3);
276
	old9p = 0;
277
}
278
 
279
void
280
seterror(Fcall *f, char *error)
281
{
282
	f->type = Rerror;
283
	f->ename = error ? error : "programmer error";
284
}
285
 
286
int
287
isowner(User *u, Fid *f)
288
{
289
	return u->id == f->st.st_uid;
290
}
291
 
292
 
293
 
294
void
295
serve(int rfd, int wfd)
296
{
297
	Fcall rx, tx;
298
 
299
	for(;;){
300
		getfcall(rfd, &rx);
301
 
302
		if(chatty9p)
303
			fprint(2, "<- %F\n", &rx);
304
 
305
		memset(&tx, 0, sizeof tx);
306
		tx.type = rx.type+1;
307
		tx.tag = rx.tag;
308
		switch(rx.type){
309
		case Tflush:
310
			break;
311
		case Tversion:
312
			rversion(&rx, &tx);
313
			break;
314
		case Tauth:
315
			rauth(&rx, &tx);
316
			break;
317
		case Tattach:
318
			rattach(&rx, &tx);
319
			break;
320
		case Twalk:
321
			rwalk(&rx, &tx);
322
			break;
323
		case Tstat:
324
			tx.stat = databuf;
325
			rstat(&rx, &tx);
326
			break;
327
		case Twstat:
328
			rwstat(&rx, &tx);
329
			break;
330
		case Topen:
331
			ropen(&rx, &tx);
332
			break;
333
		case Tcreate:
334
			rcreate(&rx, &tx);
335
			break;
336
		case Tread:
337
			tx.data = databuf;
338
			rread(&rx, &tx);
339
			break;
340
		case Twrite:
341
			rwrite(&rx, &tx);
342
			break;
343
		case Tclunk:
344
			rclunk(&rx, &tx);
345
			break;
346
		case Tremove:
347
			rremove(&rx, &tx);
348
			break;
349
		default:
350
			fprint(2, "unknown message %F\n", &rx);
351
			seterror(&tx, "bad message");
352
			break;
353
		}
354
 
355
		if(chatty9p)
356
			fprint(2, "-> %F\n", &tx);
357
 
358
		(old9p ? putfcallold : putfcallnew)(wfd, &tx);
359
	}
360
}
361
 
362
void
363
rversion(Fcall *rx, Fcall *tx)
364
{
365
	if(msize > rx->msize)
366
		msize = rx->msize;
367
	tx->msize = msize;
368
	if(strncmp(rx->version, "9P", 2) != 0)
369
		tx->version = "unknown";
370
	else
371
		tx->version = "9P2000";
372
}
373
 
374
void
375
rauth(Fcall *rx, Fcall *tx)
376
{
377
	char *e;
378
 
379
	if((e = auth->auth(rx, tx)) != nil)
380
		seterror(tx, e);
381
}
382
 
383
void
384
rattach(Fcall *rx, Fcall *tx)
385
{
386
	char *e;
387
	Fid *fid;
388
	User *u;
389
 
390
	if(rx->aname == nil)
391
		rx->aname = "";
392
 
393
	if(strcmp(rx->aname, "device") == 0){
394
		if(connected && !devallowed){
395
			seterror(tx, Especial0);
396
			return;
397
		}
398
		devallowed = 1;
399
	}else{
400
		if(connected && devallowed){
401
			seterror(tx, Especial1);
402
			return;
403
		}
404
	}
405
 
406
	if(strcmp(rx->uname, "none") == 0){
407
		if(authed == 0){
408
			seterror(tx, Eauth);
409
			return;
410
		}
411
		if (none != nil)
412
			rx->uname = none->name;
413
	} else {
414
		if((e = auth->attach(rx, tx)) != nil){
415
			seterror(tx, e);
416
			return;
417
		}
418
		authed++;
419
	}
420
 
421
	if((fid = newfid(rx->fid, &e)) == nil){
422
		seterror(tx, e);
423
		return;
424
	}
425
	fid->path = estrdup("/");
426
	if(fidstat(fid, &e) < 0){
427
		seterror(tx, e);
428
		freefid(fid);
429
		return;
430
	}
431
 
432
	if(defaultuser)
433
		rx->uname = defaultuser;
434
 
435
	if((u = uname2user(rx->uname)) == nil
436
	|| (!defaultuser && u->id == 0)){
437
		/* we don't know anyone named root... */
438
		seterror(tx, Eunknownuser);
439
		freefid(fid);
440
		return;
441
	}
442
 
443
	fid->u = u;
444
	tx->qid = stat2qid(&fid->st);
445
	return;
446
}
447
 
448
void
449
rwalk(Fcall *rx, Fcall *tx)
450
{
451
	int i;
452
	char *path, *e;
453
	Fid *fid, *nfid;
454
 
455
	e = nil;
456
	if((fid = oldfid(rx->fid, &e)) == nil){
457
		seterror(tx, e);
458
		return;
459
	}
460
 
461
	if(fid->omode != -1){
462
		seterror(tx, Ebadusefid);
463
		return;
464
	}
465
 
466
	if(fidstat(fid, &e) < 0){
467
		seterror(tx, e);
468
		return;
469
	}
470
 
471
	if(!S_ISDIR(fid->st.st_mode) && rx->nwname){
472
		seterror(tx, Enotdir);
473
		return;
474
	}
475
 
476
	nfid = nil;
477
	if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){
478
		seterror(tx, e);
479
		return;
480
	}
481
 
482
	path = estrdup(fid->path);
483
	e = nil;
484
	for(i=0; i<rx->nwname; i++)
485
		if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0)
486
			break;
487
 
488
	if(i == rx->nwname){		/* successful clone or walk */
489
		tx->nwqid = i;
490
		if(nfid){
491
			nfid->path = path;
492
			nfid->u = fid->u;
493
		}else{
494
			free(fid->path);
495
			fid->path = path;
496
		}
497
	}else{
498
		if(i > 0)		/* partial walk? */
499
			tx->nwqid = i;
500
		else
501
			seterror(tx, e);
502
 
503
		if(nfid)		/* clone implicit new fid */
504
			freefid(nfid);
505
		free(path);
506
	}
507
	return;
508
}
509
 
510
void
511
ropen(Fcall *rx, Fcall *tx)
512
{
513
	char *e;
514
	Fid *fid;
515
 
516
	if((fid = oldfid(rx->fid, &e)) == nil){
517
		seterror(tx, e);
518
		return;
519
	}
520
 
521
	if(fid->omode != -1){
522
		seterror(tx, Ebadusefid);
523
		return;
524
	}
525
 
526
	if(fidstat(fid, &e) < 0){
527
		seterror(tx, e);
528
		return;
529
	}
530
 
531
	if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){
532
		seterror(tx, Especial);
533
		return;
534
	}
535
 
536
	if(useropen(fid, rx->mode, &e) < 0){
537
		seterror(tx, e);
538
		return;
539
	}
540
 
541
	tx->iounit = 0;
542
	tx->qid = stat2qid(&fid->st);
543
}
544
 
545
void
546
rcreate(Fcall *rx, Fcall *tx)
547
{
548
	char *e;
549
	Fid *fid;
550
 
551
	if((fid = oldfid(rx->fid, &e)) == nil){
552
		seterror(tx, e);
553
		return;
554
	}
555
 
556
	if(fid->omode != -1){
557
		seterror(tx, Ebadusefid);
558
		return;
559
	}
560
 
561
	if(fidstat(fid, &e) < 0){
562
		seterror(tx, e);
563
		return;
564
	}
565
 
566
	if(!S_ISDIR(fid->st.st_mode)){
567
		seterror(tx, Enotdir);
568
		return;
569
	}
570
 
571
	if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){
572
		seterror(tx, e);
573
		return;
574
	}
575
 
576
	if(fidstat(fid, &e) < 0){
577
		seterror(tx, e);
578
		return;
579
	}
580
 
581
	tx->iounit = 0;
582
	tx->qid = stat2qid(&fid->st);
583
}
584
 
585
uchar
586
modebyte(struct stat *st)
587
{
588
	uchar b;
589
 
590
	b = 0;
591
 
592
	if(S_ISDIR(st->st_mode))
593
		b |= QTDIR;
594
 
595
	/* no way to test append-only */
596
	/* no real way to test exclusive use, but mark devices as such */
597
	if(S_ISSPECIAL(st->st_mode))
598
		b |= QTEXCL;
599
 
600
	return b;
601
}
602
 
603
ulong
604
plan9mode(struct stat *st)
605
{
606
	return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777);
607
}
608
 
609
/* 
610
 * this is for chmod, so don't worry about S_IFDIR
611
 */
612
mode_t
613
unixmode(Dir *d)
614
{
615
	return (mode_t)(d->mode&0777);
616
}
617
 
618
Qid
619
stat2qid(struct stat *st)
620
{
621
	uchar *p, *ep, *q;
622
	Qid qid;
623
 
624
	/*
625
	 * For now, ignore the device number.
626
	 */
627
	qid.path = 0;
628
	p = (uchar*)&qid.path;
629
	ep = p+sizeof(qid.path);
630
	q = p+sizeof(ino_t);
631
	if(q > ep){
632
		fprint(2, "warning: inode number too big\n");
633
		q = ep;
634
	}
635
	memmove(p, &st->st_ino, q-p);
636
	q = q+sizeof(dev_t);
637
	if(q > ep){
638
/*
639
 *		fprint(2, "warning: inode number + device number too big %d+%d\n",
640
 *			sizeof(ino_t), sizeof(dev_t));
641
 */
642
		q = ep - sizeof(dev_t);
643
		if(q < p)
644
			fprint(2, "warning: device number too big by itself\n");
645
		else
646
			*(dev_t*)q ^= st->st_dev;
647
	}
648
 
649
	qid.vers = st->st_mtime ^ (st->st_size << 8);
650
	qid.type = modebyte(st);
651
	return qid;
652
}
653
 
654
char *
655
enfrog(char *src)
656
{
657
	char *d, *dst;
658
	uchar *s;
659
 
660
	d = dst = emalloc(strlen(src)*3 + 1);
661
	for (s = (uchar *)src; *s; s++)
662
		if(isfrog[*s] || *s == '\\')
663
			d += sprintf(d, "\\%02x", *s);
664
		else
665
			*d++ = *s;
666
	*d = 0;
667
	return dst;
668
}
669
 
670
char *
671
defrog(char *s)
672
{
673
	char *d, *dst, buf[3];
674
 
675
	d = dst = emalloc(strlen(s) + 1);
676
	for(; *s; s++)
677
		if(*s == '\\' && strlen(s) >= 3){
678
			buf[0] = *++s;			/* skip \ */
679
			buf[1] = *++s;
680
			buf[2] = 0;
681
			*d++ = strtoul(buf, NULL, 16);
682
		} else
683
			*d++ = *s;
684
	*d = 0;
685
	return dst;
686
}
687
 
688
void
689
stat2dir(char *path, struct stat *st, Dir *d)
690
{
691
	User *u;
692
	char *q, *p, *npath;
693
 
694
	memset(d, 0, sizeof(*d));
695
	d->qid = stat2qid(st);
696
	d->mode = plan9mode(st);
697
	d->atime = st->st_atime;
698
	d->mtime = st->st_mtime;
699
	d->length = st->st_size;
700
 
701
	d->uid = (u = uid2user(st->st_uid)) ? u->name : "???";
702
	d->gid = (u = gid2user(st->st_gid)) ? u->name : "???";
703
	d->muid = "";
704
 
705
	if((q = strrchr(path, '/')) != nil)
706
		d->name = enfrog(q+1);
707
	else
708
		d->name = enfrog(path);
709
}
710
 
711
void
712
rread(Fcall *rx, Fcall *tx)
713
{
714
	char *e, *path;
715
	uchar *p, *ep;
716
	int n;
717
	Fid *fid;
718
	Dir d;
719
	struct stat st;
720
 
721
	if(rx->count > msize-IOHDRSZ){
722
		seterror(tx, Etoolarge);
723
		return;
724
	}
725
 
726
	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
727
		seterror(tx, e);
728
		return;
729
	}
730
 
731
	if (fid->auth) {
732
		char *e;
733
		e = auth->read(rx, tx);
734
		if (e)
735
			seterror(tx, e);
736
		return;
737
	}
738
 
739
	if(fid->omode == -1 || (fid->omode&3) == OWRITE){
740
		seterror(tx, Ebadusefid);
741
		return;
742
	}
743
 
744
	if(fid->dir){
745
		if(rx->offset != fid->diroffset){
746
			if(rx->offset != 0){
747
				seterror(tx, Ebadoffset);
748
				return;
749
			}
750
			rewinddir(fid->dir);
751
			fid->diroffset = 0;
752
			fid->direof = 0;
753
		}
754
		if(fid->direof){
755
			tx->count = 0;
756
			return;
757
		}
758
 
759
		p = (uchar*)tx->data;
760
		ep = (uchar*)tx->data+rx->count;
761
		for(;;){
762
			if(p+BIT16SZ >= ep)
763
				break;
764
			if(fid->dirent == nil)	/* one entry cache for when convD2M fails */
765
				if((fid->dirent = readdir(fid->dir)) == nil){
766
					fid->direof = 1;
767
					break;
768
				}
769
			if(strcmp(fid->dirent->d_name, ".") == 0
770
			|| strcmp(fid->dirent->d_name, "..") == 0){
771
				fid->dirent = nil;
772
				continue;
773
			}
774
			path = estrpath(fid->path, fid->dirent->d_name, 0);
775
			memset(&st, 0, sizeof st);
776
			if(stat(path, &st) < 0){
777
				fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno));
778
				fid->dirent = nil;
779
				free(path);
780
				continue;
781
			}
782
			free(path);
783
			stat2dir(fid->dirent->d_name, &st, &d);
784
			if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ)
785
				break;
786
			p += n;
787
			fid->dirent = nil;
788
		}
789
		tx->count = p - (uchar*)tx->data;
790
		fid->diroffset += tx->count;
791
	}else{
792
		if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){
793
			seterror(tx, strerror(errno));
794
			return;
795
		}
796
		tx->count = n;
797
	}
798
}
799
 
800
void
801
rwrite(Fcall *rx, Fcall *tx)
802
{
803
	char *e;
804
	Fid *fid;
805
	int n;
806
 
807
	if(rx->count > msize-IOHDRSZ){
808
		seterror(tx, Etoolarge);
809
		return;
810
	}
811
 
812
	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
813
		seterror(tx, e);
814
		return;
815
	}
816
 
817
	if (fid->auth) {
818
		char *e;
819
		e = auth->write(rx, tx);
820
		if (e)
821
			seterror(tx, e);
822
		return;
823
	}
824
 
825
	if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){
826
		seterror(tx, Ebadusefid);
827
		return;
828
	}
829
 
830
	if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){
831
		seterror(tx, strerror(errno));
832
		return;
833
	}
834
	tx->count = n;
835
}
836
 
837
void
838
rclunk(Fcall *rx, Fcall *tx)
839
{
840
	char *e;
841
	Fid *fid;
842
 
843
	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
844
		seterror(tx, e);
845
		return;
846
	}
847
	if (fid->auth) {
848
		if (auth->clunk) {
849
			e = (*auth->clunk)(rx, tx);
850
			if (e) {
851
				seterror(tx, e);
852
				return;
853
			}
854
		}
855
	}
856
	else if(fid->omode != -1 && fid->omode&ORCLOSE)
857
		remove(fid->path);
858
	freefid(fid);
859
}
860
 
861
void
862
rremove(Fcall *rx, Fcall *tx)
863
{
864
	char *e;
865
	Fid *fid;
866
 
867
	if((fid = oldfid(rx->fid, &e)) == nil){
868
		seterror(tx, e);
869
		return;
870
	}
871
	if(userremove(fid, &e) < 0)
872
		seterror(tx, e);
873
	freefid(fid);
874
}
875
 
876
void
877
rstat(Fcall *rx, Fcall *tx)
878
{
879
	char *e;
880
	Fid *fid;
881
	Dir d;
882
 
883
	if((fid = oldfid(rx->fid, &e)) == nil){
884
		seterror(tx, e);
885
		return;
886
	}
887
 
888
	if(fidstat(fid, &e) < 0){
889
		seterror(tx, e);
890
		return;
891
	}
892
 
893
	stat2dir(fid->path, &fid->st, &d);
894
	if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ)
895
		seterror(tx, "convD2M fails");
896
}
897
 
898
void
899
rwstat(Fcall *rx, Fcall *tx)
900
{
901
	char *e;
902
	char *p, *old, *new, *dir;
903
	gid_t gid;
904
	Dir d;
905
	Fid *fid;
906
 
907
	if((fid = oldfid(rx->fid, &e)) == nil){
908
		seterror(tx, e);
909
		return;
910
	}
911
 
912
	/*
913
	 * wstat is supposed to be atomic.
914
	 * we check all the things we can before trying anything.
915
	 * still, if we are told to truncate a file and rename it and only
916
	 * one works, we're screwed.  in such cases we leave things
917
	 * half broken and return an error.  it's hardly perfect.
918
	 */
919
	if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){
920
		seterror(tx, Ewstatbuffer);
921
		return;
922
	}
923
 
924
	if(fidstat(fid, &e) < 0){
925
		seterror(tx, e);
926
		return;
927
	}
928
 
929
	/*
930
	 * The casting is necessary because d.mode is ulong and might,
931
	 * on some systems, be 64 bits.  We only want to compare the
932
	 * bottom 32 bits, since that's all that gets sent in the protocol.
933
	 * 
934
	 * Same situation for d.mtime and d.length (although that last check
935
	 * is admittedly superfluous, given the current lack of 128-bit machines).
936
	 */
937
	gid = (gid_t)-1;
938
	if(d.gid[0] != '\0'){
939
		User *g;
940
 
941
		g = gname2user(d.gid);
942
		if(g == nil){
943
			seterror(tx, Eunknowngroup);
944
			return;
945
		}
946
		gid = (gid_t)g->id;
947
 
948
		if(groupchange(fid->u, gid2user(gid), &e) < 0){
949
			seterror(tx, e);
950
			return;
951
		}		
952
	}
953
 
954
	if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){
955
		seterror(tx, Edirchange);
956
		return;
957
	}
958
 
959
	if(strcmp(fid->path, "/") == 0){
960
		seterror(tx, "no wstat of root");
961
		return;
962
	}
963
 
964
	/*
965
	 * try things in increasing order of harm to the file.
966
	 * mtime should come after truncate so that if you
967
	 * do both the mtime actually takes effect, but i'd rather
968
	 * leave truncate until last.
969
	 * (see above comment about atomicity).
970
	 */
971
	if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){
972
		if(chatty9p)
973
			fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d));
974
		seterror(tx, strerror(errno));
975
		return;
976
	}
977
 
978
	if((u32int)d.mtime != (u32int)~0){
979
		struct utimbuf t;
980
 
981
		t.actime = 0;
982
		t.modtime = d.mtime;
983
		if(utime(fid->path, &t) < 0){
984
			if(chatty9p)
985
				fprint(2, "utime(%s) failed\n", fid->path);
986
			seterror(tx, strerror(errno));
987
			return;
988
		}
989
	}
990
 
991
	if(gid != (gid_t)-1 && gid != fid->st.st_gid){
992
		if(chown(fid->path, (uid_t)-1, gid) < 0){
993
			if(chatty9p)
994
				fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid);
995
			seterror(tx, strerror(errno));
996
			return;
997
		}
998
	}
999
 
1000
	if(d.name[0]){
1001
		old = fid->path;
1002
		dir = estrdup(fid->path);
1003
		if((p = strrchr(dir, '/')) > dir)
1004
			*p = '\0';
1005
		else{
1006
			seterror(tx, "whoops: can't happen in u9fs");
1007
			return;
1008
		}
1009
		new = estrpath(dir, d.name, 1);
1010
		if(strcmp(old, new) != 0 && rename(old, new) < 0){
1011
			if(chatty9p)
1012
				fprint(2, "rename(%s, %s) failed\n", old, new);
1013
			seterror(tx, strerror(errno));
1014
			free(new);
1015
			free(dir);
1016
			return;
1017
		}
1018
		fid->path = new;
1019
		free(old);
1020
		free(dir);
1021
	}
1022
 
1023
	if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){
1024
		fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length);
1025
		seterror(tx, strerror(errno));
1026
		return;
1027
	}
1028
}
1029
 
1030
/*
1031
 * we keep a table by numeric id.  by name lookups happen infrequently
1032
 * while by-number lookups happen once for every directory entry read
1033
 * and every stat request.
1034
 */
1035
User *utab[64];
1036
User *gtab[64];
1037
 
1038
User*
1039
adduser(struct passwd *p)
1040
{
1041
	User *u;
1042
 
1043
	u = emalloc(sizeof(*u));
1044
	u->id = p->pw_uid;
1045
	u->name = estrdup(p->pw_name);
1046
	u->next = utab[p->pw_uid%nelem(utab)];
1047
	u->defaultgid = p->pw_gid;
1048
	utab[p->pw_uid%nelem(utab)] = u;
1049
	return u;
1050
}
1051
 
1052
int
1053
useringroup(User *u, User *g)
1054
{
1055
	int i;
1056
 
1057
	for(i=0; i<g->nmem; i++)
1058
		if(strcmp(g->mem[i], u->name) == 0)
1059
			return 1;
1060
 
1061
	/*
1062
	 * Hack around common Unix problem that everyone has
1063
	 * default group "user" but /etc/group lists no members.
1064
	 */
1065
	if(u->defaultgid == g->id)
1066
		return 1;
1067
	return 0;
1068
}
1069
 
1070
User*
1071
addgroup(struct group *g)
1072
{
1073
	User *u;
1074
	char **p;
1075
	int n;
1076
 
1077
	u = emalloc(sizeof(*u));
1078
	n = 0;
1079
	for(p=g->gr_mem; *p; p++)
1080
		n++;
1081
	u->mem = emalloc(sizeof(u->mem[0])*n);
1082
	n = 0;
1083
	for(p=g->gr_mem; *p; p++)
1084
		u->mem[n++] = estrdup(*p);
1085
	u->nmem = n;
1086
	u->id = g->gr_gid;
1087
	u->name = estrdup(g->gr_name);
1088
	u->next = gtab[g->gr_gid%nelem(gtab)];
1089
	gtab[g->gr_gid%nelem(gtab)] = u;
1090
	return u;
1091
}
1092
 
1093
User*
1094
uname2user(char *name)
1095
{
1096
	int i;
1097
	User *u;
1098
	struct passwd *p;
1099
 
1100
	for(i=0; i<nelem(utab); i++)
1101
		for(u=utab[i]; u; u=u->next)
1102
			if(strcmp(u->name, name) == 0)
1103
				return u;
1104
 
1105
	if((p = getpwnam(name)) == nil)
1106
		return nil;
1107
	return adduser(p);
1108
}
1109
 
1110
User*
1111
uid2user(int id)
1112
{
1113
	User *u;
1114
	struct passwd *p;
1115
 
1116
	for(u=utab[id%nelem(utab)]; u; u=u->next)
1117
		if(u->id == id)
1118
			return u;
1119
 
1120
	if((p = getpwuid(id)) == nil)
1121
		return nil;
1122
	return adduser(p);
1123
}
1124
 
1125
User*
1126
gname2user(char *name)
1127
{
1128
	int i;
1129
	User *u;
1130
	struct group *g;
1131
 
1132
	for(i=0; i<nelem(gtab); i++)
1133
		for(u=gtab[i]; u; u=u->next)
1134
			if(strcmp(u->name, name) == 0)
1135
				return u;
1136
 
1137
	if((g = getgrnam(name)) == nil)
1138
		return nil;
1139
	return addgroup(g);
1140
}
1141
 
1142
User*
1143
gid2user(int id)
1144
{
1145
	User *u;
1146
	struct group *g;
1147
 
1148
	for(u=gtab[id%nelem(gtab)]; u; u=u->next)
1149
		if(u->id == id)
1150
			return u;
1151
 
1152
	if((g = getgrgid(id)) == nil)
1153
		return nil;
1154
	return addgroup(g);
1155
}
1156
 
1157
void
1158
sysfatal(char *fmt, ...)
1159
{
1160
	char buf[1024];
1161
	va_list va, temp;
1162
 
1163
	va_start(va, fmt);
1164
	va_copy(temp, va);
1165
	doprint(buf, buf+sizeof buf, fmt, &temp);
1166
	va_end(temp);
1167
	va_end(va);
1168
	fprint(2, "u9fs: %s\n", buf);
1169
	fprint(2, "last unix error: %s\n", strerror(errno));
1170
	exit(1);
1171
}
1172
 
1173
void*
1174
emalloc(size_t n)
1175
{
1176
	void *p;
1177
 
1178
	if(n == 0)
1179
		n = 1;
1180
	p = malloc(n);
1181
	if(p == 0)
1182
		sysfatal("malloc(%ld) fails", (long)n);
1183
	memset(p, 0, n);
1184
	return p;
1185
}
1186
 
1187
void*
1188
erealloc(void *p, size_t n)
1189
{
1190
	if(p == 0)
1191
		p = malloc(n);
1192
	else
1193
		p = realloc(p, n);
1194
	if(p == 0)
1195
		sysfatal("realloc(..., %ld) fails", (long)n);
1196
	return p;
1197
}
1198
 
1199
char*
1200
estrdup(char *p)
1201
{
1202
	p = strdup(p);
1203
	if(p == 0)
1204
		sysfatal("strdup(%.20s) fails", p);
1205
	return p;
1206
}
1207
 
1208
char*
1209
estrpath(char *p, char *q, int frog)
1210
{
1211
	char *r, *s;
1212
 
1213
	if(strcmp(q, "..") == 0){
1214
		r = estrdup(p);
1215
		if((s = strrchr(r, '/')) && s > r)
1216
			*s = '\0';
1217
		else if(s == r)
1218
			s[1] = '\0';
1219
		return r;
1220
	}
1221
 
1222
	if(frog)
1223
		q = defrog(q);
1224
	else
1225
		q = strdup(q);
1226
	r = emalloc(strlen(p)+1+strlen(q)+1);
1227
	strcpy(r, p);
1228
	if(r[0]=='\0' || r[strlen(r)-1] != '/')
1229
		strcat(r, "/");
1230
	strcat(r, q);
1231
	free(q);
1232
	return r;
1233
}
1234
 
1235
Fid *fidtab[1];
1236
 
1237
Fid*
1238
lookupfid(int fid)
1239
{
1240
	Fid *f;
1241
 
1242
	for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next)
1243
		if(f->fid == fid)
1244
			return f;
1245
	return nil;
1246
}
1247
 
1248
Fid*
1249
newfid(int fid, char **ep)
1250
{
1251
	Fid *f;
1252
 
1253
	if(lookupfid(fid) != nil){
1254
		*ep = Efidactive;
1255
		return nil;
1256
	}
1257
 
1258
	f = emalloc(sizeof(*f));
1259
	f->next = fidtab[fid%nelem(fidtab)];
1260
	if(f->next)
1261
		f->next->prev = f;
1262
	fidtab[fid%nelem(fidtab)] = f;
1263
	f->fid = fid;
1264
	f->fd = -1;
1265
	f->omode = -1;
1266
	return f;
1267
}
1268
 
1269
Fid*
1270
newauthfid(int fid, void *magic, char **ep)
1271
{
1272
	Fid *af;
1273
	af = newfid(fid, ep);
1274
	if (af == nil)
1275
		return nil;
1276
	af->auth = 1;
1277
	af->authmagic = magic;
1278
	return af;
1279
}
1280
 
1281
Fid*
1282
oldfidex(int fid, int auth, char **ep)
1283
{
1284
	Fid *f;
1285
 
1286
	if((f = lookupfid(fid)) == nil){
1287
		*ep = Ebadfid;
1288
		return nil;
1289
	}
1290
 
1291
	if (auth != -1 && f->auth != auth) {
1292
		*ep = Ebadfid;
1293
		return nil;
1294
	}
1295
 
1296
	if (!f->auth) {
1297
		if(userchange(f->u, ep) < 0)
1298
			return nil;
1299
	}
1300
 
1301
	return f;
1302
}
1303
 
1304
Fid*
1305
oldfid(int fid, char **ep)
1306
{
1307
	return oldfidex(fid, 0, ep);
1308
}
1309
 
1310
Fid*
1311
oldauthfid(int fid, void **magic, char **ep)
1312
{
1313
	Fid *af;
1314
	af = oldfidex(fid, 1, ep);
1315
	if (af == nil)
1316
		return nil;
1317
	*magic = af->authmagic;
1318
	return af;
1319
}
1320
 
1321
void
1322
freefid(Fid *f)
1323
{
1324
	if(f->prev)
1325
		f->prev->next = f->next;
1326
	else
1327
		fidtab[f->fid%nelem(fidtab)] = f->next;
1328
	if(f->next)
1329
		f->next->prev = f->prev;
1330
	if(f->dir)
1331
		closedir(f->dir);
1332
	if(f->fd)
1333
		close(f->fd);
1334
	free(f->path);
1335
	free(f);
1336
}
1337
 
1338
int
1339
fidstat(Fid *fid, char **ep)
1340
{
1341
	if(stat(fid->path, &fid->st) < 0){
1342
		fprint(2, "fidstat(%s) failed\n", fid->path);
1343
		if(ep)
1344
			*ep = strerror(errno);
1345
		return -1;
1346
	}
1347
	if(S_ISDIR(fid->st.st_mode))
1348
		fid->st.st_size = 0;
1349
	return 0;
1350
}
1351
 
1352
int
1353
userchange(User *u, char **ep)
1354
{
1355
	if(defaultuser)
1356
		return 0;
1357
 
1358
	if(setreuid(0, 0) < 0){
1359
		fprint(2, "setreuid(0, 0) failed\n");
1360
		*ep = "cannot setuid back to root";
1361
		return -1;
1362
	}
1363
 
1364
	/*
1365
	 * Initgroups does not appear to be SUSV standard.
1366
	 * But it exists on SGI and on Linux, which makes me
1367
	 * think it's standard enough.  We have to do something
1368
	 * like this, and the closest other function I can find is
1369
	 * setgroups (which initgroups eventually calls).
1370
	 * Setgroups is the same as far as standardization though,
1371
	 * so we're stuck using a non-SUSV call.  Sigh.
1372
	 */
1373
	if(initgroups(u->name, u->defaultgid) < 0)
1374
		fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno));
1375
 
1376
	if(setreuid(-1, u->id) < 0){
1377
		fprint(2, "setreuid(-1, %s) failed\n", u->name);
1378
		*ep = strerror(errno);
1379
		return -1;
1380
	}
1381
 
1382
	return 0;
1383
}
1384
 
1385
/*
1386
 * We do our own checking here, then switch to root temporarily
1387
 * to set our gid.  In a perfect world, you'd be allowed to set your
1388
 * egid to any of the supplemental groups of your euid, but this
1389
 * is not the case on Linux 2.2.14 (and perhaps others).
1390
 *
1391
 * This is a race, of course, but it's a race against processes
1392
 * that can edit the group lists.  If you can do that, you can
1393
 * change your own group without our help.
1394
 */
1395
int
1396
groupchange(User *u, User *g, char **ep)
1397
{
1398
	if(g == nil)
1399
		return -1;
1400
	if(!useringroup(u, g)){
1401
		if(chatty9p)
1402
			fprint(2, "%s not in group %s\n", u->name, g->name);
1403
		*ep = Enotingroup;
1404
		return -1;
1405
	}
1406
 
1407
	setreuid(0,0);
1408
	if(setregid(-1, g->id) < 0){
1409
		fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id);
1410
		*ep = strerror(errno);
1411
		return -1;
1412
	}
1413
	if(userchange(u, ep) < 0)
1414
		return -1;
1415
 
1416
	return 0;
1417
}
1418
 
1419
 
1420
/*
1421
 * An attempt to enforce permissions by looking at the 
1422
 * file system.  Separation of checking permission and
1423
 * actually performing the action is a terrible idea, of 
1424
 * course, so we use setreuid for most of the permission
1425
 * enforcement.  This is here only so we can give errors
1426
 * on open(ORCLOSE) in some cases.
1427
 */
1428
int
1429
userperm(User *u, char *path, int type, int need)
1430
{
1431
	char *p, *q;
1432
	int i, have;
1433
	struct stat st;
1434
	User *g;
1435
 
1436
	switch(type){
1437
	default:
1438
		fprint(2, "bad type %d in userperm\n", type);
1439
		return -1;
1440
	case Tdot:
1441
		if(stat(path, &st) < 0){
1442
			fprint(2, "userperm: stat(%s) failed\n", path);
1443
			return -1;
1444
		}
1445
		break;
1446
	case Tdotdot:
1447
		p = estrdup(path);
1448
		if((q = strrchr(p, '/'))==nil){
1449
			fprint(2, "userperm(%s, ..): bad path\n", p);
1450
			free(p);
1451
			return -1;
1452
		}
1453
		if(q > p)
1454
			*q = '\0';
1455
		else
1456
			*(q+1) = '\0';
1457
		if(stat(p, &st) < 0){
1458
			fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n",
1459
				p, path);
1460
			free(p);
1461
			return -1;
1462
		}
1463
		free(p);
1464
		break;
1465
	}
1466
 
1467
	if(u == none){
1468
		fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode);
1469
		have = st.st_mode&7;
1470
		if((have&need)==need)
1471
			return 0;
1472
		return -1;
1473
	}
1474
	have = st.st_mode&7;
1475
	if((uid_t)u->id == st.st_uid)
1476
		have |= (st.st_mode>>6)&7;
1477
	if((have&need)==need)
1478
		return 0;
1479
	if(((have|((st.st_mode>>3)&7))&need) != need)	/* group won't help */
1480
		return -1;
1481
	g = gid2user(st.st_gid);
1482
	for(i=0; i<g->nmem; i++){
1483
		if(strcmp(g->mem[i], u->name) == 0){
1484
			have |= (st.st_mode>>3)&7;
1485
			break;
1486
		}
1487
	}
1488
	if((have&need)==need)
1489
		return 0;
1490
	return -1;
1491
}
1492
 
1493
int
1494
userwalk(User *u, char **path, char *elem, Qid *qid, char **ep)
1495
{
1496
	char *npath;
1497
	struct stat st;
1498
 
1499
	npath = estrpath(*path, elem, 1);
1500
	if(stat(npath, &st) < 0){
1501
		free(npath);
1502
		*ep = strerror(errno);
1503
		return -1;
1504
	}
1505
	*qid = stat2qid(&st);
1506
	free(*path);
1507
	*path = npath;
1508
	return 0;
1509
}
1510
 
1511
int
1512
useropen(Fid *fid, int omode, char **ep)
1513
{
1514
	int a, o;
1515
 
1516
	/*
1517
	 * Check this anyway, to try to head off problems later.
1518
	 */
1519
	if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){
1520
		*ep = Eperm;
1521
		return -1;
1522
	}
1523
 
1524
	switch(omode&3){
1525
	default:
1526
		*ep = "programmer error";
1527
		return -1;
1528
	case OREAD:
1529
		a = R_OK;
1530
		o = O_RDONLY;
1531
		break;
1532
	case ORDWR:
1533
		a = R_OK|W_OK;
1534
		o = O_RDWR;
1535
		break;
1536
	case OWRITE:
1537
		a = W_OK;
1538
		o = O_WRONLY;
1539
		break;
1540
	case OEXEC:
1541
		a = X_OK;
1542
		o = O_RDONLY;
1543
		break;
1544
	}
1545
	if(omode & OTRUNC){
1546
		a |= W_OK;
1547
		o |= O_TRUNC;
1548
	}
1549
 
1550
	if(S_ISDIR(fid->st.st_mode)){
1551
		if(a != R_OK){
1552
			fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode);
1553
			*ep = Eperm;
1554
			return -1;
1555
		}
1556
		if((fid->dir = opendir(fid->path)) == nil){
1557
			*ep = strerror(errno);
1558
			return -1;
1559
		}
1560
	}else{
1561
		/*
1562
		 * This is wrong because access used the real uid
1563
		 * and not the effective uid.  Let the open sort it out.
1564
		 *
1565
		if(access(fid->path, a) < 0){
1566
			*ep = strerror(errno);
1567
			return -1;
1568
		}
1569
		 *
1570
		 */
1571
		if((fid->fd = open(fid->path, o)) < 0){
1572
			*ep = strerror(errno);
1573
			return -1;
1574
		}
1575
	}
1576
	fid->omode = omode;
1577
	return 0;
1578
}
1579
 
1580
int
1581
usercreate(Fid *fid, char *elem, int omode, long perm, char **ep)
1582
{
1583
	int o, m;
1584
	char *opath, *npath;
1585
	struct stat st, parent;
1586
 
1587
	if(stat(fid->path, &parent) < 0){
1588
		*ep = strerror(errno);
1589
		return -1;
1590
	}
1591
 
1592
	/*
1593
	 * Change group so that created file has expected group
1594
	 * by Plan 9 semantics.  If that fails, might as well go
1595
	 * with the user's default group.
1596
	 */
1597
	if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0
1598
	&& groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0)
1599
		return -1;
1600
 
1601
	m = (perm & DMDIR) ? 0777 : 0666;
1602
	perm = perm & (~m | (fid->st.st_mode & m));
1603
 
1604
	npath = estrpath(fid->path, elem, 1);
1605
	if(perm & DMDIR){
1606
		if((omode&~ORCLOSE) != OREAD){
1607
			*ep = Eperm;
1608
			free(npath);
1609
			return -1;
1610
		}
1611
		if(stat(npath, &st) >= 0 || errno != ENOENT){
1612
			*ep = Eexist;
1613
			free(npath);
1614
			return -1;
1615
		}
1616
		/* race */
1617
		if(mkdir(npath, (perm|0400)&0777) < 0){
1618
			*ep = strerror(errno);
1619
			free(npath);
1620
			return -1;
1621
		}
1622
		if((fid->dir = opendir(npath)) == nil){
1623
			*ep = strerror(errno);
1624
			remove(npath);		/* race */
1625
			free(npath);
1626
			return -1;
1627
		}
1628
	}else{
1629
		o = O_CREAT|O_EXCL;
1630
		switch(omode&3){
1631
		default:
1632
			*ep = "programmer error";
1633
			return -1;
1634
		case OREAD:
1635
		case OEXEC:
1636
			o |= O_RDONLY;
1637
			break;
1638
		case ORDWR:
1639
			o |= O_RDWR;
1640
			break;
1641
		case OWRITE:
1642
			o |= O_WRONLY;
1643
			break;
1644
		}
1645
		if(omode & OTRUNC)
1646
			o |= O_TRUNC;
1647
		if((fid->fd = open(npath, o, perm&0777)) < 0){
1648
			if(chatty9p)
1649
				fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777);
1650
			*ep = strerror(errno);
1651
			free(npath);
1652
			return -1;
1653
		}
1654
	}
1655
 
1656
	opath = fid->path;
1657
	fid->path = npath;
1658
	if(fidstat(fid, ep) < 0){
1659
		fprint(2, "stat after create on %s failed\n", npath);
1660
		remove(npath);	/* race */
1661
		free(npath);
1662
		fid->path = opath;
1663
		if(fid->fd >= 0){
1664
			close(fid->fd);
1665
			fid->fd = -1;
1666
		}else{
1667
			closedir(fid->dir);
1668
			fid->dir = nil;
1669
		}
1670
		return -1;
1671
	}
1672
	fid->omode = omode;
1673
	free(opath);
1674
	return 0;
1675
}
1676
 
1677
int
1678
userremove(Fid *fid, char **ep)
1679
{
1680
	if(remove(fid->path) < 0){
1681
		*ep = strerror(errno);
1682
		return -1;
1683
	}
1684
	return 0;
1685
}
1686
 
1687
void
1688
usage(void)
1689
{
1690
	fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n");
1691
	exit(1);
1692
}
1693
 
1694
int
1695
main(int argc, char **argv)
1696
{
1697
	char *authtype;
1698
	int i;
1699
	int fd;
1700
	int logflag;
1701
 
1702
	auth = authmethods[0];
1703
	logflag = O_WRONLY|O_APPEND|O_CREAT;
1704
	ARGBEGIN{
1705
	case 'D':
1706
		chatty9p = 1;
1707
		break;
1708
	case 'a':
1709
		authtype = EARGF(usage());
1710
		auth = nil;
1711
		for(i=0; i<nelem(authmethods); i++)
1712
			if(strcmp(authmethods[i]->name, authtype)==0)
1713
				auth = authmethods[i];
1714
		if(auth == nil)
1715
			sysfatal("unknown auth type '%s'", authtype);
1716
		break;
1717
	case 'A':
1718
		autharg = EARGF(usage());
1719
		break;
1720
	case 'l':
1721
		logfile = EARGF(usage());
1722
		break;
1723
	case 'm':
1724
		msize = strtol(EARGF(usage()), 0, 0);
1725
		break;
1726
	case 'n':
1727
		network = 0;
1728
		break;
1729
	case 'u':
1730
		defaultuser = EARGF(usage());
1731
		break;
1732
	case 'z':
1733
		logflag |= O_TRUNC;
1734
	}ARGEND
1735
 
1736
	if(argc > 1)
1737
		usage();
1738
 
1739
	fd = open(logfile, logflag, 0666);
1740
	if(fd < 0)
1741
		sysfatal("cannot open log '%s'", logfile);
1742
 
1743
	if(dup2(fd, 2) < 0)
1744
		sysfatal("cannot dup fd onto stderr");
1745
	fprint(2, "u9fs\nkill %d\n", (int)getpid());
1746
 
1747
	fmtinstall('F', fcallconv);
1748
	fmtinstall('D', dirconv);
1749
	fmtinstall('M', dirmodeconv);
1750
 
1751
	rxbuf = emalloc(msize);
1752
	txbuf = emalloc(msize);
1753
	databuf = emalloc(msize);
1754
 
1755
	if(auth->init)
1756
		auth->init();
1757
 
1758
	if(network)
1759
		getremotehostname(remotehostname, sizeof remotehostname);
1760
 
1761
	if(gethostname(hostname, sizeof hostname) < 0)
1762
		strcpy(hostname, "gnot");
1763
 
1764
	umask(0);
1765
 
1766
	if(argc == 1)
1767
		if(chroot(argv[0]) < 0)
1768
			sysfatal("chroot '%s' failed", argv[0]);
1769
 
1770
	none = uname2user("none");
1771
	if(none == nil)
1772
		none = uname2user("nobody");
1773
 
1774
	serve(0, 1);
1775
	return 0;
1776
}