- Clean up some string handling, patch from Peter Lundkvist
[ntk/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 #ifdef __GNUG__
14 #pragma implementation "apt-pkg/cdromutl.h"
15 #endif
16 #include <apt-pkg/cdromutl.h>
17 #include <apt-pkg/error.h>
18 #include <apt-pkg/md5.h>
19 #include <apt-pkg/fileutl.h>
20 #include <apt-pkg/configuration.h>
21
22 #include <apti18n.h>
23
24 #include <sys/wait.h>
25 #include <sys/errno.h>
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
34 // IsMounted - Returns true if the mount point is mounted /*{{{*/
35 // ---------------------------------------------------------------------
36 /* This is a simple algorithm that should always work, we stat the mount point
37 and the '..' file in the mount point and see if they are on the same device.
38 By definition if they are the same then it is not mounted. This should
39 account for symlinked mount points as well. */
40 bool IsMounted(string &Path)
41 {
42 if (Path.empty() == true)
43 return false;
44
45 // Need that trailing slash for directories
46 if (Path[Path.length() - 1] != '/')
47 Path += '/';
48
49 /* First we check if the path is actualy mounted, we do this by
50 stating the path and the previous directory (carefull of links!)
51 and comparing their device fields. */
52 struct stat Buf,Buf2;
53 if (stat(Path.c_str(),&Buf) != 0 ||
54 stat((Path + "../").c_str(),&Buf2) != 0)
55 return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str());
56
57 if (Buf.st_dev == Buf2.st_dev)
58 return false;
59 return true;
60 }
61 /*}}}*/
62 // UnmountCdrom - Unmount a cdrom /*{{{*/
63 // ---------------------------------------------------------------------
64 /* Forking umount works much better than the umount syscall which can
65 leave /etc/mtab inconsitant. We drop all messages this produces. */
66 bool UnmountCdrom(string Path)
67 {
68 if (IsMounted(Path) == false)
69 return true;
70
71 int Child = ExecFork();
72
73 // The child
74 if (Child == 0)
75 {
76 // Make all the fds /dev/null
77 for (int I = 0; I != 3; I++)
78 dup2(open("/dev/null",O_RDWR),I);
79
80 if (_config->Exists("Acquire::cdrom::"+Path+"::UMount") == true)
81 {
82 if (system(_config->Find("Acquire::cdrom::"+Path+"::UMount").c_str()) != 0)
83 _exit(100);
84 _exit(0);
85 }
86 else
87 {
88 const char *Args[10];
89 Args[0] = "umount";
90 Args[1] = Path.c_str();
91 Args[2] = 0;
92 execvp(Args[0],(char **)Args);
93 _exit(100);
94 }
95 }
96
97 // Wait for mount
98 return ExecWait(Child,"umount",true);
99 }
100 /*}}}*/
101 // MountCdrom - Mount a cdrom /*{{{*/
102 // ---------------------------------------------------------------------
103 /* We fork mount and drop all messages */
104 bool MountCdrom(string Path)
105 {
106 if (IsMounted(Path) == true)
107 return true;
108
109 int Child = ExecFork();
110
111 // The child
112 if (Child == 0)
113 {
114 // Make all the fds /dev/null
115 for (int I = 0; I != 3; I++)
116 dup2(open("/dev/null",O_RDWR),I);
117
118 if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true)
119 {
120 if (system(_config->Find("Acquire::cdrom::"+Path+"::Mount").c_str()) != 0)
121 _exit(100);
122 _exit(0);
123 }
124 else
125 {
126 const char *Args[10];
127 Args[0] = "mount";
128 Args[1] = Path.c_str();
129 Args[2] = 0;
130 execvp(Args[0],(char **)Args);
131 _exit(100);
132 }
133 }
134
135 // Wait for mount
136 return ExecWait(Child,"mount",true);
137 }
138 /*}}}*/
139 // IdentCdrom - Generate a unique string for this CD /*{{{*/
140 // ---------------------------------------------------------------------
141 /* We convert everything we hash into a string, this prevents byte size/order
142 from effecting the outcome. */
143 bool IdentCdrom(string CD,string &Res,unsigned int Version)
144 {
145 MD5Summation Hash;
146
147 string StartDir = SafeGetCWD();
148 if (chdir(CD.c_str()) != 0)
149 return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str());
150
151 DIR *D = opendir(".");
152 if (D == 0)
153 return _error->Errno("opendir",_("Unable to read %s"),CD.c_str());
154
155 /* Run over the directory, we assume that the reader order will never
156 change as the media is read-only. In theory if the kernel did
157 some sort of wacked caching this might not be true.. */
158 char S[300];
159 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
160 {
161 // Skip some files..
162 if (strcmp(Dir->d_name,".") == 0 ||
163 strcmp(Dir->d_name,"..") == 0)
164 continue;
165
166 if (Version <= 1)
167 {
168 sprintf(S,"%lu",(unsigned long)Dir->d_ino);
169 }
170 else
171 {
172 struct stat Buf;
173 if (stat(Dir->d_name,&Buf) != 0)
174 continue;
175 sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
176 }
177
178 Hash.Add(S);
179 Hash.Add(Dir->d_name);
180 };
181
182 chdir(StartDir.c_str());
183 closedir(D);
184
185 // Some stats from the fsys
186 if (_config->FindB("Debug::identcdrom",false) == false)
187 {
188 struct statvfs Buf;
189 if (statvfs(CD.c_str(),&Buf) != 0)
190 return _error->Errno("statfs",_("Failed to stat the cdrom"));
191
192 // We use a kilobyte block size to advoid overflow
193 sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),
194 (long)(Buf.f_bfree*(Buf.f_bsize/1024)));
195 Hash.Add(S);
196 sprintf(S,"-%u",Version);
197 }
198 else
199 sprintf(S,"-%u.debug",Version);
200
201 Res = Hash.Result().Value() + S;
202 return true;
203 }
204 /*}}}*/