xref: /plan9/sys/doc/prog4.ms (revision 426d2b71458df9b491ba6c167f699b3f1f7b0428)
1.HTML "Changes to the Programming Environment in the Fourth Release of Plan 9
2.FP lucidasans
3.TL
4Changes to the Programming Environment
5.br
6in the
7.br
8Fourth Release of Plan 9
9.AU
10Rob Pike
11.sp
12rob@plan9.bell-labs.com
13.SH
14Introduction
15.PP
16The fourth release of Plan 9 includes changes at many levels of the system,
17with repercussions in the libraries and program interfaces.
18This document summarizes the changes and describes how
19existing programs must be modified to run in the new release.
20It is not exhaustive, of course; for further detail about any of the
21topics refer to the manual pages, as always.
22.PP
23Programmers new to Plan 9 may find valuable tidbits here, but the
24real audience for this paper is those with a need to update applications
25and servers written in C for earlier releases of the Plan 9 operating system.
26.SH
279P, NAMELEN, and strings
28.PP
29The underlying file service protocol for Plan 9, 9P, retains its basic form
30but has had a number of adjustments to deal with longer file names and error strings,
31new authentication mechanisms, and to make it more efficient at
32evaluating file names.
33The change to file names affects a number of system interfaces;
34because file name elements are no longer of fixed size, they can
35no longer be stored as arrays.
36.PP
379P used to be a fixed-format protocol with
38.CW NAMELEN -sized
39byte arrays representing file name elements.
40Now, it is a variable-format protocol, as described in
41.I intro (5),
42in which strings are represented by a count followed by that many bytes.
43Thus, the string
44.CW ken
45would previously have occupied 28
46.CW NAMELEN ) (
47bytes in the message; now it occupies 5: a two-byte count followed by the three bytes of
48.CW ken
49and no terminal zero.
50(And of course, a name could now be much longer.)
51A similar format change has been made to
52.CW stat
53buffers: they are no longer
54.CW DIRLEN
55bytes long but instead have variable size prefixed by a two-byte count.
56And in fact the entire 9P message syntax has changed: every message
57now begins with a message length field that makes it trivial to break the
58string into messages without parsing them, so
59.CW aux/fcall
60is gone.
61A new library entry point,
62.CW read9pmsg ,
63makes it easy for user-level servers to break the client data stream into 9P messages.
64All servers should switch from using
65.CW read
66(or the now gone
67.CW getS)
68to using
69.CW read9pmsg .
70.PP
71This change to 9P affects the way strings are handled by the kernel and throughout
72the system.
73The consequences are primarily that fixed-size arrays have been replaced
74by pointers and counts in a variety of system interfaces.
75Most programs will need at least some adjustment to the new style.
76In summary:
77.CW NAMELEN
78is gone, except as a vestige in the authentication libraries, where it has been
79rechristened
80.CW ANAMELEN .
81.CW DIRLEN
82and
83.CW ERRLEN
84are also gone.
85All programs that mention
86these constants
87will need to be fixed.
88.PP
89The simplest place to see this change is in the
90.CW errstr
91system call, which no longer assumes a buffer of length
92.CW ERRLEN
93but now requires a byte-count argument:
94.P1
95char buf[...];
96
97errstr(buf, sizeof buf);
98.P2
99The buffer can be any size you like.
100For convenience, the kernel stores error strings internally as 256-byte arrays,
101so if you like \(em but it's not required \(em you can use the defined constant
102.CW ERRMAX= 256
103as a good buffer size.
104Unlike the old
105.CW ERRLEN
106(which had value 64),
107.CW ERRMAX
108is advisory, not mandatory, and is not part of the 9P specification.
109.PP
110With names, stat buffers, and directories, there isn't even an echo of a fixed-size array any more.
111.SH
112Directories and wait messages
113.PP
114With strings now variable-length, a number of system calls needed to change:
115.CW errstr ,
116.CW stat ,
117.CW fstat ,
118.CW wstat ,
119.CW fwstat ,
120and
121.CW wait
122are all affected, as is
123.CW read
124when applied to directories.
125.PP
126As far as directories are concerned, most programs don't use the system calls
127directly anyway, since they operate on the machine-independent form, but
128instead call the machine-dependent
129.CW Dir
130routines
131.CW dirstat ,
132.CW dirread ,
133etc.
134These used to fill user-provided fixed-size buffers; now they return objects allocated
135by
136.CW malloc
137(which must therefore be freed after use).
138To `stat' a file:
139.P1
140Dir *d;
141
142d = dirstat(filename);
143if(d == nil){
144	fprint(2, "can't stat %s: %r\en", filename);
145	exits("stat");
146}
147use(d);
148free(d);
149.P2
150A common new bug is to forget to free a
151.CW Dir
152returned by
153.CW dirstat .
154.PP
155.CW Dirfstat
156and
157.CW Dirfwstat
158work pretty much as before, but changes to 9P make
159it possible to exercise finer-grained control on what fields
160of the
161.CW Dir
162are to be changed; see
163.I stat (2)
164and
165.I stat (5)
166for details.
167.PP
168Reading a directory works in a similar way to
169.CW dirstat ,
170with
171.CW dirread
172allocating and filling in an array of
173.CW Dir
174structures.
175The return value is the number of elements of the array.
176The arguments to
177.CW dirread
178now include a pointer to a
179.CW Dir*
180to be filled in with the address of the allocated array:
181.P1
182Dir *d;
183int i, n;
184
185while((n = dirread(fd, &d)) > 0){
186	for(i=0; i<n; i++)
187		use(&d[i]);
188	free(d);
189}
190.P2
191A new library function,
192.CW dirreadall ,
193has the same form as
194.CW dirread
195but returns the entire directory in one call:
196.P1
197n = dirreadall(fd, &d)
198for(i=0; i<n; i++)
199	use(&d[i]);
200free(d);
201.P2
202If your program insists on using the underlying
203.CW stat
204system call or its relatives, or wants to operate directly on the
205machine-independent format returned by
206.CW stat
207or
208.CW read ,
209it will need to be modified.
210Such programs are rare enough that we'll not discuss them here beyond referring to
211the man page
212.I stat (2)
213for details.
214Be aware, though, that it used to be possible to regard the buffer returned by
215.CW stat
216as a byte array that began with the zero-terminated
217name of the file; this is no longer true.
218With very rare exceptions, programs that call
219.CW stat
220would be better recast to use the
221.CW dir
222routines or, if their goal is just to test the existence of a file,
223.CW access .
224.PP
225Similar changes have affected the
226.CW wait
227system call.  In fact,
228.CW wait
229is no longer a system call but a library routine that calls the new
230.CW await
231system call and returns a newly allocated machine-dependent
232.CW Waitmsg
233structure:
234.P1
235Waitmsg *w;
236
237w = wait();
238if(w == nil)
239	error("wait: %r");
240print("pid is %d; exit string %s\en", w->pid, w->msg);
241free(w);
242.P2
243The exit string
244.CW w->msg
245may be empty but it will never be a nil pointer.
246Again, don't forget to free the structure returned by
247.CW wait .
248If all you need is the pid, you can call
249.CW waitpid ,
250which reports just the pid and doesn't return an allocated structure:
251.P1
252int pid;
253
254pid = waitpid();
255if(pid < 0)
256	error("wait: %r");
257print("pid is %d\en", pid);
258.P2
259.SH
260Quoted strings and tokenize
261.PP
262.CW Wait
263gives us a good opportunity to describe how the system copes with all this
264free-format data.
265Consider the text returned by the
266.CW await
267system call, which includes a set of integers (pids and times) and a string (the exit status).
268This information is formatted free-form; here is the statement in the kernel that
269generates the message:
270.P1
271n = snprint(a, n, "%d %lud %lud %lud %q",
272	wq->w.pid,
273	wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
274	wq->w.msg);
275.P2
276Note the use of
277.CW %q
278to produce a quoted-string representation of the exit status.
279The
280.CW %q
281format is like %s but will wrap
282.CW rc -style
283single quotes around the string if it contains white space or is otherwise ambiguous.
284The library routine
285.CW tokenize
286can be used to parse data formatted this way: it splits white-space-separated
287fields but understands the
288.CW %q
289quoting conventions.
290Here is how the
291.CW wait
292library routine builds its
293.CW Waitmsg
294from the data returned by
295.CW await :
296.P1
297Waitmsg*
298wait(void)
299{
300	int n, l;
301	char buf[512], *fld[5];
302	Waitmsg *w;
303
304	n = await(buf, sizeof buf-1);
305	if(n < 0)
306		return nil;
307	buf[n] = '\0';
308	if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
309		werrstr("couldn't parse wait message");
310		return nil;
311	}
312	l = strlen(fld[4])+1;
313	w = malloc(sizeof(Waitmsg)+l);
314	if(w == nil)
315		return nil;
316	w->pid = atoi(fld[0]);
317	w->time[0] = atoi(fld[1]);
318	w->time[1] = atoi(fld[2]);
319	w->time[2] = atoi(fld[3]);
320	w->msg = (char*)&w[1];
321	memmove(w->msg, fld[4], l);
322	return w;
323}
324.P2
325.PP
326This style of quoted-string and
327.CW tokenize
328is used all through the system now.
329In particular, devices now
330.CW tokenize
331the messages written to their
332.CW ctl
333files, which means that you can send messages that contain white space, by quoting them,
334and that you no longer need to worry about whether or not the device accepts a newline.
335In other words, you can say
336.P1
337echo message > /dev/xx/ctl
338.P2
339instead of
340.CW echo
341.CW -n
342because
343.CW tokenize
344treats the newline character as white space and discards it.
345.PP
346While we're on the subject of quotes and strings, note that the implementation of
347.CW await
348used
349.CW snprint
350rather than
351.CW sprint .
352We now deprecate
353.CW sprint
354because it has no protection against buffer overflow.
355We prefer
356.CW snprint
357or
358.CW seprint ,
359to constrain the output.
360The
361.CW %q
362format is cleverer than most in this regard:
363if the string is too long to be represented in full,
364.CW %q
365is smart enough to produce a truncated but correctly quoted
366string within the available space.
367.SH
368Mount
369.PP
370Although strings in 9P are now variable-length and not zero-terminated,
371this has little direct effect in most of the system interfaces.
372File and user names are still zero-terminated strings as always;
373the kernel does the work of translating them as necessary for
374transport.
375And of course, they are now free to be as long as you might want;
376the only hard limit is that their length must be represented in 16 bits.
377.PP
378One example where this matters is that the file system specification in the
379.CW mount
380system call can now be much longer.
381Programs like
382.CW rio
383that used the specification string in creative ways were limited by the
384.CW NAMELEN
385restriction; now they can use the string more freely.
386.CW Rio
387now accepts a simple but less cryptic specification language for the window
388to be created by the
389.CW mount
390call, e.g.:
391.P1
392% mount $wsys /mnt/wsys 'new -dx 250 -dy 250 -pid 1234'
393.P2
394In the old system, this sort of control was impossible through the
395.CW mount
396interface.
397.PP
398While we're on the subject of
399.CW mount ,
400note that with the new security architecture
401(see
402.I factotum (4)),
4039P has moved its authentication outside the protocol proper.
404(For a full description of this change to 9P, see
405.I fauth (2),
406.I attach (5),
407and the paper
408.I "Security in Plan 9\f1.)
409The most explicit effect of this change is that
410.CW mount
411now takes another argument,
412.CW afd ,
413a file descriptor for the
414authentication file through which the authentication will be made.
415For most user-level file servers, which do not require authentication, it is
416sufficient to provide
417.CW -1
418as the value of
419.CW afd:
420.P1
421if(mount(fd, -1, "/mnt/wsys", MREPL,
422   "new -dx 250 -dy 250 -pid 1234") < 0)
423	error("mount failed: %r");
424.P2
425To connect to servers that require authentication, use the new
426.CW fauth
427system call or the reimplemented
428.CW amount
429(authenticated mount) library call.
430In fact, since
431.CW amount
432handles both authenticating and non-authenticating servers, it is often
433easiest just to replace calls to
434.CW mount
435by calls to
436.CW amount ;
437see
438.I auth (2)
439for details.
440.SH
441Print
442.PP
443The C library has been heavily reworked in places.
444Besides the changes mentioned above, it
445now has a much more complete set of routines for handling
446.CW Rune
447strings (that is, zero-terminated arrays of 16-bit character values).
448The most sweeping changes, however, are in the way formatted I/O is performed.
449.PP
450The
451.CW print
452routine and all its relatives have been reimplemented to offer a number
453of improvements:
454.IP (1)
455Better buffer management, including the provision of an internal flush
456routine, makes it unnecessary to provide large buffers.
457For example,
458.CW print
459uses a much smaller buffer now (reducing stack load) while simultaneously
460removing the need to truncate the output string if it doesn't fit in the buffer.
461.IP (2)
462Global variables have been eliminated so no locking is necessary.
463.IP (3)
464The combination of (1) and (2) means that the standard implementation of
465.CW print
466now works fine in threaded programs, and
467.CW threadprint
468is gone.
469.IP (4)
470The new routine
471.CW smprint
472prints into, and returns, storage allocated on demand by
473.CW malloc .
474.IP (5)
475It is now possible to print into a
476.CW Rune
477string; for instance,
478.CW runesmprint
479is the
480.CW Rune
481analog of
482.CW smprint .
483.IP (6)
484There is improved support for custom
485print verbs and custom output routines such as error handlers.
486The routine
487.CW doprint
488is gone, but
489.CW vseprint
490can always be used instead.
491However, the new routines
492.CW fmtfdinit ,
493.CW fmtstrinit ,
494.CW fmtprint ,
495and friends
496are often a better replacement.
497The details are too long for exposition here;
498.I fmtinstall (2)
499explains the new interface and provides examples.
500.IP (7)
501Two new format flags, space and comma, close somewhat the gap between
502Plan 9 and ANSI C.
503.PP
504Despite these changes, most programs will be unaffected;
505.CW print
506is still
507.CW print .
508Don't forget, though, that
509you should eliminate calls to
510.CW sprint
511and use the
512.CW %q
513format when appropriate.
514.SH
515Binary compatibility
516.PP
517The discussion so far has been about changes at the source level.
518Existing binaries will probably run without change in the new
519environment, since the kernel provides backward-compatible
520system calls for
521.CW errstr ,
522.CW stat ,
523.CW wait ,
524etc.
525The only exceptions are programs that do either a
526.CW mount
527system call, because of the security changes and because
528the file descriptor in
529.CW mount
530must point to a new 9P connection; or a
531.CW read
532system call on a directory, since the returned data will
533be in the new format.
534A moment's reflection will discover that this means old
535user-level file servers will need to be fixed to run on the new system.
536.SH
537File servers
538.PP
539A full description of what user-level servers must do to provide service with
540the new 9P is beyond the scope of this paper.
541Your best source of information is section 5 of the manual,
542combined with study of a few examples.
543.CW /sys/src/cmd/ramfs.c
544is a simple example; it has a counterpart
545.CW /sys/src/lib9p/ramfs.c
546that implements the same service using the new
547.I 9p (2)
548library.
549.PP
550That said, it's worth summarizing what to watch for when converting a file server.
551The
552.CW session
553message is gone, and there is a now a
554.CW version
555message that is exchanged at the start of a connection to establish
556the version of the protocol to use (there's only one at the moment, identified by
557the string
558.CW 9P2000 )
559and what the maximum message size will be.
560This negotiation makes it easier to handle 9P encapsulation, such as with
561.CW exportfs ,
562and also permits larger message sizes when appropriate.
563.PP
564If your server wants to authenticate, it will need to implement an authentication file
565and implement the
566.CW auth
567message; otherwise it should return a helpful error string to the
568.CW Tauth
569request to signal that authentication is not required.
570.PP
571The handling of
572.CW stat
573and directory reads will require some changes but they should not be fundamental.
574Be aware that seeking on directories is forbidden, so it is fine if you disregard the
575file offset when implementing directory reads; this makes it a little easier to handle
576the variable-length entries.
577You should still never return a partial directory entry; if the I/O count is too small
578to return even one entry, you should return two bytes containing the byte count
579required to represent the next entry in the directory.
580User code can use this value to formulate a retry if it desires.
581See the
582DIAGNOSTICS section of
583.I stat (2)
584for a description of this process.
585.PP
586The trickiest part of updating a file server is that the
587.CW clone
588and
589.CW walk
590messages have been merged into a single message, a sort of `clone-multiwalk'.
591The new message, still called
592.CW walk ,
593proposes a sequence of file name elements to be evaluated using a possibly
594cloned fid.
595The return message contains the qids of the files reached by
596walking to the sequential elements.
597If all the elements can be walked, the fid will be cloned if requested.
598If a non-zero number of elements are requested, but none
599can be walked, an error should be returned.
600If only some can be walked, the fid is not cloned, the original fid is left
601where it was, and the returned
602.CW Rwalk
603message should contain the partial list of successfully reached qids.
604See
605.I walk (5)
606for a full description.
607