libzypp 17.31.23
mount.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
13#include <mntent.h>
14
15#include <cstdio>
16#include <climits>
17#include <cerrno>
18
19#include <iostream>
20#include <fstream>
21#include <string>
22
23#include <zypp-media/Mount>
24#include <zypp/base/ExternalDataSource.h>
25#include <zypp/base/Logger.h>
26#include <zypp-media/MediaException>
27
28#include <zypp/PathInfo.h>
29
30using std::endl;
31
32#ifndef N_
33#define N_(STR) STR
34#endif
35
36
37namespace zypp {
38 namespace media {
39
40 std::ostream & operator<<( std::ostream & str, const MountEntry & obj )
41 {
42 str << obj.src << " on " << obj.dir << " type " << obj.type;
43 if ( ! obj.opts.empty() )
44 str << " (" << obj.opts << ")";
45 return str;
46 }
47
48
49
51{
52 PathInfo dev_info;
53 return ( str::hasPrefix( Pathname(src).asString(), "/dev/" ) && dev_info(src) && dev_info.isBlk() );
54}
55
57{}
58
60{}
61
62void Mount::mount( const std::string & source,
63 const std::string & target,
64 const std::string & filesystem,
65 const std::string & options,
66 const Environment & environment )
67{
68 const char *const argv[] = {
69 "/bin/mount",
70 "-t", filesystem.c_str(),
71 "-o", options.c_str(),
72 source.c_str(),
73 target.c_str(),
74 NULL
75 };
76
77 std::string err; // Error summary
78 std::string value; // legacy: Exception collects just the last output line
79 ExternalProgram prog { argv, environment, ExternalProgram::Stderr_To_Stdout, false, -1, true };
80 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() ) {
81 output[output.size()-1] = '\0'; // clip tailing NL
82 value = std::move( output );
83 DBG << "stdout: " << value << endl;
84
85 if ( value.find( "is already mounted on" ) != std::string::npos ) {
86 err = "Media already mounted";
87 }
88 else if ( value.find( "ermission denied" ) != std::string::npos ) {
89 err = "Permission denied";
90 }
91 else if ( value.find( "wrong fs type" ) != std::string::npos ) {
92 err = "Invalid filesystem on media";
93 }
94 else if ( value.find( "No medium found" ) != std::string::npos ) {
95 err = "No medium found";
96 }
97 else if ( value.find( "Not a directory" ) != std::string::npos ) {
98 if ( filesystem == "nfs" || filesystem == "nfs4" ) {
99 err = "NFS path is not a directory";
100 }
101 else {
102 err = "Unable to find directory on the media";
103 }
104 }
105 }
106 int exitCode = prog.close();
107
108 if ( exitCode != 0 ) {
109 if ( err.empty() ) err = "Mounting media failed";
110 WAR << "mount " << source << " " << target << ": " << exitCode << ": " << err << endl;
111 ZYPP_THROW(MediaMountException(err, source, target, value));
112 }
113 else
114 MIL << "mounted " << source << " " << target << endl;
115}
116
117void Mount::umount( const std::string & path )
118{
119 const char *const argv[] = {
120 "/bin/umount",
121 path.c_str(),
122 NULL
123 };
124
125 std::string err; // Error summary
126 int exitCode = -1;
127
128 bool doRetry = false;
129 unsigned numRetry = 2;
130 do {
131 if ( doRetry ) {
132 if ( numRetry-- ) {
133 WAR << "umount " << path << ": " << exitCode << ": " << err << " - retrying in 1 sec." << endl;
134 sleep( 1 );
135 err.clear();
136 doRetry = false;
137 }
138 else {
139 WAR << "umount " << path << ": " << exitCode << ": " << err << " - giving up" << endl;
140 break;
141 }
142 }
143
144 ExternalProgram prog { argv, ExternalProgram::Stderr_To_Stdout, false, -1, true };
145 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() ) {
146 output.pop_back(); // clip tailing NL
147 DBG << "stdout: " << output << endl;
148
149 if ( output.find ( " is busy" ) != std::string::npos ) { // 'device|target is busy'
150 err = "Device is busy";
151 doRetry = true;
152 }
153 }
154 exitCode = prog.close();
155
156 } while( exitCode != 0 && doRetry );
157
158 if ( exitCode != 0 ) {
159 if ( err.empty() ) err = "Unmounting media failed";
160 WAR << "umount " << path << ": " << exitCode << ": " << err << endl;
162 }
163 else
164 MIL << "unmounted " << path << endl;
165}
166
167// STATIC
168MountEntries
169Mount::getEntries(const std::string &mtab)
170{
171 MountEntries entries;
172 std::vector<std::string> mtabs;
173 bool verbose = false;
174
175 if( mtab.empty())
176 {
177 mtabs.push_back("/proc/mounts");
178 // Also read /etc/mtab if it is a file (on newer sytems
179 // mtab is a symlink to /proc/mounts).
180 // Reason for this is the different representation of
181 // mounted loop devices:
182 // /etc/mtab: /tmp/SLES-11-SP2-MINI-ISO-x86_64-Beta2-DVD.iso on /mnt type iso9660 (ro,loop=/dev/loop0)
183 // /proc/mounts: /dev/loop0 /mnt iso9660 ro,relatime 0 0
184 if ( PathInfo( "/etc/mtab", PathInfo::LSTAT ).isFile() )
185 mtabs.push_back("/etc/mtab");
186 }
187 else
188 {
189 mtabs.push_back(mtab);
190 }
191
192 std::vector<std::string>::const_iterator t;
193 for( t=mtabs.begin(); t != mtabs.end(); ++t)
194 {
195 if( verbose)
196 {
197 DBG << "Reading mount table from '" << *t << "'" << std::endl;
198 }
199 FILE *fp = setmntent(t->c_str(), "re");
200 if( fp)
201 {
202 char buf[PATH_MAX * 4];
203 struct mntent ent;
204
205 memset(buf, 0, sizeof(buf));
206 memset(&ent, 0, sizeof(ent));
207
208 while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL)
209 {
210 if( ent.mnt_fsname && *ent.mnt_fsname &&
211 ent.mnt_dir && *ent.mnt_dir &&
212 ent.mnt_type && *ent.mnt_type &&
213 ent.mnt_opts && *ent.mnt_opts)
214 {
215 MountEntry entry(
216 ent.mnt_fsname, ent.mnt_dir,
217 ent.mnt_type, ent.mnt_opts,
218 ent.mnt_freq, ent.mnt_passno
219 );
220
221 // Attempt quick fix for bnc#710269:
222 // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de"
223 // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)"
224 // Kick the trailing '/' in "//dist/install/"
225 // TODO: Check and fix comparison in MediaHandler::checkAttached instead.
226 if ( entry.src.size() > 1 // not for "/"
227 && entry.src[entry.src.size()-1] == '/' )
228 {
229 entry.src.erase( entry.src.size()-1 );
230 }
231 entries.push_back(entry);
232
233 memset(buf, 0, sizeof(buf));
234 memset(&ent, 0, sizeof(ent));
235 }
236 }
237 endmntent(fp);
238
239 if( entries.empty())
240 {
241 WAR << "Unable to read any entry from the mount table '" << *t << "'"
242 << std::endl;
243 }
244 else
245 {
246 // OK, have a non-empty mount table.
247 t = mtabs.end();
248 break;
249 }
250 }
251 else
252 {
253 int err = errno;
254 verbose = true;
255 WAR << "Failed to read the mount table '" << *t << "': "
256 << ::strerror(err)
257 << std::endl;
258 errno = err;
259 }
260 }
261 return entries;
262}
263
265{
266 time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
267 if( mtime <= 0)
268 {
269 WAR << "Failed to retrieve modification time of '/etc/mtab'"
270 << std::endl;
271 }
272 return mtime;
273}
274
275 } // namespace media
276} // namespace zypp
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
Wrapper class for stat/lstat.
Definition: PathInfo.h:221
time_t mtime() const
Definition: PathInfo.h:376
void umount(const std::string &path)
umount device
Definition: mount.cc:117
static MountEntries getEntries(const std::string &mtab="")
Return mount entries from /etc/mtab or /etc/fstab file.
Definition: mount.cc:169
static time_t getMTime()
Get the modification time of the /etc/mtab file.
Definition: mount.cc:264
void mount(const std::string &source, const std::string &target, const std::string &filesystem, const std::string &options, const Environment &environment=Environment())
mount device
Definition: mount.cc:62
~Mount()
Clean up.
Definition: mount.cc:59
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition: mount.h:82
Mount()
Create an new instance.
Definition: mount.cc:56
String related utilities and Regular expression matching.
std::ostream & operator<<(std::ostream &str, const MediaHandler &obj)
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1027
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
A "struct mntent" like mount entry structure, but using std::strings.
Definition: mount.h:35
std::string dir
file system path prefix
Definition: mount.h:56
std::string src
name of mounted file system
Definition: mount.h:55
bool isBlockDevice() const
Returns true if the src part points to a block device in /dev.
Definition: mount.cc:50
std::string type
filesystem / mount type
Definition: mount.h:57
std::string opts
mount options
Definition: mount.h:58
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define WAR
Definition: Logger.h:97