[lxc-devel] [PATCH 18/24] Add local implementation of mntent.h

Stéphane Graber stgraber at ubuntu.com
Tue Jan 8 17:03:08 UTC 2013


Bionic (at least) is missing some of the usual mntent functions.
This adds code defining those that we need when they're missing from the C
library.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 configure.ac         |   2 +-
 src/include/mntent.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/include/mntent.h |  32 ++++++++++
 src/lxc/Makefile.am  |   6 +-
 src/lxc/cgroup.c     |   7 ++-
 src/lxc/conf.c       |   7 ++-
 6 files changed, 222 insertions(+), 5 deletions(-)
 create mode 100644 src/include/mntent.c
 create mode 100644 src/include/mntent.h

diff --git a/configure.ac b/configure.ac
index 0d50bec..3770e8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -227,7 +227,7 @@ AC_CHECK_HEADERS([sys/signalfd.h pty.h sys/capability.h sys/personality.h utmpx.
 AC_CHECK_FUNCS([setns pivot_root sethostname unshare])
 
 # Check for some functions
-AC_CHECK_FUNCS([getline fgetln openpty])
+AC_CHECK_FUNCS([getline fgetln openpty hasmntopt setmntent endmntent])
 
 # Check for some standard binaries
 AC_PROG_GCC_TRADITIONAL
diff --git a/src/include/mntent.c b/src/include/mntent.c
new file mode 100644
index 0000000..a96cd81
--- /dev/null
+++ b/src/include/mntent.c
@@ -0,0 +1,173 @@
+#include <mntent.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Since the values in a line are separated by spaces, a name cannot
+ contain a space. Therefore some programs encode spaces in names
+ by the strings "\040". We undo the encoding when reading an entry.
+ The decoding happens in place. */
+static char *
+decode_name (char *buf)
+{
+    char *rp = buf;
+    char *wp = buf;
+
+    do
+    if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
+    {
+        /* \040 is a SPACE. */
+        *wp++ = ' ';
+        rp += 3;
+    }
+    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
+    {
+        /* \011 is a TAB. */
+        *wp++ = '\t';
+        rp += 3;
+    }
+    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
+    {
+        /* \012 is a NEWLINE. */
+        *wp++ = '\n';
+        rp += 3;
+    }
+    else if (rp[0] == '\\' && rp[1] == '\\')
+    {
+        /* We have to escape \\ to be able to represent all characters. */
+        *wp++ = '\\';
+        rp += 1;
+    }
+    else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
+    {
+        /* \134 is also \\. */
+        *wp++ = '\\';
+        rp += 3;
+    }
+    else
+        *wp++ = *rp;
+    while (*rp++ != '\0');
+
+    return buf;
+}
+
+/* Read one mount table entry from STREAM. Returns a pointer to storage
+ reused on the next call, or null for EOF or error (use feof/ferror to
+ check). */
+struct mntent *getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
+{
+    char *cp;
+    char *head;
+
+    do
+    {
+        char *end_ptr;
+
+        if (fgets (buffer, bufsiz, stream) == NULL)
+        {
+            return NULL;
+        }
+
+        end_ptr = strchr (buffer, '\n');
+        if (end_ptr != NULL) /* chop newline */
+            *end_ptr = '\0';
+        else
+        {
+            /* Not the whole line was read. Do it now but forget it. */
+            char tmp[1024];
+            while (fgets (tmp, sizeof tmp, stream) != NULL)
+                if (strchr (tmp, '\n') != NULL)
+                    break;
+        }
+
+        head = buffer + strspn (buffer, " \t");
+        /* skip empty lines and comment lines: */
+    }
+    while (head[0] == '\0' || head[0] == '#');
+
+    cp = strsep (&head, " \t");
+    mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
+    if (head)
+        head += strspn (head, " \t");
+    cp = strsep (&head, " \t");
+    mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
+    if (head)
+        head += strspn (head, " \t");
+    cp = strsep (&head, " \t");
+    mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
+    if (head)
+        head += strspn (head, " \t");
+    cp = strsep (&head, " \t");
+    mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
+    switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
+    {
+        case 0:
+            mp->mnt_freq = 0;
+        case 1:
+            mp->mnt_passno = 0;
+        case 2:
+            break;
+    }
+
+    return mp;
+}
+
+struct mntent *getmntent (FILE *stream)
+{
+    static struct mntent m;
+    static char *getmntent_buffer;
+
+    #define BUFFER_SIZE 4096
+    if (getmntent_buffer == NULL) {
+        getmntent_buffer = (char *) malloc (BUFFER_SIZE);
+    }
+
+    return getmntent_r (stream, &m, getmntent_buffer, BUFFER_SIZE);
+    #undef BUFFER_SIZE
+}
+
+
+/* Prepare to begin reading and/or writing mount table entries from the
+ beginning of FILE. MODE is as for `fopen'. */
+FILE *setmntent (const char *file, const char *mode)
+{
+    /* Extend the mode parameter with "c" to disable cancellation in the
+    I/O functions and "e" to set FD_CLOEXEC. */
+    size_t modelen = strlen (mode);
+    char newmode[modelen + 3];
+    memcpy (newmode, mode, modelen);
+    memcpy (newmode + modelen, "ce", 3);
+    FILE *result = fopen (file, newmode);
+
+    return result;
+}
+
+
+/* Close a stream opened with `setmntent'. */
+int endmntent (FILE *stream)
+{
+    if (stream) /* SunOS 4.x allows for NULL stream */
+    fclose (stream);
+    return 1; /* SunOS 4.x says to always return 1 */
+}
+
+/* Search MNT->mnt_opts for an option matching OPT.
+ Returns the address of the substring, or null if none found. */
+char *hasmntopt (const struct mntent *mnt, const char *opt)
+{
+    const size_t optlen = strlen (opt);
+    char *rest = mnt->mnt_opts, *p;
+
+    while ((p = strstr (rest, opt)) != NULL)
+    {
+        if ((p == rest || p[-1] == ',')
+            && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
+            return p;
+
+        rest = strchr (p, ',');
+        if (rest == NULL)
+            break;
+        ++rest;
+    }
+
+    return NULL;
+}
diff --git a/src/include/mntent.h b/src/include/mntent.h
new file mode 100644
index 0000000..3f1d16f
--- /dev/null
+++ b/src/include/mntent.h
@@ -0,0 +1,32 @@
+#ifndef _mntent_h
+#define _mntent_h
+
+#include <../config.h>
+
+#if IS_BIONIC
+struct mntent
+{
+    char* mnt_fsname;
+    char* mnt_dir;
+    char* mnt_type;
+    char* mnt_opts;
+    int mnt_freq;
+    int mnt_passno;
+};
+
+extern struct mntent *getmntent (FILE *stream);
+#endif
+
+#ifndef HAVE_SETMNTENT
+FILE *setmntent (const char *file, const char *mode);
+#endif
+
+#ifndef HAVE_ENDMNTENT
+int endmntent (FILE *stream);
+#endif
+
+#ifndef HAVE_HASMNTOPT
+extern char *hasmntopt (const struct mntent *mnt, const char *opt);
+#endif
+
+#endif
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 3d800d5..8bc7b4b 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -20,7 +20,8 @@ pkginclude_HEADERS = \
 if IS_BIONIC
 pkginclude_HEADERS += \
 	../include/getline.h \
-	../include/openpty.h
+	../include/openpty.h \
+	../include/mntent.h
 endif
 
 sodir=$(libdir)
@@ -70,7 +71,8 @@ liblxc_so_SOURCES = \
 if IS_BIONIC
 liblxc_so_SOURCES += \
 	../include/getline.c ../include/getline.h \
-	../include/openpty.c ../include/openpty.h
+	../include/openpty.c ../include/openpty.h \
+	../include/mntent.c ../include/mntent.h
 endif
 
 AM_CFLAGS=-I$(top_srcdir)/src \
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index f6243b8..0f2057f 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -25,7 +25,6 @@
 #undef _GNU_SOURCE
 #include <stdlib.h>
 #include <errno.h>
-#include <mntent.h>
 #include <unistd.h>
 #include <string.h>
 #include <dirent.h>
@@ -44,6 +43,12 @@
 #include <lxc/cgroup.h>
 #include <lxc/start.h>
 
+#if IS_BIONIC
+#include <../include/mntent.h>
+#else
+#include <mntent.h>
+#endif
+
 lxc_log_define(lxc_cgroup, lxc);
 
 #define MTAB "/proc/mounts"
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 4a2fd22..e6efcf0 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -28,7 +28,6 @@
 #include <errno.h>
 #include <string.h>
 #include <dirent.h>
-#include <mntent.h>
 #include <unistd.h>
 #include <sys/wait.h>
 #include <sys/syscall.h>
@@ -78,6 +77,12 @@
 #include <sys/personality.h>
 #endif
 
+#if IS_BIONIC
+#include <../include/mntent.h>
+#else
+#include <mntent.h>
+#endif
+
 #include "lxcseccomp.h"
 
 lxc_log_define(lxc_conf, lxc);
-- 
1.8.0





More information about the lxc-devel mailing list