1 // -*- mode: cpp; mode: fold -*-
3 // $Id: cdromutl.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $
4 /* ######################################################################
6 CDROM Utilities - Some functions to manipulate CDROM mounts.
8 These are here for the cdrom method and apt-cdrom.
10 ##################################################################### */
12 // Include Files /*{{{*/
15 #include <apt-pkg/cdromutl.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/md5.h>
18 #include <apt-pkg/fileutl.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/strutl.h>
23 #include <sys/statvfs.h>
33 // IsMounted - Returns true if the mount point is mounted /*{{{*/
34 // ---------------------------------------------------------------------
35 /* This is a simple algorithm that should always work, we stat the mount point
36 and the '..' file in the mount point and see if they are on the same device.
37 By definition if they are the same then it is not mounted. This should
38 account for symlinked mount points as well. */
39 bool IsMounted(string
&Path
)
41 if (Path
.empty() == true)
44 // Need that trailing slash for directories
45 if (Path
[Path
.length() - 1] != '/')
48 /* First we check if the path is actualy mounted, we do this by
49 stating the path and the previous directory (carefull of links!)
50 and comparing their device fields. */
52 if (stat(Path
.c_str(),&Buf
) != 0 ||
53 stat((Path
+ "../").c_str(),&Buf2
) != 0)
54 return _error
->Errno("stat",_("Unable to stat the mount point %s"),Path
.c_str());
56 if (Buf
.st_dev
== Buf2
.st_dev
)
61 // UnmountCdrom - Unmount a cdrom /*{{{*/
62 // ---------------------------------------------------------------------
63 /* Forking umount works much better than the umount syscall which can
64 leave /etc/mtab inconsitant. We drop all messages this produces. */
65 bool UnmountCdrom(string Path
)
67 if (IsMounted(Path
) == false)
73 int Child
= ExecFork();
78 // Make all the fds /dev/null
79 for (int I
= 0; I
!= 3; I
++)
80 dup2(open("/dev/null",O_RDWR
),I
);
82 if (_config
->Exists("Acquire::cdrom::"+Path
+"::UMount") == true)
84 if (system(_config
->Find("Acquire::cdrom::"+Path
+"::UMount").c_str()) != 0)
92 Args
[1] = Path
.c_str();
94 execvp(Args
[0],(char **)Args
);
99 // if it can not be umounted, give it a bit more time
100 // this can happen when auto-mount magic or fs/cdrom prober attack
101 if (ExecWait(Child
,"umount",true) == true)
109 // MountCdrom - Mount a cdrom /*{{{*/
110 // ---------------------------------------------------------------------
111 /* We fork mount and drop all messages */
112 bool MountCdrom(string Path
, string DeviceName
)
114 if (IsMounted(Path
) == true)
117 int Child
= ExecFork();
122 // Make all the fds /dev/null
123 for (int I
= 0; I
!= 3; I
++)
124 dup2(open("/dev/null",O_RDWR
),I
);
126 if (_config
->Exists("Acquire::cdrom::"+Path
+"::Mount") == true)
128 if (system(_config
->Find("Acquire::cdrom::"+Path
+"::Mount").c_str()) != 0)
134 const char *Args
[10];
136 if (DeviceName
== "")
138 Args
[1] = Path
.c_str();
141 Args
[1] = DeviceName
.c_str();
142 Args
[2] = Path
.c_str();
145 execvp(Args
[0],(char **)Args
);
151 return ExecWait(Child
,"mount",true);
154 // IdentCdrom - Generate a unique string for this CD /*{{{*/
155 // ---------------------------------------------------------------------
156 /* We convert everything we hash into a string, this prevents byte size/order
157 from effecting the outcome. */
158 bool IdentCdrom(string CD
,string
&Res
,unsigned int Version
)
161 bool writable_media
= false;
163 // if we are on a writable medium (like a usb-stick) that is just
164 // used like a cdrom don't use "." as it will constantly change,
166 if (access(CD
.c_str(), W_OK
) == 0 && DirectoryExists(CD
+string("/.disk")))
168 writable_media
= true;
169 CD
= CD
.append("/.disk");
170 if (_config
->FindB("Debug::aptcdrom",false) == true)
171 std::clog
<< "Found writable cdrom, using alternative path: " << CD
175 string StartDir
= SafeGetCWD();
176 if (chdir(CD
.c_str()) != 0)
177 return _error
->Errno("chdir",_("Unable to change to %s"),CD
.c_str());
179 DIR *D
= opendir(".");
181 return _error
->Errno("opendir",_("Unable to read %s"),CD
.c_str());
183 /* Run over the directory, we assume that the reader order will never
184 change as the media is read-only. In theory if the kernel did
185 some sort of wacked caching this might not be true.. */
187 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
190 if (strcmp(Dir
->d_name
,".") == 0 ||
191 strcmp(Dir
->d_name
,"..") == 0)
196 sprintf(S
,"%lu",(unsigned long)Dir
->d_ino
);
201 if (stat(Dir
->d_name
,&Buf
) != 0)
203 sprintf(S
,"%lu",(unsigned long)Buf
.st_mtime
);
207 Hash
.Add(Dir
->d_name
);
210 if (chdir(StartDir
.c_str()) != 0) {
211 _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
217 // Some stats from the fsys
218 if (_config
->FindB("Debug::identcdrom",false) == false)
221 if (statvfs(CD
.c_str(),&Buf
) != 0)
222 return _error
->Errno("statfs",_("Failed to stat the cdrom"));
224 // We use a kilobyte block size to advoid overflow
227 sprintf(S
,"%lu",(long)(Buf
.f_blocks
*(Buf
.f_bsize
/1024)));
229 sprintf(S
,"%lu %lu",(long)(Buf
.f_blocks
*(Buf
.f_bsize
/1024)),
230 (long)(Buf
.f_bfree
*(Buf
.f_bsize
/1024)));
233 sprintf(S
,"-%u",Version
);
236 sprintf(S
,"-%u.debug",Version
);
238 Res
= Hash
.Result().Value() + S
;
243 // FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
244 string
FindMountPointForDevice(const char *devnode
)
250 // this is the order that mount uses as well
251 const char *mount
[] = { "/etc/mtab",
255 for (i
=0; mount
[i
] != NULL
; i
++) {
256 if (FileExists(mount
[i
])) {
257 FILE *f
=fopen(mount
[i
], "r");
258 while ( fgets(buf
, sizeof(buf
), f
) != NULL
) {
259 if (strncmp(buf
, devnode
, strlen(devnode
)) == 0) {
260 if(TokSplitString(' ', buf
, out
, 10))
263 return string(out
[1]);