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
|
.HTML "Changes to the Programming Environment in the Fourth Release of Plan 9
.FP lucidasans
.TL
Changes to the Programming Environment
.br
in the
.br
Fourth Release of Plan 9
.AU
Rob Pike
.sp
rob@plan9.bell-labs.com
.SH
Introduction
.PP
The fourth release of Plan 9 includes changes at many levels of the system,
with repercussions in the libraries and program interfaces.
This document summarizes the changes and describes how
existing programs must be modified to run in the new release.
It is not exhaustive, of course; for further detail about any of the
topics refer to the manual pages, as always.
.PP
Programmers new to Plan 9 may find valuable tidbits here, but the
real audience for this paper is those with a need to update applications
and servers written in C for earlier releases of the Plan 9 operating system.
.SH
9P, NAMELEN, and strings
.PP
The underlying file service protocol for Plan 9, 9P, retains its basic form
but has had a number of adjustments to deal with longer file names and error strings,
new authentication mechanisms, and to make it more efficient at
evaluating file names.
The change to file names affects a number of system interfaces;
because file name elements are no longer of fixed size, they can
no longer be stored as arrays.
.PP
9P used to be a fixed-format protocol with
.CW NAMELEN -sized
byte arrays representing file name elements.
Now, it is a variable-format protocol, as described in
.I intro (5),
in which strings are represented by a count followed by that many bytes.
Thus, the string
.CW ken
would previously have occupied 28
.CW NAMELEN ) (
bytes in the message; now it occupies 5: a two-byte count followed by the three bytes of
.CW ken
and no terminal zero.
(And of course, a name could now be much longer.)
A similar format change has been made to
.CW stat
buffers: they are no longer
.CW DIRLEN
bytes long but instead have variable size prefixed by a two-byte count.
And in fact the entire 9P message syntax has changed: every message
now begins with a message length field that makes it trivial to break the
string into messages without parsing them, so
.CW aux/fcall
is gone.
A new library entry point,
.CW read9pmsg ,
makes it easy for user-level servers to break the client data stream into 9P messages.
All servers should switch from using
.CW read
(or the now gone
.CW getS)
to using
.CW read9pmsg .
.PP
This change to 9P affects the way strings are handled by the kernel and throughout
the system.
The consequences are primarily that fixed-size arrays have been replaced
by pointers and counts in a variety of system interfaces.
Most programs will need at least some adjustment to the new style.
In summary:
.CW NAMELEN
is gone, except as a vestige in the authentication libraries, where it has been
rechristened
.CW ANAMELEN .
.CW DIRLEN
and
.CW ERRLEN
are also gone.
All programs that mention
these constants
will need to be fixed.
.PP
The simplest place to see this change is in the
.CW errstr
system call, which no longer assumes a buffer of length
.CW ERRLEN
but now requires a byte-count argument:
.P1
char buf[...];
errstr(buf, sizeof buf);
.P2
The buffer can be any size you like.
For convenience, the kernel stores error strings internally as 256-byte arrays,
so if you like \(em but it's not required \(em you can use the defined constant
.CW ERRMAX= 256
as a good buffer size.
Unlike the old
.CW ERRLEN
(which had value 64),
.CW ERRMAX
is advisory, not mandatory, and is not part of the 9P specification.
.PP
With names, stat buffers, and directories, there isn't even an echo of a fixed-size array any more.
.SH
Directories and wait messages
.PP
With strings now variable-length, a number of system calls needed to change:
.CW errstr ,
.CW stat ,
.CW fstat ,
.CW wstat ,
.CW fwstat ,
and
.CW wait
are all affected, as is
.CW read
when applied to directories.
.PP
As far as directories are concerned, most programs don't use the system calls
directly anyway, since they operate on the machine-independent form, but
instead call the machine-dependent
.CW Dir
routines
.CW dirstat ,
.CW dirread ,
etc.
These used to fill user-provided fixed-size buffers; now they return objects allocated
by
.CW malloc
(which must therefore be freed after use).
To `stat' a file:
.P1
Dir *d;
d = dirstat(filename);
if(d == nil){
fprint(2, "can't stat %s: %r\en", filename);
exits("stat");
}
use(d);
free(d);
.P2
A common new bug is to forget to free a
.CW Dir
returned by
.CW dirstat .
.PP
.CW Dirfstat
and
.CW Dirfwstat
work pretty much as before, but changes to 9P make
it possible to exercise finer-grained control on what fields
of the
.CW Dir
are to be changed; see
.I stat (2)
and
.I stat (5)
for details.
.PP
Reading a directory works in a similar way to
.CW dirstat ,
with
.CW dirread
allocating and filling in an array of
.CW Dir
structures.
The return value is the number of elements of the array.
The arguments to
.CW dirread
now include a pointer to a
.CW Dir*
to be filled in with the address of the allocated array:
.P1
Dir *d;
int i, n;
while((n = dirread(fd, &d)) > 0){
for(i=0; i<n; i++)
use(&d[i]);
free(d);
}
.P2
A new library function,
.CW dirreadall ,
has the same form as
.CW dirread
but returns the entire directory in one call:
.P1
n = dirreadall(fd, &d)
for(i=0; i<n; i++)
use(&d[i]);
free(d);
.P2
If your program insists on using the underlying
.CW stat
system call or its relatives, or wants to operate directly on the
machine-independent format returned by
.CW stat
or
.CW read ,
it will need to be modified.
Such programs are rare enough that we'll not discuss them here beyond referring to
the man page
.I stat (2)
for details.
Be aware, though, that it used to be possible to regard the buffer returned by
.CW stat
as a byte array that began with the zero-terminated
name of the file; this is no longer true.
With very rare exceptions, programs that call
.CW stat
would be better recast to use the
.CW dir
routines or, if their goal is just to test the existence of a file,
.CW access .
.PP
Similar changes have affected the
.CW wait
system call. In fact,
.CW wait
is no longer a system call but a library routine that calls the new
.CW await
system call and returns a newly allocated machine-dependent
.CW Waitmsg
structure:
.P1
Waitmsg *w;
w = wait();
if(w == nil)
error("wait: %r");
print("pid is %d; exit string %s\en", w->pid, w->msg);
free(w);
.P2
The exit string
.CW w->msg
may be empty but it will never be a nil pointer.
Again, don't forget to free the structure returned by
.CW wait .
If all you need is the pid, you can call
.CW waitpid ,
which reports just the pid and doesn't return an allocated structure:
.P1
int pid;
pid = waitpid();
if(pid < 0)
error("wait: %r");
print("pid is %d\en", pid);
.P2
.SH
Quoted strings and tokenize
.PP
.CW Wait
gives us a good opportunity to describe how the system copes with all this
free-format data.
Consider the text returned by the
.CW await
system call, which includes a set of integers (pids and times) and a string (the exit status).
This information is formatted free-form; here is the statement in the kernel that
generates the message:
.P1
n = snprint(a, n, "%d %lud %lud %lud %q",
wq->w.pid,
wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
wq->w.msg);
.P2
Note the use of
.CW %q
to produce a quoted-string representation of the exit status.
The
.CW %q
format is like %s but will wrap
.CW rc -style
single quotes around the string if it contains white space or is otherwise ambiguous.
The library routine
.CW tokenize
can be used to parse data formatted this way: it splits white-space-separated
fields but understands the
.CW %q
quoting conventions.
Here is how the
.CW wait
library routine builds its
.CW Waitmsg
from the data returned by
.CW await :
.P1
Waitmsg*
wait(void)
{
int n, l;
char buf[512], *fld[5];
Waitmsg *w;
n = await(buf, sizeof buf-1);
if(n < 0)
return nil;
buf[n] = '\0';
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
werrstr("couldn't parse wait message");
return nil;
}
l = strlen(fld[4])+1;
w = malloc(sizeof(Waitmsg)+l);
if(w == nil)
return nil;
w->pid = atoi(fld[0]);
w->time[0] = atoi(fld[1]);
w->time[1] = atoi(fld[2]);
w->time[2] = atoi(fld[3]);
w->msg = (char*)&w[1];
memmove(w->msg, fld[4], l);
return w;
}
.P2
.PP
This style of quoted-string and
.CW tokenize
is used all through the system now.
In particular, devices now
.CW tokenize
the messages written to their
.CW ctl
files, which means that you can send messages that contain white space, by quoting them,
and that you no longer need to worry about whether or not the device accepts a newline.
In other words, you can say
.P1
echo message > /dev/xx/ctl
.P2
instead of
.CW echo
.CW -n
because
.CW tokenize
treats the newline character as white space and discards it.
.PP
While we're on the subject of quotes and strings, note that the implementation of
.CW await
used
.CW snprint
rather than
.CW sprint .
We now deprecate
.CW sprint
because it has no protection against buffer overflow.
We prefer
.CW snprint
or
.CW seprint ,
to constrain the output.
The
.CW %q
format is cleverer than most in this regard:
if the string is too long to be represented in full,
.CW %q
is smart enough to produce a truncated but correctly quoted
string within the available space.
.SH
Mount
.PP
Although strings in 9P are now variable-length and not zero-terminated,
this has little direct effect in most of the system interfaces.
File and user names are still zero-terminated strings as always;
the kernel does the work of translating them as necessary for
transport.
And of course, they are now free to be as long as you might want;
the only hard limit is that their length must be represented in 16 bits.
.PP
One example where this matters is that the file system specification in the
.CW mount
system call can now be much longer.
Programs like
.CW rio
that used the specification string in creative ways were limited by the
.CW NAMELEN
restriction; now they can use the string more freely.
.CW Rio
now accepts a simple but less cryptic specification language for the window
to be created by the
.CW mount
call, e.g.:
.P1
% mount $wsys /mnt/wsys 'new -dx 250 -dy 250 -pid 1234'
.P2
In the old system, this sort of control was impossible through the
.CW mount
interface.
.PP
While we're on the subject of
.CW mount ,
note that with the new security architecture
(see
.I factotum (4)),
9P has moved its authentication outside the protocol proper.
(For a full description of this change to 9P, see
.I fauth (2),
.I attach (5),
and the paper
.I "Security in Plan 9\f1.)
The most explicit effect of this change is that
.CW mount
now takes another argument,
.CW afd ,
a file descriptor for the
authentication file through which the authentication will be made.
For most user-level file servers, which do not require authentication, it is
sufficient to provide
.CW -1
as the value of
.CW afd:
.P1
if(mount(fd, -1, "/mnt/wsys", MREPL,
"new -dx 250 -dy 250 -pid 1234") < 0)
error("mount failed: %r");
.P2
To connect to servers that require authentication, use the new
.CW fauth
system call or the reimplemented
.CW amount
(authenticated mount) library call.
In fact, since
.CW amount
handles both authenticating and non-authenticating servers, it is often
easiest just to replace calls to
.CW mount
by calls to
.CW amount ;
see
.I auth (2)
for details.
.SH
Print
.PP
The C library has been heavily reworked in places.
Besides the changes mentioned above, it
now has a much more complete set of routines for handling
.CW Rune
strings (that is, zero-terminated arrays of 16-bit character values).
The most sweeping changes, however, are in the way formatted I/O is performed.
.PP
The
.CW print
routine and all its relatives have been reimplemented to offer a number
of improvements:
.IP (1)
Better buffer management, including the provision of an internal flush
routine, makes it unnecessary to provide large buffers.
For example,
.CW print
uses a much smaller buffer now (reducing stack load) while simultaneously
removing the need to truncate the output string if it doesn't fit in the buffer.
.IP (2)
Global variables have been eliminated so no locking is necessary.
.IP (3)
The combination of (1) and (2) means that the standard implementation of
.CW print
now works fine in threaded programs, and
.CW threadprint
is gone.
.IP (4)
The new routine
.CW smprint
prints into, and returns, storage allocated on demand by
.CW malloc .
.IP (5)
It is now possible to print into a
.CW Rune
string; for instance,
.CW runesmprint
is the
.CW Rune
analog of
.CW smprint .
.IP (6)
There is improved support for custom
print verbs and custom output routines such as error handlers.
The routine
.CW doprint
is gone, but
.CW vseprint
can always be used instead.
However, the new routines
.CW fmtfdinit ,
.CW fmtstrinit ,
.CW fmtprint ,
and friends
are often a better replacement.
The details are too long for exposition here;
.I fmtinstall (2)
explains the new interface and provides examples.
.IP (7)
Two new format flags, space and comma, close somewhat the gap between
Plan 9 and ANSI C.
.PP
Despite these changes, most programs will be unaffected;
.CW print
is still
.CW print .
Don't forget, though, that
you should eliminate calls to
.CW sprint
and use the
.CW %q
format when appropriate.
.SH
Binary compatibility
.PP
The discussion so far has been about changes at the source level.
Existing binaries will probably run without change in the new
environment, since the kernel provides backward-compatible
system calls for
.CW errstr ,
.CW stat ,
.CW wait ,
etc.
The only exceptions are programs that do either a
.CW mount
system call, because of the security changes and because
the file descriptor in
.CW mount
must point to a new 9P connection; or a
.CW read
system call on a directory, since the returned data will
be in the new format.
A moment's reflection will discover that this means old
user-level file servers will need to be fixed to run on the new system.
.SH
File servers
.PP
A full description of what user-level servers must do to provide service with
the new 9P is beyond the scope of this paper.
Your best source of information is section 5 of the manual,
combined with study of a few examples.
.CW /sys/src/cmd/ramfs.c
is a simple example; it has a counterpart
.CW /sys/src/lib9p/ramfs.c
that implements the same service using the new
.I 9p (2)
library.
.PP
That said, it's worth summarizing what to watch for when converting a file server.
The
.CW session
message is gone, and there is a now a
.CW version
message that is exchanged at the start of a connection to establish
the version of the protocol to use (there's only one at the moment, identified by
the string
.CW 9P2000 )
and what the maximum message size will be.
This negotiation makes it easier to handle 9P encapsulation, such as with
.CW exportfs ,
and also permits larger message sizes when appropriate.
.PP
If your server wants to authenticate, it will need to implement an authentication file
and implement the
.CW auth
message; otherwise it should return a helpful error string to the
.CW Tauth
request to signal that authentication is not required.
.PP
The handling of
.CW stat
and directory reads will require some changes but they should not be fundamental.
Be aware that seeking on directories is forbidden, so it is fine if you disregard the
file offset when implementing directory reads; this makes it a little easier to handle
the variable-length entries.
You should still never return a partial directory entry; if the I/O count is too small
to return even one entry, you should return two bytes containing the byte count
required to represent the next entry in the directory.
User code can use this value to formulate a retry if it desires.
See the
DIAGNOSTICS section of
.I stat (2)
for a description of this process.
.PP
The trickiest part of updating a file server is that the
.CW clone
and
.CW walk
messages have been merged into a single message, a sort of `clone-multiwalk'.
The new message, still called
.CW walk ,
proposes a sequence of file name elements to be evaluated using a possibly
cloned fid.
The return message contains the qids of the files reached by
walking to the sequential elements.
If all the elements can be walked, the fid will be cloned if requested.
If a non-zero number of elements are requested, but none
can be walked, an error should be returned.
If only some can be walked, the fid is not cloned, the original fid is left
where it was, and the returned
.CW Rwalk
message should contain the partial list of successfully reached qids.
See
.I walk (5)
for a full description.
|