Hi!

----

Attached (as "astksh20130807_devfile001.diff.txt") is a prototype
patch for ast-ksh.2013-08-07 which adds a new "virtual device" called
/dev/file@... which adds the ability to pass extra |O_*| flags to
open(2).

Example usage:
-- snip --
$ ksh -c  'redirect {n}</dev/file@directory/etc/profile '
/bin/ksh: /dev/file@directory/etc/profile: cannot open [Not a directory]
-- snip --
This error happens because /dev/file@directory sets the |O_DIRECTORY|
flag for the following path

** Notes:
* The code explicitly sits in libast only to make sure _any_ libast
consumer can use it (main consumers are going to be the CERN and GE
Healthcare camps who crave for |O_DIRECT| to disable kernel-buffering
for some I/O applications)

* The naming scheme was inspired by ksh93's /dev/tcp&&co. and Solaris
devfs (see http://docs.oracle.com/cd/E19963-01/html/819-3159/fgomr.html)
which uses complex expressions with ',', ':', '@' to describe
physical/virtual devices/device drivers under /devices

* I've avoided using other characters than ',', ':', '@' for the same
reasons as Sun's engineers avoided them in Solaris devfs... some of
them like '#' are toxic to some shells, blanks/whitespaces don't mix
with them either

* I've explicitly used /dev/file@... as basis because using any
relative pathname doesn't work because somehow the attributes need to
be specified.

* Filenames/naming scheme alternatives - what does not work:
- The portable file name character set allows a lot of characters
- Looking at the RPM filename database even more exotic things like
"filename(attr)" or filename{attr}" are already in common use on
Linux.
- "foo;attr" doesn't work either since filename;string" is more or
less reserved for filesystems which do versioning (see VMS, Solaris's
samfs+CD and ISO9660 used on CDROMs).
- The final stroke on that idea comes from Windows where users and
applications use almost every sane/insane combination of characters
from the whole Unicode range except '\0'.

** Todo:
1. Discuss
2. Test SIGPOLL
3. Fix any issues
4. Make sure something like /dev/file@async,nonblock/dev/fd/19 works,
too (which means the matching lookup must be done recursive).

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) [email protected]
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)
diff -r -u original/src/lib/libast/include/ast.h 
build_sigfixes/src/lib/libast/include/ast.h
--- src/lib/libast/include/ast.h        2013-06-27 16:03:06.000000000 +0200
+++ src/lib/libast/include/ast.h        2013-08-09 02:47:25.119595367 +0200
@@ -126,6 +126,7 @@
 {
        int             fd;
        pid_t           pid;
+       int             oflags;
        Pathpart_t      prot;
        Pathpart_t      host;
        Pathpart_t      port;
diff -r -u original/src/lib/libast/path/pathcanon.c 
build_sigfixes/src/lib/libast/path/pathcanon.c
--- src/lib/libast/path/pathcanon.c     2013-08-06 21:12:09.000000000 +0200
+++ src/lib/libast/path/pathcanon.c     2013-08-09 06:38:43.460376644 +0200
@@ -117,7 +117,12 @@
        else if (!size)
                size = strlen(path);
        if (dev)
+       {
+               memset(dev, 0, sizeof(*dev));
                dev->path.offset = 0;
+               dev->oflags = 0;
+               dev->fd = -1;
+       }
        else
                dev = &nodev;
        if (*path == '/')
@@ -264,6 +269,69 @@
                                        dev->prot.offset = 0;
                                }
                        }
+                       else if (size > 6 && s[0] == 'f' && s[1] == 'i' && s[2] 
== 'l' && s[3] == 'e' && s[4] == '@')
+                       {
+                               char            *param = &s[5];
+                               const char      *paramend = strchr(param, '/');
+                               const char      *tok;
+
+                               if (!paramend)
+                               {
+                                       errno = EINVAL;
+                                       return(NULL);
+                               }
+
+                               for (tok = param;
+                                       tok && ((paramend - tok) > 0L);
+                                       tok = strchr(tok, ','))
+                               {
+                                       while(*tok == ',')
+                                               tok++;
+
+                                       errno = 0;
+
+#define MATCH_O_FLAG(s, name, nsize) \
+       ((!strncmp((s), (name), (nsize))) && (s[(nsize)]==',' || 
s[(nsize)]=='/'))
+                                       if (MATCH_O_FLAG(tok, "directory", 9))
+#ifdef O_DIRECTORY
+                                               dev->oflags |= O_DIRECTORY;
+#else
+                                               errno = ENOTSUP;
+#endif
+                                       else if (MATCH_O_FLAG(tok, "nonblock", 
8))
+#ifdef O_NONBLOCK
+                                               dev->oflags |= O_NONBLOCK;
+#else
+                                               errno = ENOTSUP;
+#endif
+                                       else if (MATCH_O_FLAG(tok, "async", 5))
+#ifdef O_ASYNC
+                                               dev->oflags |= O_ASYNC;
+#else
+                                               errno = ENOTSUP;
+#endif
+                                       else if (MATCH_O_FLAG(tok, "sync", 4))
+#ifdef O_SYNC
+                                               dev->oflags |= O_SYNC;
+#else
+                                               errno = ENOTSUP;
+#endif
+                                       else if (MATCH_O_FLAG(tok, "direct", 6))
+#ifdef O_DIRECT
+                                               dev->oflags |= O_DIRECT;
+#else
+                                               errno = ENOTSUP;
+#endif
+                                       else
+                                               errno = EINVAL;
+
+                                       if (errno)
+                                               return (NULL);
+                               }
+
+                               r = paramend;
+                               canon = NULL;
+                       }
                }
                if (r)
                {
diff -r -u original/src/lib/libast/path/pathopen.c 
build_sigfixes/src/lib/libast/path/pathopen.c
--- src/lib/libast/path/pathopen.c      2013-08-06 21:14:58.000000000 +0200
+++ src/lib/libast/path/pathopen.c      2013-08-09 06:47:16.729061537 +0200
@@ -163,6 +163,8 @@
        b = canon ? canon : (char*)path;
        if (pathdev(path, canon, size, flags, &dev) && dev.path.offset)
        {
+               oflags |= dev.oflags;
+
                if (dev.fd >= 0)
                {
                        if (dev.pid > 0 && dev.pid != getpid())
@@ -323,10 +325,33 @@
                        return fd;
                }
        }
+       else
+       {
+               dev.path.offset = 0;
+       }
+
        if (flags & PATH_DEV)
        {
                errno = ENODEV;
                return -1;
        }
-       return openat(fd, b, oflags, mode);
+
+       fd = openat(fd, b + dev.path.offset, oflags, mode);
+       if ((fd >= 0) && (oflags & O_ASYNC))
+       {
+#if defined(O_ASYNC)
+               /*
+                * open(2) on Linux says:
+                * Currently, it is not possible to enable signal-driven I/O
+                * by specifying O_ASYNC when calling open(); use fcntl(2) to
+                * enable this flag.
+                * grrr...
+                */
+
+               oflags = fcntl(fd, F_GETFL, 0);
+               (void)fcntl(fd, F_SETFL, oflags|O_ASYNC);
+#endif
+               (void)fcntl(fd, F_SETOWN, getpid());
+       }
+       return (fd);
 }
_______________________________________________
ast-developers mailing list
[email protected]
http://lists.research.att.com/mailman/listinfo/ast-developers

Reply via email to