at master 4.0 kB view raw
1{ pkgs, ... }: 2{ 3 name = "mtp"; 4 meta = with pkgs.lib.maintainers; { 5 maintainers = [ 6 matthewcroughan 7 nixinator 8 ]; 9 }; 10 11 nodes = { 12 client = 13 { config, pkgs, ... }: 14 { 15 # DBUS runs only once a user session is created, which means a user has to 16 # login. Here, we log in as root. Once logged in, the gvfs-daemon service runs 17 # as UID 0 in User-0.service 18 services.getty.autologinUser = "root"; 19 20 # XDG_RUNTIME_DIR is needed for running systemd-user services such as 21 # gvfs-daemon as root. 22 environment.variables.XDG_RUNTIME_DIR = "/run/user/0"; 23 24 environment.systemPackages = with pkgs; [ 25 usbutils 26 glib 27 jmtpfs 28 tree 29 ]; 30 services.gvfs.enable = true; 31 32 # Creates a usb-mtp device inside the VM, which is mapped to the host's 33 # /tmp folder, it is able to write files to this location, but only has 34 # permissions to read its own creations. 35 virtualisation.qemu.options = [ 36 "-usb" 37 "-device usb-mtp,rootdir=/tmp,readonly=false" 38 ]; 39 }; 40 }; 41 42 testScript = 43 { nodes, ... }: 44 let 45 # Creates a list of QEMU MTP devices matching USB ID (46f4:0004). This 46 # value can be sourced in a shell script. This is so we can loop over the 47 # devices we find, as this test may want to use more than one MTP device 48 # in future. 49 mtpDevices = pkgs.writeScript "mtpDevices.sh" '' 50 export mtpDevices=$(lsusb -d 46f4:0004 | awk {'print $2","$4'} | sed 's/[:-]/ /g') 51 ''; 52 # Qemu is only capable of creating an MTP device with Picture Transfer 53 # Protocol. This means that gvfs must use gphoto2:// rather than mtp:// 54 # when mounting. 55 # https://github.com/qemu/qemu/blob/970bc16f60937bcfd334f14c614bd4407c247961/hw/usb/dev-mtp.c#L278 56 gvfs = rec { 57 mountAllMtpDevices = pkgs.writeScript "mountAllMtpDevices.sh" '' 58 set -e 59 source ${mtpDevices} 60 for i in $mtpDevices 61 do 62 gio mount "gphoto2://[usb:$i]/" 63 done 64 ''; 65 unmountAllMtpDevices = pkgs.writeScript "unmountAllMtpDevices.sh" '' 66 set -e 67 source ${mtpDevices} 68 for i in $mtpDevices 69 do 70 gio mount -u "gphoto2://[usb:$i]/" 71 done 72 ''; 73 # gvfsTest: 74 # 1. Creates a 10M test file 75 # 2. Copies it to the device using GIO tools 76 # 3. Checks for corruption with `diff` 77 # 4. Removes the file, then unmounts the disks. 78 gvfsTest = pkgs.writeScript "gvfsTest.sh" '' 79 set -e 80 source ${mtpDevices} 81 ${mountAllMtpDevices} 82 dd if=/dev/urandom of=testFile10M bs=1M count=10 83 for i in $mtpDevices 84 do 85 gio copy ./testFile10M gphoto2://[usb:$i]/ 86 ls -lah /run/user/0/gvfs/*/testFile10M 87 gio remove gphoto2://[usb:$i]/testFile10M 88 done 89 ${unmountAllMtpDevices} 90 ''; 91 }; 92 jmtpfs = { 93 # jmtpfsTest: 94 # 1. Mounts the device on a dir named `phone` using jmtpfs 95 # 2. Puts the current Nixpkgs libmtp version into a file 96 # 3. Checks for corruption with `diff` 97 # 4. Prints the directory tree 98 jmtpfsTest = pkgs.writeScript "jmtpfsTest.sh" '' 99 set -e 100 mkdir phone 101 jmtpfs phone 102 echo "${pkgs.libmtp.version}" > phone/tmp/testFile 103 echo "${pkgs.libmtp.version}" > testFile 104 diff phone/tmp/testFile testFile 105 tree phone 106 ''; 107 }; 108 in 109 # Using >&2 allows the results of the scripts to be printed to the terminal 110 # when building this test with Nix. Scripts would otherwise complete 111 # silently. 112 '' 113 start_all() 114 client.wait_for_unit("multi-user.target") 115 client.wait_for_unit("dbus.service") 116 client.succeed("${gvfs.gvfsTest} >&2") 117 client.succeed("${jmtpfs.jmtpfsTest} >&2") 118 ''; 119}