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