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