use free() instead of delete() when realloc is used
[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 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 char S[300];
211 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
212 {
213 // Skip some files..
214 if (strcmp(Dir->d_name,".") == 0 ||
215 strcmp(Dir->d_name,"..") == 0)
216 continue;
34fc0421
AL
217
218 if (Version <= 1)
219 {
0f297e46 220 sprintf(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;
1ae93c94 227 sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
34fc0421
AL
228 }
229
d669751b
AL
230 Hash.Add(S);
231 Hash.Add(Dir->d_name);
232 };
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
AL
239 closedir(D);
240
241 // Some stats from the fsys
fbdccabb
AL
242 if (_config->FindB("Debug::identcdrom",false) == false)
243 {
101030ab
AL
244 struct statvfs Buf;
245 if (statvfs(CD.c_str(),&Buf) != 0)
b2e465d6 246 return _error->Errno("statfs",_("Failed to stat the cdrom"));
4dc7b4a7 247
fbdccabb 248 // We use a kilobyte block size to advoid overflow
4dc7b4a7
MV
249 if (writable_media)
250 {
251 sprintf(S,"%lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)));
252 } else {
253 sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),
254 (long)(Buf.f_bfree*(Buf.f_bsize/1024)));
255 }
fbdccabb
AL
256 Hash.Add(S);
257 sprintf(S,"-%u",Version);
258 }
259 else
260 sprintf(S,"-%u.debug",Version);
d669751b 261
34fc0421 262 Res = Hash.Result().Value() + S;
d669751b
AL
263 return true;
264}
265 /*}}}*/
6070a346 266// FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
02aa6f67 267string FindMountPointForDevice(const char *devnode)
ef381816 268{
ef381816 269 // this is the order that mount uses as well
12844170 270 std::vector<std::string> const mounts = _config->FindVector("Dir::state::MountPoints", "/etc/mtab,/proc/mount");
ef381816 271
12844170
DK
272 for (std::vector<std::string>::const_iterator m = mounts.begin(); m != mounts.end(); ++m)
273 if (FileExists(*m) == true)
274 {
275 char * line = NULL;
276 size_t line_len = 0;
277 FILE * f = fopen(m->c_str(), "r");
278 while(getline(&line, &line_len, f) != -1)
279 {
280 char * out[] = { NULL, NULL, NULL };
281 TokSplitString(' ', line, out, 3);
282 if (out[2] != NULL || out[1] == NULL || out[0] == NULL)
283 continue;
284 if (strcmp(out[0], devnode) != 0)
285 continue;
286 fclose(f);
287 // unescape the \0XXX chars in the path
288 string mount_point = out[1];
289 return DeEscapeString(mount_point);
290 }
291 fclose(f);
ef381816 292 }
12844170 293
02aa6f67 294 return string();
ef381816 295}
6070a346 296 /*}}}*/