]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/cdromutl.cc
enable mount support for apt-cdrom in the tests
[apt.git] / apt-pkg / contrib / cdromutl.cc
CommitLineData
d669751b
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b2e465d6 3// $Id: cdromutl.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $
d669751b
AL
4/* ######################################################################
5
6 CDROM Utilities - Some functions to manipulate CDROM mounts.
7
8 These are here for the cdrom method and apt-cdrom.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
ea542140
DK
13#include<config.h>
14
d669751b
AL
15#include <apt-pkg/cdromutl.h>
16#include <apt-pkg/error.h>
17#include <apt-pkg/md5.h>
18#include <apt-pkg/fileutl.h>
6c907975 19#include <apt-pkg/configuration.h>
ef381816 20#include <apt-pkg/strutl.h>
d669751b 21
453b82a3
DK
22#include <stdlib.h>
23#include <string.h>
24#include <iostream>
25#include <string>
101030ab 26#include <sys/statvfs.h>
d669751b
AL
27#include <dirent.h>
28#include <fcntl.h>
4df0b629 29#include <sys/stat.h>
d669751b
AL
30#include <unistd.h>
31#include <stdio.h>
ea542140
DK
32
33#include <apti18n.h>
d669751b
AL
34 /*}}}*/
35
8f3ba4e8
DK
36using std::string;
37
6c907975 38// IsMounted - Returns true if the mount point is mounted /*{{{*/
d669751b 39// ---------------------------------------------------------------------
6c907975
AL
40/* This is a simple algorithm that should always work, we stat the mount point
41 and the '..' file in the mount point and see if they are on the same device.
42 By definition if they are the same then it is not mounted. This should
43 account for symlinked mount points as well. */
44bool IsMounted(string &Path)
d669751b 45{
4df0b629
AL
46 if (Path.empty() == true)
47 return false;
79bde56e 48
4df0b629
AL
49 // Need that trailing slash for directories
50 if (Path[Path.length() - 1] != '/')
51 Path += '/';
79bde56e
DK
52
53 // if the path has a ".disk" directory we treat it as mounted
54 // this way even extracted copies of disks are recognized
55 if (DirectoryExists(Path + ".disk/") == true)
56 return true;
57
1e3f4083
MV
58 /* First we check if the path is actually mounted, we do this by
59 stating the path and the previous directory (careful of links!)
4df0b629
AL
60 and comparing their device fields. */
61 struct stat Buf,Buf2;
62 if (stat(Path.c_str(),&Buf) != 0 ||
63 stat((Path + "../").c_str(),&Buf2) != 0)
b2e465d6 64 return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str());
4df0b629
AL
65
66 if (Buf.st_dev == Buf2.st_dev)
6c907975
AL
67 return false;
68 return true;
69}
70 /*}}}*/
71// UnmountCdrom - Unmount a cdrom /*{{{*/
72// ---------------------------------------------------------------------
73/* Forking umount works much better than the umount syscall which can
74 leave /etc/mtab inconsitant. We drop all messages this produces. */
75bool UnmountCdrom(string Path)
76{
454b97a5
DK
77 // do not generate errors, even if the mountpoint does not exist
78 // the mountpoint might be auto-created by the mount command
79 // and a non-existing mountpoint is surely not mounted
80 _error->PushToStack();
81 bool const mounted = IsMounted(Path);
82 _error->RevertToStack();
83 if (mounted == false)
4df0b629 84 return true;
d669751b 85
5ae004ce 86 for (int i=0;i<3;i++)
d669751b 87 {
5ae004ce
MV
88
89 int Child = ExecFork();
d669751b 90
5ae004ce
MV
91 // The child
92 if (Child == 0)
6c907975 93 {
5ae004ce 94 // Make all the fds /dev/null
454b97a5
DK
95 int const null_fd = open("/dev/null",O_RDWR);
96 for (int I = 0; I != 3; ++I)
97 dup2(null_fd, I);
5ae004ce
MV
98
99 if (_config->Exists("Acquire::cdrom::"+Path+"::UMount") == true)
100 {
101 if (system(_config->Find("Acquire::cdrom::"+Path+"::UMount").c_str()) != 0)
102 _exit(100);
103 _exit(0);
104 }
105 else
106 {
107 const char *Args[10];
108 Args[0] = "umount";
109 Args[1] = Path.c_str();
110 Args[2] = 0;
111 execvp(Args[0],(char **)Args);
6c907975 112 _exit(100);
5ae004ce 113 }
6c907975 114 }
5ae004ce
MV
115
116 // if it can not be umounted, give it a bit more time
117 // this can happen when auto-mount magic or fs/cdrom prober attack
118 if (ExecWait(Child,"umount",true) == true)
119 return true;
120 sleep(1);
d669751b
AL
121 }
122
5ae004ce 123 return false;
d669751b
AL
124}
125 /*}}}*/
126// MountCdrom - Mount a cdrom /*{{{*/
127// ---------------------------------------------------------------------
128/* We fork mount and drop all messages */
a6418a4b 129bool MountCdrom(string Path, string DeviceName)
d669751b 130{
454b97a5
DK
131 // do not generate errors, even if the mountpoint does not exist
132 // the mountpoint might be auto-created by the mount command
133 _error->PushToStack();
134 bool const mounted = IsMounted(Path);
135 _error->RevertToStack();
136 if (mounted == true)
6c907975 137 return true;
454b97a5 138
54676e1a 139 int Child = ExecFork();
d669751b
AL
140
141 // The child
142 if (Child == 0)
143 {
144 // Make all the fds /dev/null
454b97a5
DK
145 int const null_fd = open("/dev/null",O_RDWR);
146 for (int I = 0; I != 3; ++I)
fe0036dd 147 dup2(null_fd, I);
454b97a5 148
6c907975
AL
149 if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true)
150 {
151 if (system(_config->Find("Acquire::cdrom::"+Path+"::Mount").c_str()) != 0)
152 _exit(100);
153 _exit(0);
154 }
155 else
156 {
157 const char *Args[10];
158 Args[0] = "mount";
a6418a4b
MV
159 if (DeviceName == "")
160 {
161 Args[1] = Path.c_str();
162 Args[2] = 0;
163 } else {
164 Args[1] = DeviceName.c_str();
165 Args[2] = Path.c_str();
166 Args[3] = 0;
167 }
6c907975
AL
168 execvp(Args[0],(char **)Args);
169 _exit(100);
170 }
d669751b
AL
171 }
172
173 // Wait for mount
ddc1d8d0 174 return ExecWait(Child,"mount",true);
d669751b
AL
175}
176 /*}}}*/
177// IdentCdrom - Generate a unique string for this CD /*{{{*/
178// ---------------------------------------------------------------------
179/* We convert everything we hash into a string, this prevents byte size/order
180 from effecting the outcome. */
34fc0421 181bool IdentCdrom(string CD,string &Res,unsigned int Version)
d669751b
AL
182{
183 MD5Summation Hash;
4dc7b4a7 184 bool writable_media = false;
d669751b 185
2a001232
MV
186 // if we are on a writable medium (like a usb-stick) that is just
187 // used like a cdrom don't use "." as it will constantly change,
188 // use .disk instead
4dc7b4a7
MV
189 if (access(CD.c_str(), W_OK) == 0 && DirectoryExists(CD+string("/.disk")))
190 {
191 writable_media = true;
7970157f 192 CD = CD.append("/.disk");
2a001232 193 if (_config->FindB("Debug::aptcdrom",false) == true)
7970157f
MV
194 std::clog << "Found writable cdrom, using alternative path: " << CD
195 << std::endl;
2a001232
MV
196 }
197
d669751b
AL
198 string StartDir = SafeGetCWD();
199 if (chdir(CD.c_str()) != 0)
b2e465d6 200 return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str());
d669751b
AL
201
202 DIR *D = opendir(".");
203 if (D == 0)
b2e465d6 204 return _error->Errno("opendir",_("Unable to read %s"),CD.c_str());
d669751b 205
4df0b629
AL
206 /* Run over the directory, we assume that the reader order will never
207 change as the media is read-only. In theory if the kernel did
208 some sort of wacked caching this might not be true.. */
d669751b
AL
209 char S[300];
210 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
211 {
212 // Skip some files..
213 if (strcmp(Dir->d_name,".") == 0 ||
214 strcmp(Dir->d_name,"..") == 0)
215 continue;
34fc0421
AL
216
217 if (Version <= 1)
218 {
0f297e46 219 sprintf(S,"%lu",(unsigned long)Dir->d_ino);
34fc0421
AL
220 }
221 else
222 {
223 struct stat Buf;
224 if (stat(Dir->d_name,&Buf) != 0)
225 continue;
1ae93c94 226 sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
34fc0421
AL
227 }
228
d669751b
AL
229 Hash.Add(S);
230 Hash.Add(Dir->d_name);
231 };
232
6070a346
DK
233 if (chdir(StartDir.c_str()) != 0) {
234 _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str());
235 closedir(D);
236 return false;
237 }
d669751b
AL
238 closedir(D);
239
240 // Some stats from the fsys
fbdccabb
AL
241 if (_config->FindB("Debug::identcdrom",false) == false)
242 {
101030ab
AL
243 struct statvfs Buf;
244 if (statvfs(CD.c_str(),&Buf) != 0)
b2e465d6 245 return _error->Errno("statfs",_("Failed to stat the cdrom"));
4dc7b4a7 246
fbdccabb 247 // We use a kilobyte block size to advoid overflow
4dc7b4a7
MV
248 if (writable_media)
249 {
250 sprintf(S,"%lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)));
251 } else {
252 sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),
253 (long)(Buf.f_bfree*(Buf.f_bsize/1024)));
254 }
fbdccabb
AL
255 Hash.Add(S);
256 sprintf(S,"-%u",Version);
257 }
258 else
259 sprintf(S,"-%u.debug",Version);
d669751b 260
34fc0421 261 Res = Hash.Result().Value() + S;
d669751b
AL
262 return true;
263}
264 /*}}}*/
ef381816 265
6070a346 266// FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
02aa6f67 267string FindMountPointForDevice(const char *devnode)
ef381816
MV
268{
269 char buf[255];
270 char *out[10];
271 int i=0;
272
273 // this is the order that mount uses as well
274 const char *mount[] = { "/etc/mtab",
275 "/proc/mount",
276 NULL };
277
278 for (i=0; mount[i] != NULL; i++) {
279 if (FileExists(mount[i])) {
280 FILE *f=fopen(mount[i], "r");
281 while ( fgets(buf, sizeof(buf), f) != NULL) {
282 if (strncmp(buf, devnode, strlen(devnode)) == 0) {
283 if(TokSplitString(' ', buf, out, 10))
6070a346
DK
284 {
285 fclose(f);
a513ace2 286 // unescape the \0XXX chars in the path
f748b476 287 string mount_point = out[1];
a513ace2 288 return DeEscapeString(mount_point);
6070a346 289 }
ef381816
MV
290 }
291 }
292 fclose(f);
293 }
294 }
295
02aa6f67 296 return string();
ef381816 297}
6070a346 298 /*}}}*/