libzypp 17.35.16
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>
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
58
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 ...
int close() override
Wait for the progamm to complete.
Wrapper class for stat/lstat.
Definition PathInfo.h:222
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
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition mount.h:83
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
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:1026
Easy-to use interface to the ZYPP dependency resolver.
std::string asString(const Patch::Category &obj)
Definition Patch.cc:122
A "struct mntent" like mount entry structure, but using std::strings.
Definition mount.h:36
std::string dir
file system path prefix
Definition mount.h:57
std::string src
name of mounted file system
Definition mount.h:56
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:58
std::string opts
mount options
Definition mount.h:59
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:424
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define WAR
Definition Logger.h:101