summaryrefslogtreecommitdiff
path: root/man/10/styxserver
blob: d0a8d3216cd7b52776fdf16d97f7e7d47581b0b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
.TH STYXSERVER 10.2
.SH NAME
Styxserver \- C Styx server library
.SH SYNOPSIS
.EX
#define Qroot	0

#define MSGMAX	((((8192+128)*2)+3) & ~3)

extern char Enomem[];	/* out of memory */
extern char Eperm[];		/* permission denied */
extern char Enodev[];	/* no free devices */
extern char Ehungup[];	/* i/o on hungup channel */
extern char Eexist[];		/* file exists */
extern char Enonexist[];	/* file does not exist */
extern char Ebadcmd[];	/* bad command */
extern char Ebadarg[];	/* bad arguments */

typedef uvlong	Path;
typedef struct Styxserver	Styxserver;
typedef struct Styxops Styxops;
typedef struct Styxfile Styxfile;
typedef struct Client Client;

struct Styxserver
{
	Styxops *ops;
	Path qidgen;
	int connfd;
	Client *clients;
	Client *curc;
	Styxfile *root;
	Styxfile **ftab;
	void	*priv;	/* private */
};

struct Client
{
	Styxserver *server;
	Client *next;
	int		fd;
	char	msg[MSGMAX];
	uint		nread;		/* valid bytes in msg (including nc)*/
	int		nc;		/* bytes consumed from front of msg by convM2S */
	char	data[MSGMAX];	/* Tread/Rread data */
	int		state;
	Fid		*fids;
	char		*uname;	/* uid */
	char		*aname;	/* attach name */
	void		*u;
};

struct Styxops
{
	char *(*newclient)(Client *c);
	char *(*freeclient)(Client *c);

	char *(*attach)(char *uname, char *aname);
	char *(*walk)(Qid *qid, char *name);
	char *(*open)(Qid *qid, int mode);
	char *(*create)(Qid *qid, char *name, int perm, int mode);
	char *(*read)(Qid qid, char *buf, ulong *n, vlong offset);
	char *(*write)(Qid qid, char *buf, ulong *n, vlong offset);
	char *(*close)(Qid qid, int mode);
	char *(*remove)(Qid qid);
	char *(*stat)(Qid qid, Dir *d);
	char *(*wstat)(Qid qid, Dir *d);
};

struct Styxfile
{
	Dir	d;
	Styxfile *parent;
	Styxfile *child;
	Styxfile *sibling;
	Styxfile *next;
	int ref;
	int open;
	void	*u;
};

char *styxinit(Styxserver *server, Styxops *ops, char *port, int perm, int needfile);
char *styxwait(Styxserver *server);
char *styxprocess(Styxserver *server);
char *styxend(Styxserver *server);

Client *styxclient(Styxserver *server);

Styxfile *styxaddfile(Styxserver *server, Path pqid, Path qid, char *name,
					int mode, char *owner);
Styxfile *styxadddir(Styxserver *server, Path pqid, Path qid, char *name,
					int mode, char *owner);
int styxrmfile(Styxserver *server, Path qid);
Styxfile *styxfindfile(Styxserver *server, Path qid);

int	styxperm(Styxfile *file, char *uid, int mode);
long styxreadstr(ulong off, char *buf, ulong n, char *str);
Qid styxqid(int path, int isdir);
void *styxmalloc(int bytes);
void styxfree(void *p);
void styxdebug(void);
.EE
.SH DESCRIPTION
The C Styx server library provides a small suite of functions to enable the
production of a file server based on the Inferno Styx protocol. The following
elements define the primary routines in the interface:
.TP
.BI styxinit(server\fP,\fP\ ops\fP,\fP\ port\fP,\fP\ perm\fP,\fP\ needfile )
Initializes the interface given a pointer to a Styxserver structure
.I server
, a callback table of operations
.I ops
, a port number
.I port
to announce the file service on
and the permissions
.I perm
on the root directory. The default permission is 0555 (read and execute for user, 
group and others) if the latter is specified as -1. If the last argument
.I needfile
is set to true, the styx library will check that each path number it deals with
has a corresponding file associated with it and, if it hasn't, it will issue a
"file does not exist" message automatically. In case of an error, the error message is
returned, otherwise nil is returned to indicate success.
.TP
.BI styxwait(server )
Waits for communication from a client. Return value as above.
.TP
.BI styxprocess(server )
Processes the client message after a successful call to
.I styxwait .
This may result in calls to the functions in the table provided to
.I styxinit .
Return value as above.
.TP
.BI styxend(server )
End all file service. Return value as above.
.TP 
.BI styxclient(server )
Returns the client whose request is currently being processed.
.PP
The next set of functions allow the creation of a file system structure based
upon the
.I Styxfile
structure. This contains a Dir structure 
.I d
describing the properties of the file
(defined in lib9.h) and pointers to other files in the file tree:
.I parent
,
.I child
,
.I sibling
and
.I next .
The
.I ref
field
counts current references to the file. The
.I open
field counts the current number of opens on the file. Finally the
.I u
field allows further fields to be tagged onto each file. It is not
used by the Styx server library.
.PP
Each file must have a unique path number in the server. The root of
the tree
.I Qroot
always has path number zero. It's corresponding file is created during library initialization
and placed in the
.I root
field of the server structure. All other files must be supplied with a path number
to identify them. Files are created/deleted as follows:
.TP
.BI styxaddfile(server\fP,\fP\ ppath\fP,\fP\ path\fP,\fP\ name\fP,\fP\ mode\fP,\fP\ owner )
Add a new file (ie non-directory) with the given path
.I path
, name
.I name
, mode
.I mode
and owner
.I owner
to the directory identified by the path
.I ppath .
If
.I path
is -1 the library will generate a unique path number instead.
Returns nil if the parent file with path
.I ppath
does not exist, if the parent is not a directory, if the path number
.I path
already is assigned to a file or if the parent already contains a file of name
.I name .
.TP
.BI styxadddir(server\fP,\fP\ ppath\fP,\fP\ path\fP,\fP\ name\fP,\fP\ mode\fP,\fP\ owner )
Add a new directory with the given path
.I path
, name
.I name
, mode
.I mode
and owner
.I owner
to the directory identified by the path
.I ppath .
Returns nil in the same circumstances as
.I styxaddfile .
.TP
.BI styxrmfile(server\fP,\fP\  path )
Remove the file or directory with path
.I path
from the file server tree. If the file is a directory, it's contents will be recursively
removed. If the file does not exist, -1 is returned, otherwise 0 is returned for
success.
.TP
.BI styxfindfile(server\fP,\fP\  path )
Return the file structure corresponding to the file or directory with path
.I path .
Nil is returned if the file does not exist.
.PP
If the file system is created in this way the Styx library will check read/write/execute
permissions, check for invalid uses of files and check that path numbers exist
in the file system (see
.I styxinit
for the latter). If it's not feasible to do this (for instance if there is a more suitable
way of describing the file system in question), then all file checking must be
done as part of the callback functions below.
.PP
The library provides a callback mechanism so that the implementer of the
file server can take corresponding action when a particular request is made
of the server. All of these functions may return an error message which will
be communicated back to the client. Otherwise they should return nil to
indicate the success of the operation. Any of these functions may be nil in which case the library
performs a default operation which will be described below. These routines use
the
.I Qid
structure defined in lib9.h to describe files. This structure contains the path number(
.I path
), a version number(
.I vers
) typically zero and a type(
.I type
) which indicates whether the file is a directory, append-only etc.
.TP
.BI newclient(c )
Called whenever a new client connects to the server. The Client structure
.I c
contains mainly private data but the
.I uname
field contains a user name and the
.I aname
field an attach name if required. The
.I u
field may be used to tag further data onto each client. It is not used by
the Styx server library.
.TP
.BI freeclient(c )
Called whenever a client disconnects from the server.
.TP
.BI attach(uname\fP,\fP\ aname )
Called when a client user first mounts the file server. The
.I uname
is the user id and
.I aname
is typically the file tree to access if the server provides a choice.
The default action is to allow the attach to the root of the file system.
.TP
.BI walk(qid\fP,\fP\ name )
In a directory represented by
.I qid
, find a file member whose name is that given and place it's Qid in
.I qid .
The default action is to perform the walk using any directory structure provided.
.TP
.BI open(qid\fP,\fP\ mode )
Open the file represented by
.I qid
with mode
.I mode .
The latter may be one of OREAD, OWRITE, ORDWR etc (see lib9.h). If the Qid
of the newly opened file is different from that given (a file server may understand
the opening of a file called "new" say to signify the creation of a directory whose
Qid is returned instead) place it's Qid in
.I qid .
The default action is to nominally allow the open.
.TP
.BI create(qid\fP,\fP\ name\fP,\fP\ perm\fP,\fP\ mode )
Create a file in the directory given by
.I qid
with name
.I name
, permissions
.I perm
and mode
.I mode .
Place the Qid of the newly created file in
.I qid .
The default action is to issue a permission denied message.
.TP
.BI read(qid\fP,\fP\ buf\fP,\fP\ n\fP,\fP\ offset )
Read
.I n
bytes of the file represented by
.I qid
at offset
.I offset
and place the result in
.I buf.
 Place in
.I n
the actual number of bytes read.
The default action is to read directories but to issue permission denied on ordinary
files.
.TP
.BI write(qid\fP,\fP\ buf\fP,\fP\ n\fP,\fP\ offset )
Write
.I n
bytes to the file represented by
.I qid
at offset
.I offset
from the buffer
.I buf.
 Place in
.I n
the actual number of bytes written.
The default action is to issue permission denied.
.TP
.BI close(qid\fP,\fP\ mode )
Close the file represented by
.I qid .
The mode it was originally opened with is given by
.I mode .
The default action is to allow the close.
.TP
.BI remove(qid )
Remove the file represented by
.I qid .
The default action is to issue a permission denied message.
.TP
.BI stat(qid\fP,\fP\ d )
Place the information for the file represented by
.I qid
in the Dir structure(see lib9.h)
.I d .
The default action is to allow the stat using any information in the file tree.
.TP
.BI wstat(qid\fP,\fP\ d )
Update the information for the file represented by
.I qid
according to the Dir structure
.I d .
The default action is to disallow this with a permission denied message.
.PP
A small number of utility functions are provided:
.TP
.BI styxperm(file\fP,\fP\ uid\fP,\fP\ mode )
Does the file/directory
.I file
allow the user
.I uid
the permission given by
.I mode .
For example use
.I OREAD
for read permission,
.I OWRITE
for write permission and
.I ORDWR
for both.
.TP
.BI styxreadstr(off\fP,\fP\ buf\fP,\fP\ n\fP,\fP\ str )
Read
.I n
bytes of data from the string
.I str
at offset
.I off
and place the result in
.I buf .
Returns the actual number of bytes read.
.TP
.BI styxqid(path\fP,\fP\ isdir )
Returns a typical Qid structure with the given path number
.I path
and whether the Qid is for a directory
.I isdir .
.TP
.BI styxmalloc(n )
Allocate
.I n
bytes of memory and return it.
.TP
.BI styxfree(p )
Free the memory pointed to by
.I p .
.TP
.BI styxdebug()
Print out some of the actions of the server.
.SH EXAMPLE
.PP
A very small file server example is illustrated. First the include files and globals.
.PP
.EX
	#include <lib9.h>
	#include "styxserver.h"

	int nq;
	Styxserver *server;
.EE
.PP
The main processing loop:
.PP
.EX
	main(int argc, char **argv)
	{
		Styxserver s;

		server = &s;
		styxinit(&s, &ops, "6701", 100, 0555, 0);
		myinit(&s);
		for(;;) {
			styxwait(&s);
			styxprocess(&s);
		}
		return 0;
	}
.EE
.PP
Here the port number is 6701 and the root file permissions are 0555 - no write
permission for anyone which implies that files and directories cannot be 
created in the root directory.
.PP
The creation of the directory tree:
.PP
.EX
	myinit(Styxserver *s)
	{
		styxaddfile(s, Qroot, 1, "fred", 0664, "inferno");
		styxaddfile(s, Qroot, 2, "joe", 0664, "inferno");
		styxadddir(s, Qroot, 3, "adir", 0775, "inferno");
		styxaddfile(s, 3, 4, "bill", 0664, "inferno");
		styxadddir(s, Qroot, 5, "new", 0775, "inferno");
		styxadddir(s, 5, 6, "cdir", 0775, "inferno");
		styxaddfile(s, 6, 7, "cfile", 0664, "inferno");
		nq = 8;
	}
.EE
.PP
This creates two files
.I fred
and
.I joe
and two directories
.I adir
and
.I new
at the top level.
.I adir
contains a file called
.I bill
and
.I new
contains a directory called
.I cdir
which contains a file called
.I cfile .
Note that each new path number is unique.
.PP
The callback functions:
.PP
.EX
	Styxops ops = {
		nil,			/* newclient */
		nil,			/* freeclient */

		nil,			/* attach */
		nil,			/* walk */
		nil,			/* open */
		mycreate,		/* create */
		myread,		/* read */
		nil,			/* write */
		nil,			/* close */
		myremove,	/* remove */
		nil,			/* stat */
		nil,			/* wstat */
	};
.EE
.PP
Here we choose the defaults most of the time.
.PP
The supplied callback routines:
.PP
.EX
	char *
	mycreate(Qid *qid, char *name, int perm, int mode)
	{
		int isdir;
		Styxfile *f;

		isdir = perm&DMDIR;
		if(isdir)
			f = styxadddir(server, qid->path, nq++, name , perm, "inferno");
		else
			f = styxaddfile(server, qid->path, nq++, name, perm, "inferno");
		if(f == nil)
			return Eexist;
		*qid = f->d.qid;
		return nil;
	}

	char *
	myremove(Qid qid)
	{
		Styxfile *f;

		f = styxfindfile(server, qid.path);
		if(f != nil && (f->d.qid.type&QTDIR) && f->child != nil)
			return "directory not empty";

		if(styxrmfile(server, qid.path) < 0)
			return Enonexist;
		return nil;
	}

	char *
	myread(Qid qid, char *d, ulong *n, vlong offset)
	{
		if(qid.path != 1){
			*n = 0;
			return nil;
		}
		*n = styxreadstr(offset, d, *n, "abcdeghijklmn");
		return nil;
	}
.EE
.PP
Permission checking for walk (need execute permission on directory), open (the
given mode must be compatible with the file permissions), create and remove (both of
which need write permission on directory) is done automatically whenever
possible. The functions
.I mycreate
and
.I myremove
below therefore can omit these checks.
.PP
The function
.I mycreate
simply creates a directory or file and
if the file cannot be added to the directory tree it returns a 'file exists' error string.
It sets the Qid for the newly created file before returning.
.PP
The function
.I myremove
first checks to see if the file represents a non-empty directory, in which case it
disallows it's removal. Otherwise it
removes the file if it can find it and returns a 'file does not exist' error string if it
can't.
.PP
The function
.I myread
considers all files to be empty except for
.I fred
which notionally contains
.I abcdefghijklmn .
Note that the number of bytes read is returned in the argument
.I n .
.PP
Once this file server is running, the root can be accessed by doing for example
.PP
.EX
	mount -A tcp!<address>!6701 /n/remote
.EE
.PP
under Inferno. Here
.I <address>
is the address of the machine running the file server (or the loopback address
127.0.0.1 if it's all on one machine). The 
.I -A
option is used to prevent authentication which is not supported at the moment.
Then we can do
.PP
.EX
	cd /n/remote
	ls
	adir
	fred
	joe
	new
	...
.EE
.PP
For a more complicated file server see /tools/styxtest/styxtest.c.
.PP
The file /tools/styxtest/mkfile shows how to compile and link the file server
sources.
.SH SOURCE
.B /Nt/386/include/lib9.h
.br
.B /tools/libstyx/styxserver.h
.br
.B /tools/libstyx/styxserver.c
.br
.B /tools/styxtest/styxtest.c
.br
.B /tools/styxtest/styxtest0.c
.SH BUGS
Currently the library is available under Windows, Linux and Solaris only.
.br
Authentication is not supported.