5

Question:

In C/C++/C#. (I need it for C#, but C and C++ is also fine).

How can I do a mount -a on Linux. I mean programmatically, without starting a process like

system("mount -a");

Edit:
Note the "-a".
My question is not actually about how to mount A mountpoint.
It's about how to mount ALL mountpoints in /etc/fstab.
That means parsing the file, extracting the mountpoints, check if already mounted, and only if not already mounted, mount...

Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • Probably the best way to learn this by looking at the source of the actually command "mount" – John Riselvato May 30 '12 at 16:27
  • 1
    The Mono.Unix docs for mount there say : "mount Inherently non-portable across the various Unix flavours, and will never be supported. Instead, use stem.Diagnostics.Process and invoke the command-line mount(8) program." I don't see why executing a subprocess here is a bad thing. – IanNorton May 30 '12 at 16:30
  • @IanNorton: I also read this, and it's only for my server, not anybody else's, so portability is not an issue. – Stefan Steiger May 30 '12 at 16:36

3 Answers3

9

Check out the man page by typing man 2 mount. It talks about a system call that can avoid the actual use of system():

#include <sys/mount.h>
int mount(const char *source, const char *target, const char *filesystemtype,
          unsigned long mountflags, const void *data);
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
squiguy
  • 32,370
  • 6
  • 56
  • 63
  • Yea, I actually did. You (and everybody else) missed the "-a". Only mounting one, I managed to implement myself already - in C# :) – Stefan Steiger May 30 '12 at 16:40
5

@Ignacio Vazquez-Abrams: About your "no way to perform this in C#" ...

Proof that you're wrong by contradiction:

The bellow code is capable of doing the same as

(apt-get install jfsutils)
dd if=/dev/zero of=jfs.dsk bs=1048576 count=150
mkfs.jfs -O jfs.dsk
mkdir -p /mnt/jfs
mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop
umount /mnt/jfs/

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Syscalls
{


    public class Linux
    {

        // apt-get source util-linux
        // ./mount/loop.h
        // ./mount/mount.c
        // ./mount/lomount.c
        // ./include/linux_version.h
        // ./lib/linux_version.c
        // ./include/linux_reboot.h



        protected const int LOOP_SET_FD = 0x4C00;
        protected const int LOOP_CLR_FD = 0x4C01;

        protected const int LOOP_GET_STATUS = 0x4C03;
        protected const int LOOP_SET_STATUS = 0x4C02;

        protected const int LOOP_GET_STATUS64 = 0x4C05;
        protected const int LOOP_SET_STATUS64 = 0x4C04;

        protected const int LO_NAME_SIZE = 64;
        protected const int LO_KEY_SIZE = 32;

        protected const int PATH_MAX = 4096;


        // MS_RELATIME  //(default for Linux >= 2.6.30) 
        // MS_STRICTATIME //(default for Linux < 2.6.30) 

        // http://harmattan-dev.nokia.com/docs/library/html/manpages/headers/sys/mount.html
        public enum MountFlags : ulong
        {
            MS_RDONLY = 1,         // Mount read-only.
            MS_NOSUID = 2,         // Ignore suid and sgid bits.
            MS_NODEV = 4,         // Disallow access to device special files.
            MS_NOEXEC = 8,         // Disallow program execution.
            MS_SYNCHRONOUS = 16,    // Writes are synced at once.
            MS_REMOUNT = 32,    // Alter flags of a mounted FS.
            MS_MANDLOCK = 64,    // Allow mandatory locks on an FS.
            S_WRITE = 128,   // Write on file/directory/symlink.
            S_APPEND = 256,   // Append-only file.
            S_IMMUTABLE = 512,   // Immutable file.
            MS_NOATIME = 1024,  // Do not update access times.
            MS_NODIRATIME = 2048,  // Do not update directory access times.
            MS_BIND = 4096,  // Bind directory at different place.
        }; // End Enum MountFlags : ulong

        /*
        // http://unix.superglobalmegacorp.com/Net2/newsrc/sys/fcntl.h.html
        [Flags]
        protected enum OpenFlags : int
        {
            // open-only flags 
            O_RDONLY = 0x0000,      // open for reading only 
            O_WRONLY = 0x0001,      // open for writing only 
            O_RDWR = 0x0002,        // open for reading and writing 
            O_ACCMODE = 0x0003,     // mask for above modes 

            //#ifdef KERNEL
            FREAD = 0x0001,
            FWRITE = 0x0002,
            //#endif
            O_NONBLOCK = 0x0004,    // no delay 
            O_APPEND = 0x0008,      // set append mode 
            //#ifndef _POSIX_SOURCE
            O_SHLOCK = 0x0010,      // open with shared file lock 
            O_EXLOCK = 0x0020,      // open with exclusive file lock 
            O_ASYNC = 0x0040,       // signal pgrp when data ready 
            O_FSYNC = 0x0080,       // synchronous writes 
            //#endif
            O_CREAT = 0x0200,       // create if nonexistant 
            O_TRUNC = 0x0400,       // truncate to zero length 
            O_EXCL = 0x0800,        // error if already exists 
            //#ifdef KERNEL
            FMARK = 0x1000,         // mark during gc() 
            FDEFER = 0x2000,        // defer for next gc pass 
            FHASLOCK = 0x4000       // descriptor holds advisory lock 
        } // End Enum OpenFlags : int
        */

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        protected struct loop_info
        {
            public int lo_number;
            public System.UIntPtr lo_device; //my_dev_t lo_device; // my_dev_t: long unsigned int
            public System.UIntPtr lo_inode; //unsigned long lo_inode;
            public System.UIntPtr lo_rdevice; //my_dev_t    lo_rdevice;// my_dev_t: long unsigned int
            public int lo_offset;
            public int lo_encrypt_type;
            public int lo_encrypt_key_size;
            public int lo_flags;

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
            public string lo_name; //char       lo_name[LO_NAME_SIZE];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_KEY_SIZE)]
            public string lo_encrypt_key; //unsigned char   lo_encrypt_key[LO_KEY_SIZE];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2)]
            public System.UIntPtr[] lo_init; //unsigned long    lo_init[2];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 4)]
            public string reserved; //char      reserved[4];
        }; // End Struct loop_info


        protected struct loop_info64
        {
            public System.UInt64 lo_device;
            public System.UInt64 lo_inode;
            public System.UInt64 lo_rdevice;
            public System.UInt64 lo_offset;
            public System.UInt64 lo_sizelimit; /* bytes, 0 == max available */
            public System.UInt32 lo_number;
            public System.UInt32 lo_encrypt_type;
            public System.UInt32 lo_encrypt_key_size;
            public System.UInt32 lo_flags;

            // http://stackoverflow.com/questions/1725855/uint8-t-vs-unsigned-char

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
            public string lo_file_name; // uint8_t      lo_file_name[LO_NAME_SIZE];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
            public string lo_crypt_name; // uint8_t     lo_crypt_name[LO_NAME_SIZE];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_KEY_SIZE)]
            public string lo_encrypt_key; // uint8_t        lo_encrypt_key[LO_KEY_SIZE];

            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2)]
            public System.UInt64[] lo_init;
        }; // End Struct loop_info64


        // http://www.student.cs.uwaterloo.ca/~cs350/common/os161-src-html/kern_2include_2kern_2stat_8h.html
        protected static bool S_ISBLK(int mode)
        {
            const uint S_IFMT = 070000;
            const uint S_IFBLK = 050000;
            return (((mode) & S_IFMT) == S_IFBLK);
        } // End Function S_ISBLK


        public static int KERNEL_VERSION()
        {
            Mono.Unix.Native.Utsname unameres = new Mono.Unix.Native.Utsname();
            Mono.Unix.Native.Syscall.uname(out unameres);

            System.Text.RegularExpressions.Match ma = System.Text.RegularExpressions.Regex.Match(unameres.release, @"(\d+).(\d+).(\d+)(-)?(\d+)?");
            string strMajor = ma.Groups[1].Value;
            string strMinor = ma.Groups[2].Value;
            string strTiny = ma.Groups[3].Value;
            string strPatchlevel = ma.Groups[5].Value;

            int a = System.Convert.ToInt32(strMajor);
            int b = System.Convert.ToInt32(strMinor);
            int c = System.Convert.ToInt32(strTiny);

            return KERNEL_VERSION(a, b, c);
        } // End Function KERNEL_VERSION


        //# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
        public static int KERNEL_VERSION(int a, int b, int c)
        {
            return (((a) << 16) + ((b) << 8) + (c));
        }


        public static string CreateVirtualDisk(int iSize)
        {
            string strBaseDirectory = @"/volumes/";
            string strFileName = System.Guid.NewGuid().ToString().Replace("-", "") + ".dsk";

            string strFileNameAndPath = System.IO.Path.Combine(strBaseDirectory, strFileName);

            using (var fs = new System.IO.FileStream(strFileNameAndPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
            {
                fs.SetLength(iSize);
            } // End Using fs

            return strFileNameAndPath;
        } // End Function CreateVirtualDisk


        // umount("/mnt/testdisk");
        public static bool umount(string strMountPoint)
        {
            int status = UnsafeNativeMethods.umount(strMountPoint);

            if (status == 0)
                Console.WriteLine("Successfully unmounted device.");
            else
                Console.WriteLine("Unmount status: " + status.ToString());

            if (status == 0)
                return true;

            return false;
        } // End Function Unmount


        public static string find_unused_loop_device()
        {
            string dev;
            int fd;
            Mono.Unix.Native.Stat statbuf;
            loop_info loopinfo = new loop_info();
            loop_info64 lo64 = new loop_info64();

            for (int i = 0; i <= 7; i++)
            {
                dev = "/dev/loop" + i.ToString();

                if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(dev, out statbuf)) == (false && S_ISBLK((int)statbuf.st_mode)))
                {

                    if ((fd = Mono.Unix.Native.Syscall.open(dev, Mono.Unix.Native.OpenFlags.O_RDONLY)) >= 0)
                    {

                        // This block was commented out initially
                        if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS64, ref lo64) == 0)
                        {
                            if (Mono.Unix.Native.Syscall.GetLastError() == Mono.Unix.Native.Errno.ENXIO)
                            {   // probably free
                                Mono.Unix.Native.Syscall.close(fd);
                                return dev;
                            }
                        }


                        if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref loopinfo) != 0)
                        {
                            // http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/include/asm-generic/errno-base.h#L9
                            // ENXIO - No such device or address
                            // The device accessed by a command is physically not present, 
                            // or the address of the device is not present
                            if (Mono.Unix.Native.Syscall.GetLastError() == Mono.Unix.Native.Errno.ENXIO)
                            {
                                // that means the device is most-likely free
                                Mono.Unix.Native.Syscall.close(fd);
                                return dev;
                            }

                        } // End if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref loopinfo) != 0)

                        Mono.Unix.Native.Syscall.close(fd);
                    } // End if ((fd = UnsafeNativeMethods.open(dev, OpenFlags.O_RDONLY)) >= 0)

                } // End if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(dev, out statbuf)) == (false && S_ISBLK((int)statbuf.st_mode)))

            } // Next i

            return null;
        } // End Function find_unused_loop_device


        public static int set_loop(string device, string file, int offset, ref int loopro)
        {
            loop_info loopinfo = new loop_info();
            int fd = 0, ffd = 0;
            Mono.Unix.Native.OpenFlags mode;

            mode = loopro != 0 ? Mono.Unix.Native.OpenFlags.O_RDONLY : Mono.Unix.Native.OpenFlags.O_RDWR;

            if (
                    (
                        ffd = Mono.Unix.Native.Syscall.open(file, mode)
                    ) < 0
                    &&
                    (
                        (!System.Convert.ToBoolean((int)loopro))
                        &&
                        (

                            Mono.Unix.Native.Syscall.GetLastError() != Mono.Unix.Native.Errno.EROFS
                            ||
                            (ffd = Mono.Unix.Native.Syscall.open(file, mode = Mono.Unix.Native.OpenFlags.O_RDONLY))
                            < 0
                        )
                    )
                ) // if
            {
                Console.WriteLine("Error: file: " + file);
                //perror_msg("%s", file);
                return 1;
            } // End if


            if ((fd = Mono.Unix.Native.Syscall.open(device, mode)) < 0)
            {
                Mono.Unix.Native.Syscall.close(ffd);
                Console.WriteLine("Error: device: " + device);
                //perror_msg("%s", device);
                return 1;
            }

            loopro = System.Convert.ToInt32(mode == Mono.Unix.Native.OpenFlags.O_RDONLY);
            //memset(&loopinfo, 0, sizeof(loopinfo));


            //safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
            //strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
            loopinfo.lo_name = string.IsNullOrEmpty(file) ? null : file.Substring(0, Math.Min(file.Length, LO_NAME_SIZE));

            loopinfo.lo_offset = offset;
            loopinfo.lo_encrypt_key_size = 0;

            if (UnsafeNativeMethods.ioctl(fd, LOOP_SET_FD, ffd) < 0)
            {
                Console.WriteLine("ioctl: LOOP_SET_FD");
                //perror_msg("ioctl: LOOP_SET_FD");
                Mono.Unix.Native.Syscall.close(fd);
                Mono.Unix.Native.Syscall.close(ffd);
                return 1;
            }

            if (UnsafeNativeMethods.ioctl(fd, LOOP_SET_STATUS, ref loopinfo) < 0)
            {
                int ro = 0;
                UnsafeNativeMethods.ioctl(fd, LOOP_CLR_FD, ref ro);
                //perror_msg("ioctl: LOOP_SET_STATUS");
                Console.WriteLine("ioctl: LOOP_SET_STATUS");
                Mono.Unix.Native.Syscall.close(fd);
                Mono.Unix.Native.Syscall.close(ffd);
                return 1;
            }

            Mono.Unix.Native.Syscall.close(fd);
            Mono.Unix.Native.Syscall.close(ffd);
            return 0;
        } // End Function set_loop


        public static int del_loop(string device)
        {
            int fd;

            if ((fd = Mono.Unix.Native.Syscall.open(device, Mono.Unix.Native.OpenFlags.O_RDONLY)) < 0)
            {
                //perror_msg("%s", device);
                Console.WriteLine("Error description: " + Mono.Unix.Native.Syscall.strerror(Mono.Unix.Native.Syscall.GetLastError()));
                return 0;
            }

            int r = 0;

            if (UnsafeNativeMethods.ioctl(fd, LOOP_CLR_FD, ref r) < 0)
            {
                //perror_msg("ioctl: LOOP_CLR_FD");
                Console.WriteLine("ioctl: LOOP_CLR_FD\nError description: " + Mono.Unix.Native.Syscall.strerror(Mono.Unix.Native.Syscall.GetLastError()));
                return 0;
            }

            Mono.Unix.Native.Syscall.close(fd);
            Console.WriteLine("Successfully closed loop-device\n");
            return 1;
        } // End Function del_loop


        public static bool mount(string strDevice, string strMountPoint, string strFsType)
        {
            return mount(strDevice, strMountPoint, strFsType, MountFlags.MS_NOATIME);
        }

        public static bool mount(string strDevice, string strMountPoint, string strFsType, MountFlags mflags)
        {
            return mount(strDevice, strMountPoint, strFsType, mflags, IntPtr.Zero);
        }


        // http://cboard.cprogramming.com/c-programming/126630-using-sys-mount-h-mounting-usb-thumb-drive.html
        // http://stackoverflow.com/questions/10458549/mount-usb-drive-in-linux-with-c
        // mount("/dev/loop1", "/mnt/testdisk", "vfat");
        public static bool mount(string strDevice, string strMountPoint, string strFsType, MountFlags mflags, IntPtr options)
        {

            // http://linux.die.net/man/2/mount
            // MS_RDONLY
            // MS_RELATIME (default for Linux >= 2.6.30) 
            // MS_STRICTATIME (default for Linux < 2.6.30) 

            if (UnsafeNativeMethods.mount(strDevice, strMountPoint, strFsType, mflags, options) != 0)
            {
                Mono.Unix.Native.Errno errno = Mono.Unix.Native.Syscall.GetLastError();

                if (errno == Mono.Unix.Native.Errno.EBUSY)
                {
                    Console.WriteLine("Mountpoint busy");
                }
                else
                {
                    Console.WriteLine("Mount error: " + Mono.Unix.Native.Syscall.strerror(errno));
                }

                return false;
            }
            else
            {
                Console.WriteLine("Successfully mounted device !");
            }

            return true; ;
        } // End Function mount


        static class UnsafeNativeMethods
        {


            //string name = "Test";
            //TypedReference tf = __makeref(name);
            //int c = VarSum(2, __arglist(__makeref(name)));


            // http://khason.net/blog/how-to-pinvoke-varargs-variable-arguments-in-c-or-hidden-junk-in-clr/
            // //int rv = ioctl(2, 3, __arglist(5, 10));
            [System.Runtime.InteropServices.DllImportAttribute("libc", EntryPoint = "ioctl",
            CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
            public static extern int ioctl(int descriptor, int request, __arglist);

            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            public static extern int ioctl(int d, int request, int data);

            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            public static extern int ioctl(int d, int request, ref int data);

            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            public static extern int ioctl(int d, int request, ref loop_info data);

            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            public static extern int ioctl(int d, int request, ref loop_info64 data);

            //[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            //public static extern int open([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]string pathname, OpenFlags flags);

            //[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            //public static extern int close(int fd);

            //[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            //public static extern IntPtr read(int fd, IntPtr buffer, UIntPtr count);
            ///////unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);

            // http://linux.die.net/man/2/mount
            // http://www.kernel.org/doc/man-pages/online/pages/man2/mount.2.html
            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            private static extern int mount(string source, string target, string filesystemtype, UIntPtr mountflags, System.IntPtr data);
            //int mount(const char *source, const char *target, const char *filesystemtype, ulong mountflags, const void *data);


            public static int mount(string source, string target, string filesystemtype, MountFlags mountflags, System.IntPtr data)
            {
                System.UIntPtr p = new System.UIntPtr((ulong)mountflags);
                return mount(source, target, filesystemtype, p, data);
            } // End Function mount


            [System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
            public static extern int umount(string strMountPoint);
            // extern int umount (__const char *__special_file);
        } // End Class UnsafeNativeMethods


        public static void TryMount()
        {
            const bool SUCCESS = true;

            // int iReturnCode = Mono.Unix.Native.Syscall.system("mount -a");
            // int iReturnCode = Mono.Unix.Native.Syscall.system("mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop");
            // int iReturnCode = Mono.Unix.Native.Syscall.system("mkfs.jfs -O \"jfs.dsk\"");

            string strLoopDeviceToUse = find_unused_loop_device();
            string strMountPoint = "/mnt/testdisk";

            int ro = 0;
            set_loop(strLoopDeviceToUse, "/volumes/testdisk.dsk", 0, ref ro);

            string strLoopDeviceToUse2 = find_unused_loop_device();

            bool status = false;
            int mountAttempts = 0;
            do
            {
                //status = mount("/dev/sda1", "/media/usb0", "vfat", MS_MGC_VAL | MS_NOSUID, "");
                status = mount(strLoopDeviceToUse, strMountPoint, "vfat", MountFlags.MS_NOATIME);

                if (status != SUCCESS)
                    System.Threading.Thread.Sleep(1000);

                mountAttempts++;
            } while (status != SUCCESS && mountAttempts < 3);

        } // End Sub TryMount



        // In gcc or g++, to show all of the macros that are defined for a given platform:
        // gcc -dM -E test.c
        // or 
        // g++ -dM -E test.cpp

        // http://manual.cream.org/index.cgi/gnu_dev_major.3
        // http://www.gnu.org/software/gnulib/coverage/usr/include/sys/sysmacros.h.gcov.frameset.html
        // http://en.wikipedia.org/wiki/C_data_types
        protected static uint gnu_dev_major(System.UInt64 __dev)
        {
            return (uint)((uint)(((__dev >> 8) & 0xfff)) | ((uint)(__dev >> 32) & ~0xfff));
        }

        protected static uint gnu_dev_minor(System.UInt64 __dev)
        {
            return (uint)((uint)(__dev & 0xff) | ((uint)(__dev >> 12) & ~0xff));
        }


        public static string loopfile_from_sysfs(string device)
        {
            string res = null;
            Mono.Unix.Native.Stat st;
            System.IntPtr f;

            //if (stat(device, &st) || !S_ISBLK(st.st_mode))
            //if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(device, out st)) || !S_ISBLK((int) st.st_mode))
            //  return null;

            Mono.Unix.Native.Syscall.stat(device, out st);

            const string _PATH_SYS_DEVBLOCK = "/sys/dev/block";
            string strPath = string.Format("{0}/{1}:{2}/loop/backing_file", _PATH_SYS_DEVBLOCK, gnu_dev_major(st.st_rdev), gnu_dev_minor(st.st_rdev));

            f = Mono.Unix.Native.Syscall.fopen(strPath, "r");
            if (f == IntPtr.Zero)
                return null;

            Mono.Unix.Native.Syscall.fclose(f);

            res = System.IO.File.ReadAllText(strPath);
            strPath = null;
            return res;
        } // End Function loopfile_from_sysfs


        public static string loopdev_get_loopfile(string device)
        {
            string res = loopfile_from_sysfs(device);

            if (res == null)
            {
                loop_info lo = new loop_info();
                loop_info64 lo64 = new loop_info64();

                int fd;

                if ((fd = Mono.Unix.Native.Syscall.open(device, Mono.Unix.Native.OpenFlags.O_RDONLY)) < 0)
                    return null;

                if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS64, ref lo64) == 0)
                {
                    //lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
                    //lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
                    //res = strdup((char *) lo64.lo_file_name);
                    res = lo64.lo_file_name;
                    Console.WriteLine("LOOP_GET_STATUS64");

                }
                else if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref lo) == 0)
                {
                    //lo.lo_name[LO_NAME_SIZE-2] = '*';
                    //lo.lo_name[LO_NAME_SIZE-1] = 0;
                    //res = strdup((char *) lo.lo_name);
                    res = lo.lo_name;
                    Console.WriteLine("LOOP_GET_STATUS");
                }

                Mono.Unix.Native.Syscall.close(fd);
            } // End if (res == null)

            return res;
        } // End Function loopdev_get_loopfile


        public static void TryUnmount()
        {
            /*
            string strMountPoint = "/mnt/testdisk";

            umount(strMountPoint);
            System.Threading.Thread.Sleep(1000);
            del_loop("/dev/loop2");
            */
            string xxx = loopdev_get_loopfile("/dev/loop0");
            Console.WriteLine("xxx: " + xxx);
        }

        // kernel-support:
        // grep hfs /proc/filesystems
        // cat /proc/partitions

        // apt-get install hfsprogs
        // sudo modprobe hfsplus
        // dd if=/dev/zero of=hfsplus.dsk bs=1048576 count=150
        // mkfs.hfsplus /volumes/hfsplus.dsk
        // mkfs.hfsplus hfsplus.dsk


        // apt-get install jfsutils
        // dd if=/dev/zero of=jfs.dsk bs=1048576 count=150
        // mkfs.jfs -O jfs.dsk
        // mkdir -p /mnt/jfs
        // mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop
        // umount /mnt/jfs/


        // mkdir -p /mnt/hfsplus

        // mount -t hfsplus /volumes/hfsplus.dsk /mnt/hfsplus/ -o loop

        //  
    } // End Class Linux


} // End Namespace Syscalls

// http://ubuntuforums.org/showthread.php?t=135113
// http://stackoverflow.com/questions/7027151/call-expect-script-in-c-process
// http://linux.die.net/man/1/expect
// http://linux.die.net/man/3/libexpect

// http://linuxcommand.org/man_pages/losetup8.html
// losetup /dev/loop0 /file
// losetup -d /dev/loop0

// http://linux.about.com/library/cmd/blcmdl8_losetup.htm

To perma-mount it in fstab, you need to get the partition uuid (blkid)

Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • If this is really only a *comment* to another answer, you should've put it as such, and uploaded the code on sites like http://ideone.com. – Xeo Jun 16 '12 at 09:33
  • 1
    That is a brilliant piece of code, works like a charm. It would have taken me days to do the same from scratch. By the way, is this code under a specific license? Thanks again for sharing this. – mbarthelemy Sep 01 '12 at 08:10
  • 1
    @mbarthelemy: As far as MY work is concerned, you can consider it MIT license. However, all the code I wrote is a direct rewrite of C (without sharp or ++) code that was licensed under the the GPL, and thus not really written from scratch by me. The GPL specifically covers translations to other programming languages, so the GPL license applies to pretty much all the code. Sorry for the bad news :) See here for further information: http://programmers.stackexchange.com/questions/151515/rewrote-gnu-gpl-v2-code-in-another-language-can-i-change-a-license – Stefan Steiger Sep 04 '12 at 12:35
  • Thanks a lot for your reply! In fact it's pretty good news, as the project I'm working on will be GPL (even LGPL I think). – mbarthelemy Sep 06 '12 at 12:55
4

getmntent can help you read /etc/fstab (and then use the mount function in the other answers).

Brendan Long
  • 53,280
  • 21
  • 146
  • 188