Roland Mainz
2013-08-09 05:17:07 UTC
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 at ... which adds the ability to pass extra |O_*| flags to
open(2).
Example usage:
-- snip --
$ ksh -c 'redirect {n}</dev/file at directory/etc/profile '
/bin/ksh: /dev/file at directory/etc/profile: cannot open [Not a directory]
-- snip --
This error happens because /dev/file at 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 at ... 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 at async,nonblock/dev/fd/19 works,
too (which means the matching lookup must be done recursive).
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
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);
}
----
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 at ... which adds the ability to pass extra |O_*| flags to
open(2).
Example usage:
-- snip --
$ ksh -c 'redirect {n}</dev/file at directory/etc/profile '
/bin/ksh: /dev/file at directory/etc/profile: cannot open [Not a directory]
-- snip --
This error happens because /dev/file at 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 at ... 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 at async,nonblock/dev/fd/19 works,
too (which means the matching lookup must be done recursive).
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
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);
}