45

I'm sure this is a easy question, my Google-fu is obviously failing me.

How do I mount a filesystem using Python, the equivalent of running the shell command mount ...?

Obviously I can use os.system to run the shell command, but surely there is a nice tidy, Python interface to the mount system call.

I can't find it. I thought it would just be a nice, easy os.mount().

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
jjh
  • 1,410
  • 2
  • 13
  • 13
  • Old question, but for future adventures. Take a look at [mount.py](https://github.com/MrVallentin/mount.py) – vallentin Mar 27 '16 at 09:04

10 Answers10

63

As others have pointed out, there is no built-in mount function. However, it is easy to create one using ctypes, and this is a bit lighter weight and more reliable than using a shell command.

Here's an example:

import ctypes
import ctypes.util
import os

libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)

def mount(source, target, fs, options=''):
  ret = libc.mount(source.encode(), target.encode(), fs.encode(), 0, options.encode())
  if ret < 0:
    errno = ctypes.get_errno()
    raise OSError(errno, f"Error mounting {source} ({fs}) on {target} with options '{options}': {os.strerror(errno)}")

mount('/dev/sdb1', '/mnt', 'ext4', 'rw')
elboulangero
  • 818
  • 9
  • 18
Paul Donohue
  • 1,121
  • 9
  • 9
  • 4
    There's no need to instantiate `CDLL` and increment the reference count on the libc shared library every time this function is called. Also, it's a good practice to define the function prototype, so ctypes can type-check the arguments. For example, at module level, `import ctypes, ctypes.util` and `libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)` and `libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)`. Also, raising `OSError(errno, errmsg)` with the custom error message would be more idiomatic than `RuntimeError`. – Eryk Sun Mar 18 '18 at 18:28
  • 1
    Great answer! Note that in Python 3, you have to use `libc.mount(source.encode(), target.encode(), fs.encode(), 0, options.encode())` since the definition for `ctypes.c_char_p` has changed. – Frederik Aalund Mar 11 '19 at 09:09
  • If you're trying to use this code on a loop device, you might end up with *"No such device"*, most likely because the `losetup` device doesn't really behave the same way as physical drives does. – Torxed Jul 06 '20 at 14:30
  • Works perfect on a Raspberry Pi 4 ! – Marus Gradinaru Apr 24 '23 at 15:04
23

Another option would be to use the fairly new sh module. According to its documentation it provides fluent integration with Shell commands from within Python.

I am trying it out now and it looks very promising.

from sh import mount

mount("/dev/", "/mnt/test", "-t ext4")

Also take a look at baking, which allows you to quickly abstract away commands in new functions.

samvv
  • 1,934
  • 1
  • 18
  • 26
  • 4
    Please commment why this answer doesn't answer the question if you downvote it. Thank you. – samvv Feb 22 '16 at 15:08
  • 1
    I found this more useful than the ctypes answer, which gives inscrutible errors if you get the arguments wrong. In my case the arguments needed were `sh.mount('/dev/xvdf1', target_dir, "-text4")`. Note the last argument has no space. – nicb Aug 19 '17 at 01:35
  • 2
    The OP doesn't want to run `os.system`. The OP did not state that he didn't want to run the `mount` command. The OP wants "nice tidy" interface so `sh.mount()` does qualify. – shrewmouse Mar 25 '21 at 18:58
  • Been a while since I answered this but I believe I assumed @shrewmouse's reasoning when I answered this. – samvv Mar 25 '21 at 19:18
15

You can use Python bindings for libmount from util-linux project:

import pylibmount as mnt

cxt = mnt.Context()
cxt.source = '/dev/sda1'
cxt.target = '/mnt/'
cxt.mount()

For more information see this example.

yegorich
  • 4,653
  • 3
  • 31
  • 37
  • 2
    But where to import pylibmount from? – Wtower Feb 02 '17 at 10:51
  • 2
    @Wtower It depends on what Linux distro you're using. If you're using Fedora then it is [python3-libmount](https://apps.fedoraproject.org/packages/python3-libmount/) package. AFAIK Debian doesn't package Python bindings for libmount, so you'll have to compile/install it yourself. – yegorich Feb 02 '17 at 14:12
11

Import cdll from ctypes. Then load your os libc, then use libc.mount()

Read libc's docs for mount parameters

Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
marianov
  • 875
  • 1
  • 9
  • 19
4

Mounting is a pretty rare operation, so it's doubtful that there is any direct python way to do it.

Either use ctypes to do the operation directly from python, or else (and probably better), use subprocess to call the mount command (don't use os.system() - much better to use subprocess).

Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
4

As others have stated, a direct access to the syscall will not help you, unless you're running as root (which is generally bad, for many reasons). Thus, it is best to call out to the "mount" program, and hope that /etc/fstab has enabled mounts for users.

The best way to invoke mount is with the following:

subprocess.check_call(["mount", what])

where what is either the device path, or the mountpoint path. If any problems arise, then an exception will be raised.

(check_call is an easier interface than Popen and its low-level brethren)

gstein
  • 306
  • 2
  • 5
  • No it's not better to call a process. It's much more error prone. – LtWorf Sep 10 '15 at 14:10
  • 2
    @LtWorf how so? What errors are more likely with calling a process? As a kernal-non-expert, like most users, I find it difficult to predict what's likely to fail and what's not. – Stefan Aug 01 '16 at 14:21
  • You don't need to be a kernel expert to do a system call. And tools sometimes change parameters, while system calls always remain the same. – LtWorf Aug 03 '16 at 12:46
  • 1
    Using the syscall requires root privileges. Running Python programs as root is (IMO) never to be encouraged. By using the setuid /bin/mount program, your Python program can run with non-root privs. Also note that the mount program is incredibly lightweight ... it isn't like we're spawning a JVM subprocess. – gstein Oct 06 '16 at 06:58
  • Further, the code is much more legible/maintainable, and it requires no custom Python modules to be installed. – gstein Oct 06 '16 at 06:59
  • Doesn't this require sudo? – Magnus Aug 10 '20 at 16:40
3

Note that calling your libc mount function will require root privileges; Popen(['mount'...) only will if the particular mounting isn't blessed in fstab (it is the mount executable, setuid root, that performs these checks).

David
  • 31
  • 1
1

I know this is old but I had a similar issue and pexpect solved it. I could mount my Windows shared drive using the mount command but I couldn't pass my password in because it had to be escaped. I grew tired of escaping it and tried to use a credentials file which also caused issues. This seems to work for me.

password = "$wirleysaysneverquit!!!"

cmd = "sudo mount -t cifs -o username=myusername,domain=CORPORATE,rw,hard,nosetuids,noperm,sec=ntlm //mylong.evenlonger.shareddrivecompany.com/some/folder /mnt/folder -v"
p = pexpect.spawn( cmd )
p.expect( ": " )
print( p.before + p.after + password )
p.sendline( password )
p.expect( "\r\n" )

output = p.read()
arroutput = output.split("\r\n")
for o in arroutput:
    print( o )

Source: https://gist.github.com/nitrocode/192d5667ce9da67c8eac

SomeGuyOnAComputer
  • 5,414
  • 6
  • 40
  • 72
0

Badly, mounting and unmounting belongs to the things that are highly system dependent and since they are

  • rarely used and
  • can affect system stability

There is no solution that is portable available. Since that, I agree with Ferdinand Beyer, that it is unlikely, a general Python solution is existing.

Juergen
  • 12,378
  • 7
  • 39
  • 55
-16

surely this is a nice tidy, python interface to the mount system call.

I can't find it (I thought it would just be a nice, easy os.mount()).

Surely, there is none. What would this function do on Windows?

Use the shell command instead.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • 6
    it's also possible to umount/mount a partition on windows – Jamol Nov 03 '09 at 13:20
  • 23
    @Ferdinand `What would this function do on Windows?` Actually, Python has quite a few platform-specific modules (_winreg, msilib, msvcrt, posix, maxostools, ...), also some common functions behave differently on some platforms like `subprocess.Popen(..., shell=False)` for example. So this is not a criterion to exclude that option. – RedGlyph Nov 03 '09 at 13:24
  • 1
    It's better to use the libc mount function. – LtWorf Feb 11 '13 at 17:26
  • 20
    *What would this function do on Windows?* I don't agree with this reasoning. What do e.g. `os.symlink()`, `os.mkfifo()` and `oc.chmod()` and many other unix-only functions from `os` do on Windows? – Alois Mahdal Jul 20 '13 at 21:32
  • 3
    Actually, NTFS _does_ support mount points: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365733%28v=vs.85%29.aspx – Tobias Kienzler Nov 18 '14 at 12:02
  • 2
    python has `os.fork()` that doesn't work on windows. – LtWorf Sep 10 '15 at 14:10
  • 1
    "Availability" is a standard attribute on Python's stdlib documentation saying in which OS's a function or class is available or not. And besides that, nothing in the question implies that the feature should be on the stdlib - it could be a 3rd party package, and of course one is free to do OS dependant 3rd party packages. – jsbueno Feb 11 '17 at 06:44
  • This won't work if you aren't running as root, even if you have cap_sys_admin. – Omnifarious Jan 25 '18 at 01:27