Return to BSD News archive
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!sun-barr!news2me.EBay.Sun.COM!exodus.Eng.Sun.COM!sun!amdcad!BitBlocks.com!bvs From: bvs@BitBlocks.com (Bakul Shah) Newsgroups: comp.os.386bsd.development Subject: Re: A challenge to all true kernel hackers - conditional symlinks. Message-ID: <C3ow4H.FID@BitBlocks.com> Date: 10 Mar 93 20:12:16 GMT References: <JKH.93Mar9214944@whisker.lotus.ie> Organization: Bit Blocks, Inc. Lines: 124 jkh@whisker.lotus.ie (Jordan K. Hubbard) writes: >Finally (this is leading somewhere, honest) you had Apollo's >beautifully simple, yet very powerful, mechanism for doing symlinks, >which was to allow environment variables to be imbeded anywhere within >a link name. I.E.: > ln -s /usr/doc /usr/src/documents/$(LANG) >Depending on the setting of the user's environment variable "LANG", /usr/doc >might then point to /usr/src/documents/german, /usr/src/documents/french, >etc. Currently $, ( and ) are ordinary filename characters. I wouldn't want any special meaning ascribed to these three chars and some other way of gaining the same functionality would be preferable. Though, the basic idea has merit (i.e. I like it!) and can be done without further bloating the kernel. A variant of open() will allow you to do this and more. Here is a sketch of this idea. - Create a new system call open1() that takes a file-descriptor of a directory and a path. Change things so that each process gets file-descriptors for `/' and the current directory (perhaps as `well-known' constants). - open1(fd, path, path_size, flags, mode) will resolve the path relative to the directory `fd'. If the entire path can be resolved, it returns a file-descriptor of the opened file and a null path. - If only part of the path can be resolved, open1() returns the fd of the last component that could be mapped to a directory and the unresolved portion of the path. Now the caller (typically a library routine) can do what it wants with the rest of the path. If you want to implement conditional symlinks as above, it can look up the environment, replace the env. var with its value and call open1 again with the new path and fd. If you want to splice in result of a command in the path, you can do that too. Given open1(), our old friend open() can be safely removed from the kernel. It can be implemented as a library routine with something like open(char * path, int flags, int mode) { char buffer[LOTSASPACE]; char buffer1[LOTSASPACE]; int fd = CWD; extern int errno; char save; for (;;) { int dd; /* Figure out where to start the search */ if (path[0] == '/') { while (path[0] == '/') path++; dd = ROOT; } else dd = fd; strcpy(buffer, path); fd = open1(dd, buffer, sizeof buffer, flags, mode); if (fd < 0) /* error? */ return -1; if (strlen(buffer) == 0) /* are we done? */ return fd; if (buffer[0] == '$') { /* env. variable? */ /* splice in the var value before remaining path */ char * var = ++buffer; while (*buffer && *buffer != '/') buffer++; save = *buffer; *buffer = '\0'; var = getenv(var); if (!var) break; *buffer = save; sprintf(buffer1, "%s%s", var, buffer); } else if (buffer[0] == '`') { /* command? */ /* splice in the command result before remaining path */ FILE * stream; char * command = ++buffer; while (*buffer && *buffer != '/') buffer++; save = *buffer; stream = popen(command); if (!stream) break; fread(buffer1, sizeof buffer1, 1, stream); /* XXX check we got the entire path */ pclose(stream); strcat(buffer1, buffer); } else break; /* the newly doctored path is what we will work with now */ path = buffer1; } /* here in case of an error */ if (fd != CWD) close(fd); errno = ENOENT; return -1; } Like I said, this is merely a sketch; a real design will have to take care of all sorts of details. Implementing open1() shouldn't be that hard though. I would prefer a file mode for such things instead of usurping $ etc. as normal chars. In this case you'd check the mode of returned fd instead of prefix of returned path. Also note that with this scheme even code for following symlinks can be removed from the kernel. On the negative side you make a few more system calls. Comments? Bakul Shah <bvs@BitBlocks.com>