13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <auth.h>
59a747e4fSDavid du Colombier #include <authsrv.h>
69a747e4fSDavid du Colombier #include "authlocal.h"
73e12c5d1SDavid du Colombier
83e12c5d1SDavid du Colombier enum
93e12c5d1SDavid du Colombier {
103e12c5d1SDavid du Colombier NARG = 15, /* max number of arguments */
119a747e4fSDavid du Colombier MAXARG = 10*ANAMELEN, /* max length of an argument */
123e12c5d1SDavid du Colombier };
133e12c5d1SDavid du Colombier
143e12c5d1SDavid du Colombier static int setenv(char*, char*);
153e12c5d1SDavid du Colombier static char *expandarg(char*, char*);
163e12c5d1SDavid du Colombier static int splitargs(char*, char*[], char*, int);
17fdba4c50SDavid du Colombier static int nsfile(char*, Biobuf *, AuthRpc *);
18fdba4c50SDavid du Colombier static int nsop(char*, int, char*[], AuthRpc*);
193e12c5d1SDavid du Colombier static int callexport(char*, char*);
203e12c5d1SDavid du Colombier static int catch(void*, char*);
213e12c5d1SDavid du Colombier
22fdba4c50SDavid du Colombier int newnsdebug;
23fdba4c50SDavid du Colombier
247dd7cddfSDavid du Colombier static int
freecloserpc(AuthRpc * rpc)25f366f900SDavid du Colombier freecloserpc(AuthRpc *rpc)
26f366f900SDavid du Colombier {
27f366f900SDavid du Colombier if(rpc){
28f366f900SDavid du Colombier close(rpc->afd);
29f366f900SDavid du Colombier auth_freerpc(rpc);
30f366f900SDavid du Colombier }
31f366f900SDavid du Colombier return -1;
32f366f900SDavid du Colombier }
33f366f900SDavid du Colombier
34f366f900SDavid du Colombier static int
buildns(int newns,char * user,char * file)359a747e4fSDavid du Colombier buildns(int newns, char *user, char *file)
367dd7cddfSDavid du Colombier {
3765fa3f8bSDavid du Colombier Biobuf *b;
389a747e4fSDavid du Colombier char home[4*ANAMELEN];
39f366f900SDavid du Colombier int afd, cdroot;
40fe127fd2SDavid du Colombier char *path;
41f366f900SDavid du Colombier AuthRpc *rpc;
427dd7cddfSDavid du Colombier
439a747e4fSDavid du Colombier rpc = nil;
449a747e4fSDavid du Colombier /* try for factotum now because later is impossible */
459a747e4fSDavid du Colombier afd = open("/mnt/factotum/rpc", ORDWR);
46fdba4c50SDavid du Colombier if(afd < 0 && newnsdebug)
47fdba4c50SDavid du Colombier fprint(2, "open /mnt/factotum/rpc: %r\n");
489a747e4fSDavid du Colombier if(afd >= 0){
499a747e4fSDavid du Colombier rpc = auth_allocrpc(afd);
50f366f900SDavid du Colombier if(rpc == nil)
519a747e4fSDavid du Colombier close(afd);
529a747e4fSDavid du Colombier }
53f366f900SDavid du Colombier /* rpc != nil iff afd >= 0 */
54f366f900SDavid du Colombier
5565fa3f8bSDavid du Colombier if(file == nil){
5665fa3f8bSDavid du Colombier if(!newns){
5765fa3f8bSDavid du Colombier werrstr("no namespace file specified");
58f366f900SDavid du Colombier return freecloserpc(rpc);
5965fa3f8bSDavid du Colombier }
607dd7cddfSDavid du Colombier file = "/lib/namespace";
617dd7cddfSDavid du Colombier }
6265fa3f8bSDavid du Colombier b = Bopen(file, OREAD);
6365fa3f8bSDavid du Colombier if(b == 0){
647dd7cddfSDavid du Colombier werrstr("can't open %s: %r", file);
65f366f900SDavid du Colombier return freecloserpc(rpc);
667dd7cddfSDavid du Colombier }
679a747e4fSDavid du Colombier if(newns){
687dd7cddfSDavid du Colombier rfork(RFENVG|RFCNAMEG);
697dd7cddfSDavid du Colombier setenv("user", user);
70f366f900SDavid du Colombier snprint(home, sizeof home, "/usr/%s", user);
717dd7cddfSDavid du Colombier setenv("home", home);
729a747e4fSDavid du Colombier }
73f366f900SDavid du Colombier
74fdba4c50SDavid du Colombier cdroot = nsfile(newns ? "newns" : "addns", b, rpc);
7565fa3f8bSDavid du Colombier Bterm(b);
76f366f900SDavid du Colombier freecloserpc(rpc);
77fe127fd2SDavid du Colombier
78fe127fd2SDavid du Colombier /* make sure we managed to cd into the new name space */
79fe127fd2SDavid du Colombier if(newns && !cdroot){
80fe127fd2SDavid du Colombier path = malloc(1024);
81fe127fd2SDavid du Colombier if(path == nil || getwd(path, 1024) == 0 || chdir(path) < 0)
82fe127fd2SDavid du Colombier chdir("/");
83fe127fd2SDavid du Colombier if(path != nil)
84fe127fd2SDavid du Colombier free(path);
85fe127fd2SDavid du Colombier }
86fe127fd2SDavid du Colombier
8765fa3f8bSDavid du Colombier return 0;
8865fa3f8bSDavid du Colombier }
8965fa3f8bSDavid du Colombier
90fe127fd2SDavid du Colombier static int
nsfile(char * fn,Biobuf * b,AuthRpc * rpc)91fdba4c50SDavid du Colombier nsfile(char *fn, Biobuf *b, AuthRpc *rpc)
9265fa3f8bSDavid du Colombier {
9365fa3f8bSDavid du Colombier int argc;
9465fa3f8bSDavid du Colombier char *cmd, *argv[NARG+1], argbuf[MAXARG*NARG];
95fdba4c50SDavid du Colombier int cdroot;
9665fa3f8bSDavid du Colombier
97fdba4c50SDavid du Colombier cdroot = 0;
989a747e4fSDavid du Colombier atnotify(catch, 1);
9965fa3f8bSDavid du Colombier while(cmd = Brdline(b, '\n')){
10065fa3f8bSDavid du Colombier cmd[Blinelen(b)-1] = '\0';
1019a747e4fSDavid du Colombier while(*cmd==' ' || *cmd=='\t')
1029a747e4fSDavid du Colombier cmd++;
1039a747e4fSDavid du Colombier if(*cmd == '#')
1049a747e4fSDavid du Colombier continue;
1059a747e4fSDavid du Colombier argc = splitargs(cmd, argv, argbuf, NARG);
1069a747e4fSDavid du Colombier if(argc)
107fdba4c50SDavid du Colombier cdroot |= nsop(fn, argc, argv, rpc);
1089a747e4fSDavid du Colombier }
1099a747e4fSDavid du Colombier atnotify(catch, 0);
110fe127fd2SDavid du Colombier return cdroot;
1119a747e4fSDavid du Colombier }
1127dd7cddfSDavid du Colombier
1139a747e4fSDavid du Colombier int
newns(char * user,char * file)1149a747e4fSDavid du Colombier newns(char *user, char *file)
1159a747e4fSDavid du Colombier {
1169a747e4fSDavid du Colombier return buildns(1, user, file);
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier int
addns(char * user,char * file)1207dd7cddfSDavid du Colombier addns(char *user, char *file)
1217dd7cddfSDavid du Colombier {
1229a747e4fSDavid du Colombier return buildns(0, user, file);
1237dd7cddfSDavid du Colombier }
1249a747e4fSDavid du Colombier
1259a747e4fSDavid du Colombier static int
famount(int fd,AuthRpc * rpc,char * mntpt,int flags,char * aname)1269a747e4fSDavid du Colombier famount(int fd, AuthRpc *rpc, char *mntpt, int flags, char *aname)
1279a747e4fSDavid du Colombier {
1289a747e4fSDavid du Colombier int afd;
1299a747e4fSDavid du Colombier AuthInfo *ai;
130f366f900SDavid du Colombier int ret;
1319a747e4fSDavid du Colombier
1329a747e4fSDavid du Colombier afd = fauth(fd, aname);
1339a747e4fSDavid du Colombier if(afd >= 0){
1349a747e4fSDavid du Colombier ai = fauth_proxy(afd, rpc, amount_getkey, "proto=p9any role=client");
1359a747e4fSDavid du Colombier if(ai != nil)
1369a747e4fSDavid du Colombier auth_freeAI(ai);
1379a747e4fSDavid du Colombier }
138f366f900SDavid du Colombier ret = mount(fd, afd, mntpt, flags, aname);
139f366f900SDavid du Colombier if(afd >= 0)
140f366f900SDavid du Colombier close(afd);
141f366f900SDavid du Colombier return ret;
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier
144fe127fd2SDavid du Colombier static int
nsop(char * fn,int argc,char * argv[],AuthRpc * rpc)145fdba4c50SDavid du Colombier nsop(char *fn, int argc, char *argv[], AuthRpc *rpc)
1463e12c5d1SDavid du Colombier {
147219b2ee8SDavid du Colombier char *argv0;
1483e12c5d1SDavid du Colombier ulong flags;
149fdba4c50SDavid du Colombier int fd, i;
15065fa3f8bSDavid du Colombier Biobuf *b;
151fdba4c50SDavid du Colombier int cdroot;
1523e12c5d1SDavid du Colombier
153fdba4c50SDavid du Colombier cdroot = 0;
1543e12c5d1SDavid du Colombier flags = 0;
1553e12c5d1SDavid du Colombier argv0 = 0;
156fdba4c50SDavid du Colombier if (newnsdebug){
157fdba4c50SDavid du Colombier for (i = 0; i < argc; i++)
158fdba4c50SDavid du Colombier fprint(2, "%s ", argv[i]);
159fdba4c50SDavid du Colombier fprint(2, "\n");
160fdba4c50SDavid du Colombier }
1613e12c5d1SDavid du Colombier ARGBEGIN{
1623e12c5d1SDavid du Colombier case 'a':
1633e12c5d1SDavid du Colombier flags |= MAFTER;
1643e12c5d1SDavid du Colombier break;
1653e12c5d1SDavid du Colombier case 'b':
1663e12c5d1SDavid du Colombier flags |= MBEFORE;
1673e12c5d1SDavid du Colombier break;
1683e12c5d1SDavid du Colombier case 'c':
1693e12c5d1SDavid du Colombier flags |= MCREATE;
1703e12c5d1SDavid du Colombier break;
1717dd7cddfSDavid du Colombier case 'C':
1727dd7cddfSDavid du Colombier flags |= MCACHE;
1737dd7cddfSDavid du Colombier break;
1743e12c5d1SDavid du Colombier }ARGEND
1753e12c5d1SDavid du Colombier
1763e12c5d1SDavid du Colombier if(!(flags & (MAFTER|MBEFORE)))
1773e12c5d1SDavid du Colombier flags |= MREPL;
1783e12c5d1SDavid du Colombier
17965fa3f8bSDavid du Colombier if(strcmp(argv0, ".") == 0 && argc == 1){
18065fa3f8bSDavid du Colombier b = Bopen(argv[0], OREAD);
18165fa3f8bSDavid du Colombier if(b == nil)
182fe127fd2SDavid du Colombier return 0;
183fdba4c50SDavid du Colombier cdroot |= nsfile(fn, b, rpc);
18465fa3f8bSDavid du Colombier Bterm(b);
18565fa3f8bSDavid du Colombier }else if(strcmp(argv0, "clear") == 0 && argc == 0)
18665fa3f8bSDavid du Colombier rfork(RFCNAMEG);
187fdba4c50SDavid du Colombier else if(strcmp(argv0, "bind") == 0 && argc == 2){
188fdba4c50SDavid du Colombier if(bind(argv[0], argv[1], flags) < 0 && newnsdebug)
189fdba4c50SDavid du Colombier fprint(2, "%s: bind: %s %s: %r\n", fn, argv[0], argv[1]);
190fdba4c50SDavid du Colombier }else if(strcmp(argv0, "unmount") == 0){
1917dd7cddfSDavid du Colombier if(argc == 1)
1927dd7cddfSDavid du Colombier unmount(nil, argv[0]);
1937dd7cddfSDavid du Colombier else if(argc == 2)
1947dd7cddfSDavid du Colombier unmount(argv[0], argv[1]);
1957dd7cddfSDavid du Colombier }else if(strcmp(argv0, "mount") == 0){
1963e12c5d1SDavid du Colombier fd = open(argv[0], ORDWR);
197fdba4c50SDavid du Colombier if(argc == 2){
198fdba4c50SDavid du Colombier if(famount(fd, rpc, argv[1], flags, "") < 0 && newnsdebug)
199fdba4c50SDavid du Colombier fprint(2, "%s: mount: %s %s: %r\n", fn, argv[0], argv[1]);
200fdba4c50SDavid du Colombier }else if(argc == 3){
201fdba4c50SDavid du Colombier if(famount(fd, rpc, argv[1], flags, argv[2]) < 0 && newnsdebug)
202fdba4c50SDavid du Colombier fprint(2, "%s: mount: %s %s %s: %r\n", fn, argv[0], argv[1], argv[2]);
203fdba4c50SDavid du Colombier }
2043e12c5d1SDavid du Colombier close(fd);
2057dd7cddfSDavid du Colombier }else if(strcmp(argv0, "import") == 0){
2063e12c5d1SDavid du Colombier fd = callexport(argv[0], argv[1]);
2073e12c5d1SDavid du Colombier if(argc == 2)
2089a747e4fSDavid du Colombier famount(fd, rpc, argv[1], flags, "");
2093e12c5d1SDavid du Colombier else if(argc == 3)
2109a747e4fSDavid du Colombier famount(fd, rpc, argv[2], flags, "");
2113e12c5d1SDavid du Colombier close(fd);
212fdba4c50SDavid du Colombier }else if(strcmp(argv0, "cd") == 0 && argc == 1){
213fe127fd2SDavid du Colombier if(chdir(argv[0]) == 0 && *argv[0] == '/')
214fe127fd2SDavid du Colombier cdroot = 1;
215fdba4c50SDavid du Colombier }
216fe127fd2SDavid du Colombier return cdroot;
2173e12c5d1SDavid du Colombier }
2183e12c5d1SDavid du Colombier
2199a747e4fSDavid du Colombier static char *wocp = "sys: write on closed pipe";
2203e12c5d1SDavid du Colombier
2213e12c5d1SDavid du Colombier static int
catch(void * x,char * m)2223e12c5d1SDavid du Colombier catch(void *x, char *m)
2233e12c5d1SDavid du Colombier {
2243e12c5d1SDavid du Colombier USED(x);
2253e12c5d1SDavid du Colombier return strncmp(m, wocp, strlen(wocp)) == 0;
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier
2283e12c5d1SDavid du Colombier static int
callexport(char * sys,char * tree)2293e12c5d1SDavid du Colombier callexport(char *sys, char *tree)
2303e12c5d1SDavid du Colombier {
2313e12c5d1SDavid du Colombier char *na, buf[3];
2323e12c5d1SDavid du Colombier int fd;
2339a747e4fSDavid du Colombier AuthInfo *ai;
2343e12c5d1SDavid du Colombier
2353e12c5d1SDavid du Colombier na = netmkaddr(sys, 0, "exportfs");
2363e12c5d1SDavid du Colombier if((fd = dial(na, 0, 0, 0)) < 0)
2373e12c5d1SDavid du Colombier return -1;
2389a747e4fSDavid du Colombier if((ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client")) == nil
2399a747e4fSDavid du Colombier || write(fd, tree, strlen(tree)) < 0
2403e12c5d1SDavid du Colombier || read(fd, buf, 3) != 2 || buf[0]!='O' || buf[1]!= 'K'){
2413e12c5d1SDavid du Colombier close(fd);
2429a747e4fSDavid du Colombier auth_freeAI(ai);
2433e12c5d1SDavid du Colombier return -1;
2443e12c5d1SDavid du Colombier }
2459a747e4fSDavid du Colombier auth_freeAI(ai);
2463e12c5d1SDavid du Colombier return fd;
2473e12c5d1SDavid du Colombier }
2483e12c5d1SDavid du Colombier
249fdba4c50SDavid du Colombier static char*
unquote(char * s)250fdba4c50SDavid du Colombier unquote(char *s)
251fdba4c50SDavid du Colombier {
252fdba4c50SDavid du Colombier char *r, *w;
253fdba4c50SDavid du Colombier int inquote;
254fdba4c50SDavid du Colombier
255fdba4c50SDavid du Colombier inquote = 0;
256fdba4c50SDavid du Colombier for(r=w=s; *r; r++){
257fdba4c50SDavid du Colombier if(*r != '\''){
258fdba4c50SDavid du Colombier *w++ = *r;
259fdba4c50SDavid du Colombier continue;
260fdba4c50SDavid du Colombier }
261fdba4c50SDavid du Colombier if(inquote){
262fdba4c50SDavid du Colombier if(*(r+1) == '\''){
263fdba4c50SDavid du Colombier *w++ = '\'';
264fdba4c50SDavid du Colombier r++;
265fdba4c50SDavid du Colombier }else
266fdba4c50SDavid du Colombier inquote = 0;
267fdba4c50SDavid du Colombier }else
268fdba4c50SDavid du Colombier inquote = 1;
269fdba4c50SDavid du Colombier }
270fdba4c50SDavid du Colombier *w = 0;
271fdba4c50SDavid du Colombier return s;
272fdba4c50SDavid du Colombier }
273fdba4c50SDavid du Colombier
2743e12c5d1SDavid du Colombier static int
splitargs(char * p,char * argv[],char * argbuf,int nargv)27565fa3f8bSDavid du Colombier splitargs(char *p, char *argv[], char *argbuf, int nargv)
2763e12c5d1SDavid du Colombier {
2773e12c5d1SDavid du Colombier char *q;
27865fa3f8bSDavid du Colombier int i, n;
2793e12c5d1SDavid du Colombier
280fdba4c50SDavid du Colombier n = gettokens(p, argv, nargv, " \t\r");
28165fa3f8bSDavid du Colombier if(n == nargv)
28265fa3f8bSDavid du Colombier return 0;
28365fa3f8bSDavid du Colombier for(i = 0; i < n; i++){
28465fa3f8bSDavid du Colombier q = argv[i];
28565fa3f8bSDavid du Colombier argv[i] = argbuf;
2863e12c5d1SDavid du Colombier argbuf = expandarg(q, argbuf);
287fdba4c50SDavid du Colombier if(argbuf == nil)
2883e12c5d1SDavid du Colombier return 0;
289fdba4c50SDavid du Colombier unquote(argv[i]);
2903e12c5d1SDavid du Colombier }
29165fa3f8bSDavid du Colombier return n;
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier
294fdba4c50SDavid du Colombier static char*
nextdollar(char * arg)295fdba4c50SDavid du Colombier nextdollar(char *arg)
296fdba4c50SDavid du Colombier {
297fdba4c50SDavid du Colombier char *p;
298fdba4c50SDavid du Colombier int inquote;
299fdba4c50SDavid du Colombier
300fdba4c50SDavid du Colombier inquote = 0;
301fdba4c50SDavid du Colombier for(p=arg; *p; p++){
302fdba4c50SDavid du Colombier if(*p == '\'')
303fdba4c50SDavid du Colombier inquote = !inquote;
304fdba4c50SDavid du Colombier if(*p == '$' && !inquote)
305fdba4c50SDavid du Colombier return p;
306fdba4c50SDavid du Colombier }
307fdba4c50SDavid du Colombier return nil;
308fdba4c50SDavid du Colombier }
309fdba4c50SDavid du Colombier
3103e12c5d1SDavid du Colombier /*
3113e12c5d1SDavid du Colombier * copy the arg into the buffer,
3123e12c5d1SDavid du Colombier * expanding any environment variables.
3133e12c5d1SDavid du Colombier * environment variables are assumed to be
3149a747e4fSDavid du Colombier * names (ie. < ANAMELEN long)
3153e12c5d1SDavid du Colombier * the entire argument is expanded to be at
3163e12c5d1SDavid du Colombier * most MAXARG long and null terminated
3173e12c5d1SDavid du Colombier * the address of the byte after the terminating null is returned
3183e12c5d1SDavid du Colombier * any problems cause a 0 return;
3193e12c5d1SDavid du Colombier */
3203e12c5d1SDavid du Colombier static char *
expandarg(char * arg,char * buf)3213e12c5d1SDavid du Colombier expandarg(char *arg, char *buf)
3223e12c5d1SDavid du Colombier {
323fdba4c50SDavid du Colombier char env[3+ANAMELEN], *p, *x;
3243e12c5d1SDavid du Colombier int fd, n, len;
3253e12c5d1SDavid du Colombier
3263e12c5d1SDavid du Colombier n = 0;
327fdba4c50SDavid du Colombier while(p = nextdollar(arg)){
3283e12c5d1SDavid du Colombier len = p - arg;
3299a747e4fSDavid du Colombier if(n + len + ANAMELEN >= MAXARG-1)
3303e12c5d1SDavid du Colombier return 0;
3313e12c5d1SDavid du Colombier memmove(&buf[n], arg, len);
3323e12c5d1SDavid du Colombier n += len;
3333e12c5d1SDavid du Colombier p++;
334fdba4c50SDavid du Colombier arg = strpbrk(p, "/.!'$");
335fdba4c50SDavid du Colombier if(arg == nil)
336fdba4c50SDavid du Colombier arg = p+strlen(p);
3373e12c5d1SDavid du Colombier len = arg - p;
338fdba4c50SDavid du Colombier if(len == 0 || len >= ANAMELEN)
3393e12c5d1SDavid du Colombier continue;
3403e12c5d1SDavid du Colombier strcpy(env, "#e/");
3413e12c5d1SDavid du Colombier strncpy(env+3, p, len);
3423e12c5d1SDavid du Colombier env[3+len] = '\0';
3433e12c5d1SDavid du Colombier fd = open(env, OREAD);
3443e12c5d1SDavid du Colombier if(fd >= 0){
3459a747e4fSDavid du Colombier len = read(fd, &buf[n], ANAMELEN - 1);
3465d459b5aSDavid du Colombier /* some singleton environment variables have trailing NULs */
3475d459b5aSDavid du Colombier /* lists separate entries with NULs; we arbitrarily take the first element */
3485d459b5aSDavid du Colombier if(len > 0){
3495d459b5aSDavid du Colombier x = memchr(&buf[n], 0, len);
3505d459b5aSDavid du Colombier if(x != nil)
3515d459b5aSDavid du Colombier len = x - &buf[n];
3523e12c5d1SDavid du Colombier n += len;
3535d459b5aSDavid du Colombier }
3543e12c5d1SDavid du Colombier close(fd);
3553e12c5d1SDavid du Colombier }
3563e12c5d1SDavid du Colombier }
3573e12c5d1SDavid du Colombier len = strlen(arg);
3583e12c5d1SDavid du Colombier if(n + len >= MAXARG - 1)
3593e12c5d1SDavid du Colombier return 0;
3603e12c5d1SDavid du Colombier strcpy(&buf[n], arg);
3613e12c5d1SDavid du Colombier return &buf[n+len+1];
3623e12c5d1SDavid du Colombier }
3633e12c5d1SDavid du Colombier
3643e12c5d1SDavid du Colombier static int
setenv(char * name,char * val)3653e12c5d1SDavid du Colombier setenv(char *name, char *val)
3663e12c5d1SDavid du Colombier {
3673e12c5d1SDavid du Colombier int f;
3689a747e4fSDavid du Colombier char ename[ANAMELEN+6];
3693e12c5d1SDavid du Colombier long s;
3703e12c5d1SDavid du Colombier
371*c6056937SDavid du Colombier snprint(ename, sizeof ename, "#e/%s", name);
3723e12c5d1SDavid du Colombier f = create(ename, OWRITE, 0664);
3733e12c5d1SDavid du Colombier if(f < 0)
3743e12c5d1SDavid du Colombier return -1;
3753e12c5d1SDavid du Colombier s = strlen(val);
3763e12c5d1SDavid du Colombier if(write(f, val, s) != s){
3773e12c5d1SDavid du Colombier close(f);
3783e12c5d1SDavid du Colombier return -1;
3793e12c5d1SDavid du Colombier }
3803e12c5d1SDavid du Colombier close(f);
3813e12c5d1SDavid du Colombier return 0;
3823e12c5d1SDavid du Colombier }
383