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