.HTML "Changes to the Programming Environment in the Fourth Release of Plan 9.FP lucidasans.TLChanges to the Programming Environment.brin the.brFourth Release of Plan 9.AURob Pike.sprob@plan9.bell-labs.com.SHIntroduction.PPThe 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 howexisting programs must be modified to run in the new release.It is not exhaustive, of course; for further detail about any of thetopics refer to the manual pages, as always..PPProgrammers new to Plan 9 may find valuable tidbits here, but thereal audience for this paper is those with a need to update applicationsand servers written in C for earlier releases of the Plan 9 operating system..SH9P, NAMELEN, and strings.PPThe underlying file service protocol for Plan 9, 9P, retains its basic formbut has had a number of adjustments to deal with longer file names and error strings,new authentication mechanisms, and to make it more efficient atevaluating file names.The change to file names affects a number of system interfaces;because file name elements are no longer of fixed size, they canno longer be stored as arrays..PP9P used to be a fixed-format protocol with.CW NAMELEN -sizedbyte 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 kenwould 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 kenand no terminal zero.(And of course, a name could now be much longer.)A similar format change has been made to.CW statbuffers: they are no longer.CW DIRLENbytes long but instead have variable size prefixed by a two-byte count.And in fact the entire 9P message syntax has changed: every messagenow begins with a message length field that makes it trivial to break thestring into messages without parsing them, so.CW aux/fcallis 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 ..PPThis change to 9P affects the way strings are handled by the kernel and throughoutthe system.The consequences are primarily that fixed-size arrays have been replacedby pointers and counts in a variety of system interfaces.Most programs will need at least some adjustment to the new style.In summary:.CW NAMELENis gone, except as a vestige in the authentication libraries, where it has beenrechristened.CW ANAMELEN ..CW DIRLENand.CW ERRLENare also gone.All programs that mentionthese constantswill need to be fixed..PPThe simplest place to see this change is in the.CW errstrsystem call, which no longer assumes a buffer of length.CW ERRLENbut now requires a byte-count argument:.P1char buf[...]; errstr(buf, sizeof buf);.P2The 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= 256as a good buffer size.Unlike the old.CW ERRLEN(which had value 64),.CW ERRMAXis advisory, not mandatory, and is not part of the 9P specification..PPWith names, stat buffers, and directories, there isn't even an echo of a fixed-size array any more..SHDirectories and wait messages.PPWith strings now variable-length, a number of system calls needed to change:.CW errstr ,.CW stat ,.CW fstat ,.CW wstat ,.CW fwstat ,and.CW waitare all affected, as is.CW readwhen applied to directories..PPAs far as directories are concerned, most programs don't use the system callsdirectly anyway, since they operate on the machine-independent form, butinstead call the machine-dependent.CW Dirroutines.CW dirstat ,.CW dirread ,etc.These used to fill user-provided fixed-size buffers; now they return objects allocatedby.CW malloc(which must therefore be freed after use).To `stat' a file:.P1Dir *d; d = dirstat(filename);if(d == nil){ fprint(2, "can't stat %s: %r\en", filename); exits("stat");}use(d);free(d);.P2A common new bug is to forget to free a.CW Dirreturned by.CW dirstat ..PP.CW Dirfstatand.CW Dirfwstatwork pretty much as before, but changes to 9P makeit possible to exercise finer-grained control on what fieldsof the.CW Dirare to be changed; see.I stat (2)and.I stat (5)for details..PPReading a directory works in a similar way to.CW dirstat ,with.CW dirreadallocating and filling in an array of.CW Dirstructures.The return value is the number of elements of the array.The arguments to.CW dirreadnow include a pointer to a.CW Dir*to be filled in with the address of the allocated array:.P1Dir *d;int i, n; while((n = dirread(fd, &d)) > 0){ for(i=0; i<n; i++) use(&d[i]); free(d);}.P2A new library function,.CW dirreadall ,has the same form as.CW dirreadbut returns the entire directory in one call:.P1n = dirreadall(fd, &d)for(i=0; i<n; i++) use(&d[i]);free(d);.P2If your program insists on using the underlying.CW statsystem call or its relatives, or wants to operate directly on themachine-independent format returned by.CW stator.CW read ,it will need to be modified.Such programs are rare enough that we'll not discuss them here beyond referring tothe man page.I stat (2)for details.Be aware, though, that it used to be possible to regard the buffer returned by.CW statas a byte array that began with the zero-terminatedname of the file; this is no longer true.With very rare exceptions, programs that call.CW statwould be better recast to use the.CW dirroutines or, if their goal is just to test the existence of a file,.CW access ..PPSimilar changes have affected the.CW waitsystem call. In fact,.CW waitis no longer a system call but a library routine that calls the new.CW awaitsystem call and returns a newly allocated machine-dependent.CW Waitmsgstructure:.P1Waitmsg *w; w = wait();if(w == nil) error("wait: %r");print("pid is %d; exit string %s\en", w->pid, w->msg);free(w);.P2The exit string.CW w->msgmay 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:.P1int pid; pid = waitpid();if(pid < 0) error("wait: %r");print("pid is %d\en", pid);.P2.SHQuoted strings and tokenize.PP.CW Waitgives us a good opportunity to describe how the system copes with all thisfree-format data.Consider the text returned by the.CW awaitsystem 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 thatgenerates the message:.P1n = 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);.P2Note the use of.CW %qto produce a quoted-string representation of the exit status.The.CW %qformat is like %s but will wrap.CW rc -stylesingle quotes around the string if it contains white space or is otherwise ambiguous.The library routine.CW tokenizecan be used to parse data formatted this way: it splits white-space-separatedfields but understands the.CW %qquoting conventions.Here is how the.CW waitlibrary routine builds its.CW Waitmsgfrom the data returned by.CW await :.P1Waitmsg*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.PPThis style of quoted-string and.CW tokenizeis used all through the system now.In particular, devices now.CW tokenizethe messages written to their.CW ctlfiles, 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.P1echo message > /dev/xx/ctl.P2instead of.CW echo.CW -nbecause.CW tokenizetreats the newline character as white space and discards it..PPWhile we're on the subject of quotes and strings, note that the implementation of.CW awaitused.CW snprintrather than.CW sprint .We now deprecate.CW sprintbecause it has no protection against buffer overflow.We prefer.CW snprintor.CW seprint ,to constrain the output.The.CW %qformat is cleverer than most in this regard:if the string is too long to be represented in full,.CW %qis smart enough to produce a truncated but correctly quotedstring within the available space..SHMount.PPAlthough 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 fortransport.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..PPOne example where this matters is that the file system specification in the.CW mountsystem call can now be much longer.Programs like.CW riothat used the specification string in creative ways were limited by the.CW NAMELENrestriction; now they can use the string more freely..CW Rionow accepts a simple but less cryptic specification language for the windowto be created by the.CW mountcall, e.g.:.P1% mount $wsys /mnt/wsys 'new -dx 250 -dy 250 -pid 1234'.P2In the old system, this sort of control was impossible through the.CW mountinterface..PPWhile 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 mountnow takes another argument,.CW afd ,a file descriptor for theauthentication file through which the authentication will be made.For most user-level file servers, which do not require authentication, it issufficient to provide.CW -1as the value of.CW afd:.P1if(mount(fd, -1, "/mnt/wsys", MREPL, "new -dx 250 -dy 250 -pid 1234") < 0) error("mount failed: %r");.P2To connect to servers that require authentication, use the new.CW fauthsystem call or the reimplemented.CW amount(authenticated mount) library call.In fact, since.CW amounthandles both authenticating and non-authenticating servers, it is ofteneasiest just to replace calls to.CW mountby calls to.CW amount ;see.I auth (2)for details..SHPrint.PPThe C library has been heavily reworked in places.Besides the changes mentioned above, itnow has a much more complete set of routines for handling.CW Runestrings (that is, zero-terminated arrays of 16-bit character values).The most sweeping changes, however, are in the way formatted I/O is performed..PPThe.CW printroutine and all its relatives have been reimplemented to offer a numberof improvements:.IP (1)Better buffer management, including the provision of an internal flushroutine, makes it unnecessary to provide large buffers.For example,.CW printuses a much smaller buffer now (reducing stack load) while simultaneouslyremoving 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 printnow works fine in threaded programs, and.CW threadprintis gone..IP (4)The new routine.CW smprintprints into, and returns, storage allocated on demand by.CW malloc ..IP (5)It is now possible to print into a.CW Runestring; for instance,.CW runesmprintis the.CW Runeanalog of.CW smprint ..IP (6)There is improved support for customprint verbs and custom output routines such as error handlers.The routine.CW doprintis gone, but.CW vseprintcan always be used instead.However, the new routines.CW fmtfdinit ,.CW fmtstrinit ,.CW fmtprint ,and friendsare often a better replacement.The details are too long for exposition here;.I fmtinstall (2)explains the new interface and provides examples..IP (7)Lines 1–500 of 606. Load more
.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)