1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "PosixMountProvider.h"
10 
11 #include "utils/RegExp.h"
12 #include "utils/URIUtils.h"
13 #include "utils/log.h"
14 
15 #include <cstdlib>
16 
CPosixMountProvider()17 CPosixMountProvider::CPosixMountProvider()
18 {
19   m_removableLength = 0;
20   PumpDriveChangeEvents(NULL);
21 }
22 
Initialize()23 void CPosixMountProvider::Initialize()
24 {
25   CLog::Log(LOGDEBUG, "Selected Posix mount as storage provider");
26 }
27 
GetDrives(VECSOURCES & drives)28 void CPosixMountProvider::GetDrives(VECSOURCES &drives)
29 {
30   std::vector<std::string> result;
31 
32   CRegExp reMount;
33 #if defined(TARGET_DARWIN) || (defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY))
34   reMount.RegComp("on (.+) \\(([^,]+)");
35 #else
36   reMount.RegComp("on (.+) type ([^ ]+)");
37 #endif
38   char line[1024];
39 
40   FILE* pipe = popen("mount", "r");
41 
42   if (pipe)
43   {
44     while (fgets(line, sizeof(line) - 1, pipe))
45     {
46       if (reMount.RegFind(line) != -1)
47       {
48         bool accepted = false;
49         std::string mountStr = reMount.GetReplaceString("\\1");
50         std::string fsStr    = reMount.GetReplaceString("\\2");
51         const char* mount = mountStr.c_str();
52         const char* fs    = fsStr.c_str();
53 
54         // Here we choose which filesystems are approved
55         if (strcmp(fs, "fuseblk") == 0 || strcmp(fs, "vfat") == 0
56             || strcmp(fs, "ext2") == 0 || strcmp(fs, "ext3") == 0
57             || strcmp(fs, "reiserfs") == 0 || strcmp(fs, "xfs") == 0
58             || strcmp(fs, "ntfs-3g") == 0 || strcmp(fs, "iso9660") == 0
59             || strcmp(fs, "exfat") == 0
60             || strcmp(fs, "fusefs") == 0 || strcmp(fs, "hfs") == 0)
61           accepted = true;
62 
63         // Ignore root
64         if (strcmp(mount, "/") == 0)
65           accepted = false;
66 
67         if(accepted)
68           result.emplace_back(mount);
69       }
70     }
71     pclose(pipe);
72   }
73 
74   for (unsigned int i = 0; i < result.size(); i++)
75   {
76     CMediaSource share;
77     share.strPath = result[i];
78     share.strName = URIUtils::GetFileName(result[i]);
79     share.m_ignore = true;
80     drives.push_back(share);
81   }
82 }
83 
GetDiskUsage()84 std::vector<std::string> CPosixMountProvider::GetDiskUsage()
85 {
86   std::vector<std::string> result;
87   char line[1024];
88 
89 #if defined(TARGET_DARWIN)
90   FILE* pipe = popen("df -hT ufs,cd9660,hfs,udf", "r");
91 #elif (defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY))
92   FILE* pipe = popen("df -h -t ufs,cd9660,hfs,udf,zfs", "r");
93 #else
94   FILE* pipe = popen("df -h", "r");
95 #endif
96 
97   static const char* excludes[] = {"rootfs","devtmpfs","tmpfs","none","/dev/loop", "udev", NULL};
98 
99   if (pipe)
100   {
101     while (fgets(line, sizeof(line) - 1, pipe))
102     {
103       bool ok=true;
104       for (int i=0;excludes[i];++i)
105       {
106         if (strstr(line,excludes[i]))
107         {
108           ok=false;
109           break;
110         }
111       }
112       if (ok)
113         result.emplace_back(line);
114     }
115     pclose(pipe);
116   }
117 
118   return result;
119 }
120 
Eject(const std::string & mountpath)121 bool CPosixMountProvider::Eject(const std::string& mountpath)
122 {
123 
124 #if !defined(TARGET_DARWIN_EMBEDDED)
125   // just go ahead and try to umount the disk
126   // if it does umount, life is good, if not, no loss.
127   std::string cmd = "umount \"" + mountpath + "\"";
128   int status = system(cmd.c_str());
129 
130   if (status == 0)
131     return true;
132 #endif
133 
134   return false;
135 }
136 
PumpDriveChangeEvents(IStorageEventsCallback * callback)137 bool CPosixMountProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
138 {
139   VECSOURCES drives;
140   GetRemovableDrives(drives);
141   bool changed = drives.size() != m_removableLength;
142   m_removableLength = drives.size();
143   return changed;
144 }
145