- moved here from sysv/
[util-vserver.git] / src / vcheck.cc
1 // $Id: vcheck.cc,v 1.1 2003/09/29 22:01:57 ensc Exp $
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vcheck.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 /*
21         This utility is used to compare two vservers. One is known to
22         be clean and the other is potentially corrupted (cracked). The
23         goal of this program is to run the rpm verify command, but using
24         the RPM database of the first vserver.
25 */
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <dirent.h>
31
32 #include <string>
33 #include <vector>
34 #include <list>
35 #include <set>
36 #include "vutil.h"
37
38 using namespace std;
39
40
41 static void usage()
42 {
43         cerr <<
44                 "vcheck version " << VERSION <<
45                 "\n\n"
46                 "vcheck [ options ] reference-server chk-vservers\n"
47                 "\n"
48                 "--diffpkgs: Shows which package differ.\n"
49                 "            + means the package only exists in chk-server.\n"
50                 "            - means the package does not exist in chk-server.\n"
51                 "            ! means the servers have different version.\n"
52                 "\n"
53                 "--verify: Execute an RPM verify on common packages.\n"
54                 "--debug: Turn on some (useless) debugging messages.\n"
55                 ;
56 }
57
58 typedef list<PACKAGE> PACKAGES;
59
60 /*
61         Delete a directory silently
62 */
63 static int vcheck_deldir (const string &path)
64 {
65         int ret = -1;
66         struct stat st;
67         if (lstat(path.c_str(),&st)==-1){
68                 ret = 0;
69         }else{
70                 if (!S_ISDIR(st.st_mode)){
71                         fprintf (stderr,"%s already exist and is not a directory\n"
72                                 ,path.c_str());
73                         exit (-1);
74                 }else{
75                         DIR *d = opendir (path.c_str());
76                         if (d != NULL){
77                                 struct dirent *ent;
78                                 ret = 0;
79                                 while ((ent=readdir(d))!=NULL){
80                                         if (strcmp(ent->d_name,".")!=0
81                                                 && strcmp(ent->d_name,"..")!=0){
82                                                 string tmp = path + "/" + ent->d_name;
83                                                 if (unlink(tmp.c_str())==-1){
84                                                         fprintf (stderr,"Can't delete file %s (%s)\n",tmp.c_str()
85                                                                 ,strerror(errno));
86                                                         ret = -1;
87                                                         break;
88                                                 }
89                                         }
90                                 }
91                                 closedir (d);
92                                 rmdir (path.c_str());
93                         }
94                 }
95         }
96         return ret;
97 }
98                 
99
100 static int vcheck_copydb (const string &refserv, const string &path)
101 {
102         int ret = -1;
103         string refpath = refserv + "/var/lib/rpm";
104         DIR *d = opendir (refpath.c_str());
105         if (d == NULL){
106                 fprintf (stderr,"Can't open directory %s (%s)\n",refpath.c_str()
107                         ,strerror(errno));
108         }else{
109                 ret = 0;
110                 struct dirent *ent;
111                 while ((ent=readdir(d))!=NULL){
112                         if (strcmp(ent->d_name,".")!=0
113                                 && strcmp(ent->d_name,"..")!=0){
114                                 string srcpath = refpath + "/" + ent->d_name;
115                                 const char *spath = srcpath.c_str();
116                                 struct stat st;
117                                 if (stat(spath,&st)!=-1){
118                                         string dstpath = path + "/" + ent->d_name;
119                                         if (file_copy (spath,dstpath.c_str(),st) == -1){
120                                                 ret = -1;
121                                                 break;
122                                         }
123                                 }else{
124                                         ret = -1;
125                                         fprintf (stderr,"Can't stat %s (%s)\n",spath,strerror(errno));
126                                         break;
127                                 }
128                         }
129                 }
130                 closedir (d);
131         }
132         return ret;
133 }
134
135 class cmp_name{
136 public:
137         int operator()(const PACKAGE &p1, const PACKAGE &p2){
138                 return strcmp(p1.name.c_str(),p2.name.c_str());
139         }
140 };
141
142
143 int main (int argc, char *argv[])
144 {
145         int ret = -1;
146         bool diffpkg = false;
147         bool verify = false;
148         int i;
149         for (i=1; i<argc; i++){
150                 const char *arg = argv[i];
151                 //const char *opt = argv[i+1];
152                 if (strcmp(arg,"--diffpkg")==0){
153                         diffpkg = true;
154                 }else if (strcmp(arg,"--verify")==0){
155                         verify = true;
156                 }else if (strcmp(arg,"--debug")==0){
157                         debug++;
158                 }else{
159                         break;
160                 }
161         }
162         if (i!=argc-2){
163                 usage();
164         }else{
165                 string refserv = argv[i++];
166                 string chkserv = argv[i];
167                 PACKAGES refpkgs,chkpkgs;
168                 // Load the package list from both vservers
169                 vutil_loadallpkg (refserv,refpkgs);
170                 vutil_loadallpkg (chkserv,chkpkgs);
171                 PACKAGES common, differ, added, removed;
172                 // Find which package are different, missing and added
173                 // to chkserv
174                 for (PACKAGES::iterator it=refpkgs.begin(); it!=refpkgs.end(); it++){
175                         PACKAGES::iterator f = find_if(chkpkgs.begin(),chkpkgs.end(),same_name(*it));
176                         if (f == chkpkgs.end()){
177                                 removed.push_back (*it);
178                         }else if (f->version != it->version){
179                                 differ.push_back (*it);
180                         }else{
181                                 common.push_back (*it);
182                         }
183                 }
184                 for (list<PACKAGE>::iterator it=chkpkgs.begin(); it!=chkpkgs.end(); it++){
185                         list<PACKAGE>::iterator f = find_if(refpkgs.begin(),refpkgs.end(),same_name(*it));
186                         if (f == refpkgs.end()){
187                                 added.push_back (*it);
188                         }
189                 }
190                 differ.sort ();
191                 added.sort();
192                 removed.sort();
193                 common.sort ();
194                 bool something = false;
195                 if (diffpkg){
196                         for (PACKAGES::iterator it=removed.begin(); it!=removed.end(); it++){
197                                 printf ("- %s\n",it->name.c_str());
198                         }
199                         for (PACKAGES::iterator it=added.begin(); it!=added.end(); it++){
200                                 printf ("+ %s\n",it->name.c_str());
201                         }
202                         for (PACKAGES::iterator it=differ.begin(); it!=differ.end(); it++){
203                                 printf ("! %s\n",it->name.c_str());
204                         }
205                         something = true;
206                 }
207                 if (verify){
208                         // We copy the rpm database from the reference vserver to
209                         // the target vserver
210                         string dbpath = chkserv + "/tmp/vcheck.db";
211                         vcheck_deldir (dbpath);
212                         if (mkdir (dbpath.c_str(),0)==-1){
213                                 fprintf (stderr,"Can't create directory %s (%s)\n"
214                                         ,dbpath.c_str(),strerror(errno));
215                         }else if (vcheck_copydb (refserv,dbpath) != -1){
216                                 // We only compare the common package
217                                 string cmd = "rpm --dbpath /tmp/vcheck.db --root " + chkserv + " -V";
218                                 for (PACKAGES::iterator it=common.begin(); it!=common.end(); it++){
219                                         //printf ("compare %s\n",it->name.c_str());
220                                         cmd += " " + it->name;
221                                 }
222                                 if (debug) printf ("CMD: %s\n",cmd.c_str());
223                                 system (cmd.c_str());
224                         }
225                         vcheck_deldir (dbpath);
226                         something = true;
227                 }
228                 if (!something){
229                         fprintf (stderr,"Nothing to do !!!\n\n");
230                         usage();
231                 }
232         }
233         return ret;
234 }
235
236
237