]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/cdromutl.cc
merged from http://bzr.debian.org/bzr/apt/apt/debian-experimental2
[apt.git] / apt-pkg / contrib / cdromutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: cdromutl.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $
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 /*{{{*/
13 #include<config.h>
14
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>
21
22 #include <sys/wait.h>
23 #include <sys/statvfs.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdio.h>
29
30 #include <apti18n.h>
31 /*}}}*/
32
33 using std::string;
34
35 // IsMounted - Returns true if the mount point is mounted /*{{{*/
36 // ---------------------------------------------------------------------
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. */
41 bool IsMounted(string &Path)
42 {
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
50 /* First we check if the path is actualy mounted, we do this by
51 stating the path and the previous directory (carefull of links!)
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)
56 return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str());
57
58 if (Buf.st_dev == Buf2.st_dev)
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. */
67 bool UnmountCdrom(string Path)
68 {
69 if (IsMounted(Path) == false)
70 return true;
71
72 for (int i=0;i<3;i++)
73 {
74
75 int Child = ExecFork();
76
77 // The child
78 if (Child == 0)
79 {
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);
97 _exit(100);
98 }
99 }
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);
106 }
107
108 return false;
109 }
110 /*}}}*/
111 // MountCdrom - Mount a cdrom /*{{{*/
112 // ---------------------------------------------------------------------
113 /* We fork mount and drop all messages */
114 bool MountCdrom(string Path, string DeviceName)
115 {
116 if (IsMounted(Path) == true)
117 return true;
118
119 int Child = ExecFork();
120
121 // The child
122 if (Child == 0)
123 {
124 // Make all the fds /dev/null
125 for (int I = 0; I != 3; I++)
126 dup2(open("/dev/null",O_RDWR),I);
127
128 if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true)
129 {
130 if (system(_config->Find("Acquire::cdrom::"+Path+"::Mount").c_str()) != 0)
131 _exit(100);
132 _exit(0);
133 }
134 else
135 {
136 const char *Args[10];
137 Args[0] = "mount";
138 if (DeviceName == "")
139 {
140 Args[1] = Path.c_str();
141 Args[2] = 0;
142 } else {
143 Args[1] = DeviceName.c_str();
144 Args[2] = Path.c_str();
145 Args[3] = 0;
146 }
147 execvp(Args[0],(char **)Args);
148 _exit(100);
149 }
150 }
151
152 // Wait for mount
153 return ExecWait(Child,"mount",true);
154 }
155 /*}}}*/
156 // IdentCdrom - Generate a unique string for this CD /*{{{*/
157 // ---------------------------------------------------------------------
158 /* We convert everything we hash into a string, this prevents byte size/order
159 from effecting the outcome. */
160 bool IdentCdrom(string CD,string &Res,unsigned int Version)
161 {
162 MD5Summation Hash;
163 bool writable_media = false;
164
165 // if we are on a writable medium (like a usb-stick) that is just
166 // used like a cdrom don't use "." as it will constantly change,
167 // use .disk instead
168 if (access(CD.c_str(), W_OK) == 0 && DirectoryExists(CD+string("/.disk")))
169 {
170 writable_media = true;
171 CD = CD.append("/.disk");
172 if (_config->FindB("Debug::aptcdrom",false) == true)
173 std::clog << "Found writable cdrom, using alternative path: " << CD
174 << std::endl;
175 }
176
177 string StartDir = SafeGetCWD();
178 if (chdir(CD.c_str()) != 0)
179 return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str());
180
181 DIR *D = opendir(".");
182 if (D == 0)
183 return _error->Errno("opendir",_("Unable to read %s"),CD.c_str());
184
185 /* Run over the directory, we assume that the reader order will never
186 change as the media is read-only. In theory if the kernel did
187 some sort of wacked caching this might not be true.. */
188 char S[300];
189 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
190 {
191 // Skip some files..
192 if (strcmp(Dir->d_name,".") == 0 ||
193 strcmp(Dir->d_name,"..") == 0)
194 continue;
195
196 if (Version <= 1)
197 {
198 sprintf(S,"%lu",(unsigned long)Dir->d_ino);
199 }
200 else
201 {
202 struct stat Buf;
203 if (stat(Dir->d_name,&Buf) != 0)
204 continue;
205 sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
206 }
207
208 Hash.Add(S);
209 Hash.Add(Dir->d_name);
210 };
211
212 if (chdir(StartDir.c_str()) != 0) {
213 _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str());
214 closedir(D);
215 return false;
216 }
217 closedir(D);
218
219 // Some stats from the fsys
220 if (_config->FindB("Debug::identcdrom",false) == false)
221 {
222 struct statvfs Buf;
223 if (statvfs(CD.c_str(),&Buf) != 0)
224 return _error->Errno("statfs",_("Failed to stat the cdrom"));
225
226 // We use a kilobyte block size to advoid overflow
227 if (writable_media)
228 {
229 sprintf(S,"%lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)));
230 } else {
231 sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),
232 (long)(Buf.f_bfree*(Buf.f_bsize/1024)));
233 }
234 Hash.Add(S);
235 sprintf(S,"-%u",Version);
236 }
237 else
238 sprintf(S,"-%u.debug",Version);
239
240 Res = Hash.Result().Value() + S;
241 return true;
242 }
243 /*}}}*/
244
245 // FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
246 string FindMountPointForDevice(const char *devnode)
247 {
248 char buf[255];
249 char *out[10];
250 int i=0;
251
252 // this is the order that mount uses as well
253 const char *mount[] = { "/etc/mtab",
254 "/proc/mount",
255 NULL };
256
257 for (i=0; mount[i] != NULL; i++) {
258 if (FileExists(mount[i])) {
259 FILE *f=fopen(mount[i], "r");
260 while ( fgets(buf, sizeof(buf), f) != NULL) {
261 if (strncmp(buf, devnode, strlen(devnode)) == 0) {
262 if(TokSplitString(' ', buf, out, 10))
263 {
264 fclose(f);
265 // unescape the \0XXX chars in the path
266 string mount_point = out[1];
267 return DeEscapeString(mount_point);
268 }
269 }
270 }
271 fclose(f);
272 }
273 }
274
275 return string();
276 }
277 /*}}}*/