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