]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/cdromutl.cc
f850e08a5ff7c7c395e9e9c70af8b9a9f41ab04b
[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 <stdlib.h>
23 #include <string.h>
24 #include <iostream>
25 #include <string>
26 #include <sys/statvfs.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <stdio.h>
32
33 #include <apti18n.h>
34 /*}}}*/
35
36 using std::string;
37
38 // IsMounted - Returns true if the mount point is mounted /*{{{*/
39 // ---------------------------------------------------------------------
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. */
44 bool IsMounted(string &Path)
45 {
46 if (Path.empty() == true)
47 return false;
48
49 // Need that trailing slash for directories
50 if (Path[Path.length() - 1] != '/')
51 Path += '/';
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
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!)
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)
64 return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str());
65
66 if (Buf.st_dev == Buf2.st_dev)
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. */
75 bool UnmountCdrom(string Path)
76 {
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)
84 return true;
85
86 for (int i=0;i<3;i++)
87 {
88
89 int Child = ExecFork();
90
91 // The child
92 if (Child == 0)
93 {
94 // Make all the fds /dev/null
95 int const null_fd = open("/dev/null",O_RDWR);
96 for (int I = 0; I != 3; ++I)
97 dup2(null_fd, I);
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);
112 _exit(100);
113 }
114 }
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);
121 }
122
123 return false;
124 }
125 /*}}}*/
126 // MountCdrom - Mount a cdrom /*{{{*/
127 // ---------------------------------------------------------------------
128 /* We fork mount and drop all messages */
129 bool MountCdrom(string Path, string DeviceName)
130 {
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)
137 return true;
138
139 int Child = ExecFork();
140
141 // The child
142 if (Child == 0)
143 {
144 // Make all the fds /dev/null
145 int const null_fd = open("/dev/null",O_RDWR);
146 for (int I = 0; I != 3; ++I)
147 dup2(null_fd, I);
148
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";
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 }
168 execvp(Args[0],(char **)Args);
169 _exit(100);
170 }
171 }
172
173 // Wait for mount
174 return ExecWait(Child,"mount",true);
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. */
181 bool IdentCdrom(string CD,string &Res,unsigned int Version)
182 {
183 MD5Summation Hash;
184 bool writable_media = false;
185
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
189 if (access(CD.c_str(), W_OK) == 0 && DirectoryExists(CD+string("/.disk")))
190 {
191 writable_media = true;
192 CD = CD.append("/.disk");
193 if (_config->FindB("Debug::aptcdrom",false) == true)
194 std::clog << "Found writable cdrom, using alternative path: " << CD
195 << std::endl;
196 }
197
198 string StartDir = SafeGetCWD();
199 if (chdir(CD.c_str()) != 0)
200 return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str());
201
202 DIR *D = opendir(".");
203 if (D == 0)
204 return _error->Errno("opendir",_("Unable to read %s"),CD.c_str());
205
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.. */
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;
216
217 if (Version <= 1)
218 {
219 sprintf(S,"%lu",(unsigned long)Dir->d_ino);
220 }
221 else
222 {
223 struct stat Buf;
224 if (stat(Dir->d_name,&Buf) != 0)
225 continue;
226 sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
227 }
228
229 Hash.Add(S);
230 Hash.Add(Dir->d_name);
231 };
232
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 }
238 closedir(D);
239
240 // Some stats from the fsys
241 if (_config->FindB("Debug::identcdrom",false) == false)
242 {
243 struct statvfs Buf;
244 if (statvfs(CD.c_str(),&Buf) != 0)
245 return _error->Errno("statfs",_("Failed to stat the cdrom"));
246
247 // We use a kilobyte block size to advoid overflow
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 }
255 Hash.Add(S);
256 sprintf(S,"-%u",Version);
257 }
258 else
259 sprintf(S,"-%u.debug",Version);
260
261 Res = Hash.Result().Value() + S;
262 return true;
263 }
264 /*}}}*/
265
266 // FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
267 string FindMountPointForDevice(const char *devnode)
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))
284 {
285 fclose(f);
286 // unescape the \0XXX chars in the path
287 string mount_point = out[1];
288 return DeEscapeString(mount_point);
289 }
290 }
291 }
292 fclose(f);
293 }
294 }
295
296 return string();
297 }
298 /*}}}*/