1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.setup.InstallerHelper;
25 
26 import org.openoffice.setup.InstallData;
27 import org.openoffice.setup.SetupData.PackageDescription;
28 import org.openoffice.setup.Util.Converter;
29 import org.openoffice.setup.Util.ExecuteProcess;
30 import org.openoffice.setup.Util.LogManager;
31 import org.openoffice.setup.Util.SystemManager;
32 import java.io.File;
33 import java.util.Enumeration;
34 import java.util.HashMap;
35 import java.util.Vector;public class LinuxHelper {
36 
LinuxHelper()37     public LinuxHelper() {
38         super();
39     }
40 
getPackageNamesContent(PackageDescription packageData, Vector packageNames)41     private void getPackageNamesContent(PackageDescription packageData, Vector packageNames) {
42         if (( packageData.getPackageName() != null ) && ( ! packageData.getPackageName().equals("")))  {
43             packageNames.add(packageData.getPackageName() + "=" + packageData.getFullPackageName());
44         }
45 
46         for (Enumeration e = packageData.children(); e.hasMoreElements(); ) {
47             PackageDescription child = (PackageDescription) e.nextElement();
48             getPackageNamesContent(child, packageNames);
49         }
50     }
51 
getPackageNameFromRpm(PackageDescription packageData, InstallData installData)52     private String getPackageNameFromRpm(PackageDescription packageData, InstallData installData) {
53         String fullPackageName = null;
54         String packagePath = installData.getPackagePath();
55 
56         if (( packageData.getPkgSubdir() != null ) && ( ! packageData.getPkgSubdir().equals("") )) {
57             File completePackageFile = new File(packagePath, packageData.getPkgSubdir());
58             packagePath = completePackageFile.getPath();
59         }
60 
61         String rpmFileName = packageData.getPackageName();
62         File rpmFile = new File(packagePath, rpmFileName);
63 
64         if ( rpmFile.exists() ) {
65             String rpmCommand = "rpm -qp " + rpmFile.getPath();
66             String[] rpmCommandArray = new String[3];
67             rpmCommandArray[0] = "rpm";
68             rpmCommandArray[1] = "-qp";
69             rpmCommandArray[2] = rpmFile.getPath();
70 
71             Vector returnVector = new Vector();
72             Vector returnErrorVector = new Vector();
73             int returnValue = ExecuteProcess.executeProcessReturnVector(rpmCommandArray, returnVector, returnErrorVector);
74             String returnString = (String) returnVector.get(0);
75 
76             String log = rpmCommand + "<br><b>Returns: " + returnString + "</b><br>";
77             LogManager.addCommandsLogfileComment(log);
78 
79             fullPackageName = returnString;
80 
81         } else {
82             System.err.println("Error: Could not find file " + rpmFile.getPath());
83         }
84 
85         return fullPackageName;
86     }
87 
checkPackageExistence(PackageDescription packageData, InstallData installData)88     private boolean checkPackageExistence(PackageDescription packageData, InstallData installData) {
89         boolean fileExists = false;
90 
91         String packagePath = installData.getPackagePath();
92 
93         if (( packageData.getPkgSubdir() != null ) && ( ! packageData.getPkgSubdir().equals("") )) {
94             File completePackageFile = new File(packagePath, packageData.getPkgSubdir());
95             packagePath = completePackageFile.getPath();
96         }
97 
98         String rpmFileName = packageData.getPackageName();
99 
100         File rpmFile = new File(packagePath, rpmFileName);
101         if ( rpmFile.exists() ) {
102             fileExists = true;
103         }
104 
105         return fileExists;
106     }
107 
analyzeVersionString(String versionString)108     private HashMap analyzeVersionString(String versionString) {
109 
110         boolean errorOccured = false;
111 
112         Integer micro = null;
113         Integer minor = null;
114         Integer major = null;
115         Integer release = null;
116 
117         String microString = null;
118         String minorString = null;
119         String majorString = null;
120         String releaseString = null;
121 
122         int pos = versionString.lastIndexOf("_");  // this is a jre RPM (1.5.0_06)
123 
124         if ( pos > -1 ) {
125             try {
126                 releaseString = versionString.substring(pos+1, versionString.length());
127                 versionString = versionString.substring(0, pos);
128             } catch (IndexOutOfBoundsException ex) {
129                 System.err.println("Error: Could not get substring from " + versionString);
130                 errorOccured = true;
131             }
132             try {
133                 int releaseInt = Integer.parseInt(releaseString);
134                 release = new Integer(releaseInt);
135             } catch (NumberFormatException ex) {
136                 System.err.println("Error: Could not convert " + releaseString + " to integer");
137                 errorOccured = true;
138             }
139         }
140 
141         // Problem: Some rpms have "2.3" instead of "2.3.0"
142         String compareString = versionString;
143         pos = compareString.lastIndexOf(".");  // returns "-1", if not found
144         if ( pos > -1 ) {
145             String substring = compareString.substring(0, pos);
146             pos = substring.lastIndexOf(".");  // returns "-1", if not found
147             if ( pos == -1 ) {
148                 versionString = versionString + ".0";
149                 // System.err.println("Warning: Changing from " + compareString + " to " + versionString);
150             }
151         } else {
152             versionString = versionString + ".0.0";
153         }
154 
155         // the standard analyzing mechanism
156         pos = versionString.lastIndexOf(".");  // returns "-1", if not found
157 
158         if ( pos > -1 )
159         {
160             try {
161                 microString = versionString.substring(pos+1, versionString.length());
162                 versionString = versionString.substring(0, pos);
163             } catch (IndexOutOfBoundsException ex) {
164                 System.err.println("Error: Could not get substring from " + versionString);
165                 errorOccured = true;
166             }
167 
168             pos = versionString.lastIndexOf(".");
169             if ( pos > -1 ) {
170                 try {
171                     minorString = versionString.substring(pos+1, versionString.length());
172                     majorString = versionString.substring(0, pos);
173                 } catch (IndexOutOfBoundsException ex) {
174                     System.err.println("Error: Could not get substring from " + versionString);
175                     errorOccured = true;
176                 }
177                 try {
178                     int microInt = Integer.parseInt(microString);
179                     int minorInt = Integer.parseInt(minorString);
180                     int majorInt = Integer.parseInt(majorString);
181                     micro = new Integer(microInt);
182                     minor = new Integer(minorInt);
183                     major = new Integer(majorInt);
184                 } catch (NumberFormatException ex) {
185                     System.err.println("Error: Could not convert " + microString + "," +
186                                        minorString + " or " + majorString + " to integer");
187                     errorOccured = true;
188                 }
189             }
190         }
191 
192         // if ( microString == null ) { microString = ""; }
193         // if ( majorString == null ) { majorString = ""; }
194         // if ( releaseString == null ) { releaseString = ""; }
195         // if ( minorString == null ) { minorString = ""; }
196         // System.err.println("Major " + majorString + " Minor: " + minorString + " Micro: " + microString + " Release: " + releaseString);
197 
198         if ( errorOccured ) {
199             micro = null;
200             minor = null;
201             major = null;
202             release = null;
203         }
204 
205         HashMap hashRpm = new HashMap();
206 
207         hashRpm.put("micro", micro);
208         hashRpm.put("minor", minor);
209         hashRpm.put("major", major);
210         hashRpm.put("release", release);
211 
212         // If one of this values is "null", procedure "compareTwoRpms" always delivers false.
213         // This means, that the installed package is not older.
214 
215         // System.err.println("Analyzed: " + "micro: " + hashRpm.get("micro").toString() + " minor: " + hashRpm.get("minor").toString() + " major: " + hashRpm.get("major").toString());
216 
217         return hashRpm;
218     }
219 
analyzeReleaseString(HashMap hashRpm, String releaseString)220     private HashMap analyzeReleaseString(HashMap hashRpm, String releaseString) {
221         int release;
222 
223         try {
224             release = Integer.parseInt(releaseString);
225             Integer releaseObj = new Integer(release);
226             hashRpm.put("release", releaseObj);
227          }
228         catch (NumberFormatException ex) {
229         	// JRE often contain a string like "FCS"
230             // System.err.println("Error: Could not convert " + releaseString + " to integer");
231             hashRpm.put("release", null);
232         }
233 
234         return hashRpm;
235     }
236 
getInstalledMinor(String version)237     public int getInstalledMinor(String version) {
238 
239         int minor = 0;
240         int pos = version.indexOf(".");
241         if ( pos > -1 ) {
242             String reduced = version.substring(pos + 1, version.length());
243 
244             pos = reduced.indexOf(".");
245             if ( pos > -1 ) {
246                 reduced = reduced.substring(0, pos);
247                 minor = Integer.parseInt(reduced);
248             }
249         }
250 
251     	return minor;
252     }
253 
compareTwoRpms(HashMap hash1, HashMap hash2)254     private boolean compareTwoRpms(HashMap hash1, HashMap hash2) {
255         boolean hash1IsOlder = false;
256 
257         if (( hash1.get("major") != null ) && ( hash2.get("major") != null )) {
258             if ( ((Integer)hash1.get("major")).intValue() < ((Integer)hash2.get("major")).intValue() ) {
259                 hash1IsOlder = true;
260             } else {
261                 if (( hash1.get("minor") != null ) && ( hash2.get("minor") != null )) {
262                     if ( ((Integer)hash1.get("minor")).intValue() < ((Integer)hash2.get("minor")).intValue() ) {
263                         hash1IsOlder = true;
264                     } else {
265                         if (( hash1.get("micro") != null ) && ( hash2.get("micro") != null )) {
266                             if ( ((Integer)hash1.get("micro")).intValue() < ((Integer)hash2.get("micro")).intValue() ) {
267                                 hash1IsOlder = true;
268                             } else {
269                                 if (( hash1.get("release") != null ) && ( hash2.get("release") != null )) {
270                                     if ( ((Integer)hash1.get("release")).intValue() < ((Integer)hash2.get("release")).intValue() ) {
271                                         hash1IsOlder = true;
272                                     }
273                                 }
274                             }
275                         }
276                     }
277                 }
278             }
279         }
280 
281         return hash1IsOlder;
282     }
283 
compareVersionAndRelease(String versionString, String releaseString, PackageDescription packageData, boolean checkIfInstalledIsOlder)284     public boolean compareVersionAndRelease(String versionString, String releaseString, PackageDescription packageData, boolean checkIfInstalledIsOlder) {
285         // version and release are gotten from the rpm database. packageData contains
286         // the information about the rpm, that shall be installed. It has to be installed,
287         // if the installed product defined by version and release is older.
288         // version is something like "2.0.3", release something like "164".
289         // An exception is the jre package, where version is "1.5.0_06" and release "fcs".
290 
291         HashMap installedRpm = analyzeVersionString(versionString);
292         if ( installedRpm.get("release") == null ) {
293             installedRpm = analyzeReleaseString(installedRpm, releaseString);
294         }
295 
296         // System.err.println("Package: " + packageData.getPackageName());
297         // String outputString = "Installed RPM: ";
298         // if ( installedRpm.get("major") != null ) { outputString = outputString + " major: " + installedRpm.get("major").toString(); }
299         // else { outputString = outputString + " major is null"; }
300         // if ( installedRpm.get("minor") != null ) { outputString = outputString + " minor: " + installedRpm.get("minor").toString(); }
301         // else { outputString = outputString + " minor is null"; }
302         // if ( installedRpm.get("micro") != null ) { outputString = outputString + " micro: " + installedRpm.get("micro").toString(); }
303         // else { outputString = outputString + " micro is null"; }
304         // if ( installedRpm.get("release") != null ) { outputString = outputString + " release: " + installedRpm.get("release").toString(); }
305         // else { outputString = outputString + " release is null"; }
306         // System.err.println(outputString);
307 
308         HashMap notInstalledRpm = analyzeVersionString(packageData.getPkgVersion());
309         if ( notInstalledRpm.get("release") == null ) {
310             notInstalledRpm = analyzeReleaseString(notInstalledRpm, packageData.getPkgRelease());
311         }
312 
313         // outputString = "Not installed RPM: ";
314         // if ( notInstalledRpm.get("major") != null ) { outputString = outputString + " major: " + notInstalledRpm.get("major").toString(); }
315         // else { outputString = outputString + " major is null"; }
316         // if ( notInstalledRpm.get("minor") != null ) { outputString = outputString + " minor: " + notInstalledRpm.get("minor").toString(); }
317         // else { outputString = outputString + " minor is null"; }
318         // if ( notInstalledRpm.get("micro") != null ) { outputString = outputString + " micro: " + notInstalledRpm.get("micro").toString(); }
319         // else { outputString = outputString + " micro is null"; }
320         // if ( notInstalledRpm.get("release") != null ) { outputString = outputString + " release: " + notInstalledRpm.get("release").toString(); }
321         // else { outputString = outputString + " release is null"; }
322         // System.err.println(outputString);
323 
324         boolean firstIsOlder = false;
325 
326         if ( checkIfInstalledIsOlder ) {
327             firstIsOlder = compareTwoRpms(installedRpm, notInstalledRpm);
328             // System.err.println("Result: Installed RPM is older: " + firstIsOlder);
329         } else {
330             firstIsOlder = compareTwoRpms(notInstalledRpm, installedRpm);
331             // System.err.println("Result: Not installed RPM is older: " + firstIsOlder);
332         }
333 
334         return firstIsOlder;
335     }
336 
getLinuxPackageNamesFromRpmquery(PackageDescription packageData, InstallData installData)337     public void getLinuxPackageNamesFromRpmquery(PackageDescription packageData, InstallData installData) {
338 
339         if ((packageData.getPackageName() != null) && ( ! packageData.getPackageName().equals(""))) {
340 
341             boolean rpmExists = checkPackageExistence(packageData, installData);
342 
343             if ( rpmExists ) {
344                 // Full package name not defined in xpd file
345                 if (( packageData.getFullPackageName() == null ) || ( packageData.getFullPackageName().equals(""))) {
346                     // Now it is possible to query the rpm database for the packageName, if it is not defined in xpd file!
347                     String fullPackageName = getPackageNameFromRpm(packageData, installData);
348                     if ( fullPackageName != null ) {
349                         packageData.setFullPackageName(fullPackageName);
350                     } else {
351                         System.err.println("Error: Linux package name not defined in xpd file and could not be determined: "
352                                 + packageData.getPackageName());
353                     }
354                 }
355                 packageData.setPkgExists(true);
356 
357             } else {
358                 packageData.setPkgExists(false);
359             }
360 
361         }
362 
363         for (Enumeration e = packageData.children(); e.hasMoreElements(); ) {
364             PackageDescription child = (PackageDescription) e.nextElement();
365             getLinuxPackageNamesFromRpmquery(child, installData);
366         }
367     }
368 
getLinuxDatabasePath(InstallData data)369     public String getLinuxDatabasePath(InstallData data) {
370         String databasePath = null;
371         String installDir = data.getInstallDir();
372         String databaseDir = installDir;
373         // String databaseDir = SystemManager.getParentDirectory(installDir);
374         String linuxDatabaseName = ".RPM_OFFICE_DATABASE";
375         File databaseFile = new File(databaseDir, linuxDatabaseName);
376         databasePath = databaseFile.getPath();
377         return databasePath;
378     }
379 
investigateDebian(InstallData data)380     public void investigateDebian(InstallData data) {
381 
382         // First check: Is this a Debian system?
383 
384         String dpkgFile = "/usr/bin/dpkg";
385 
386         if ( new File(dpkgFile).exists() ) {
387 
388             data.setIsDebianSystem(true);
389 
390             // Second check: If this is a Debian system, is "--force-debian" required? Older
391             // versions do not support "--force-debian".
392 
393             // String rpmQuery = "rpm --help;
394             String[] rpmQueryArray = new String[2];
395             rpmQueryArray[0] = "rpm";
396             rpmQueryArray[1] = "--help";
397 
398             Vector returnVector = new Vector();
399             Vector returnErrorVector = new Vector();
400             int returnValue = ExecuteProcess.executeProcessReturnVector(rpmQueryArray, returnVector, returnErrorVector);
401 
402             // Checking if the return vector contains the string "force-debian"
403 
404             for (int i = 0; i < returnVector.size(); i++) {
405                 String line = (String) returnVector.get(i);
406                 if ( line.indexOf("force-debian") > -1 ) {
407                     data.setUseForceDebian(true);
408                 }
409             }
410         }
411     }
412 
getLinuxFileInfo(PackageDescription packageData)413     public void getLinuxFileInfo(PackageDescription packageData) {
414         // analyzing a string like "openoffice-core01-2.0.3-159" as "name-version-release"
415         InstallData data = InstallData.getInstance();
416         if ( packageData.pkgExists() ) {
417             if (( packageData.getFullPackageName() != null ) && ( ! packageData.getFullPackageName().equals(""))) {
418                 String longName = packageData.getFullPackageName();
419 
420                 int pos = longName.lastIndexOf("-");
421                 if (data.isInstallationMode()) {
422                     // not saving at uninstallation, because it can be updated without GUI installer
423                     packageData.setPkgRelease(longName.substring(pos+1, longName.length()));
424                 }
425                 longName = longName.substring(0, pos);
426 
427                 pos = longName.lastIndexOf("-");
428                 if (data.isInstallationMode()) {
429                     // not saving at uninstallation, because it can be updated without GUI installer
430                     packageData.setPkgVersion(longName.substring(pos+1, longName.length()));
431                 }
432                 packageData.setPkgRealName(longName.substring(0, pos));
433             }
434         }
435 
436         for (Enumeration e = packageData.children(); e.hasMoreElements(); ) {
437             PackageDescription child = (PackageDescription) e.nextElement();
438             getLinuxFileInfo(child);
439         }
440 
441     }
442 
setFullPackageNameAtUninstall(PackageDescription packageData, HashMap packageNames)443     public void setFullPackageNameAtUninstall(PackageDescription packageData, HashMap packageNames) {
444 
445         if (( packageData.getPackageName() != null ) && ( ! packageData.getPackageName().equals("")))  {
446             if (( packageData.getFullPackageName() == null ) || ( packageData.getFullPackageName().equals(""))) {
447                 String packageName = packageData.getPackageName();
448                 // Does this always exist? Should not be required!
449                 // But is there another way to get the packageNames, without this file?
450                 // During installation the packageNames can be determined by querying the rpm file
451                 // -> this is not possible during uninstallation
452                 String fullPackageName = (String) packageNames.get(packageName);
453                 packageData.setFullPackageName(fullPackageName);
454             }
455         }
456 
457         for (Enumeration e = packageData.children(); e.hasMoreElements(); ) {
458             PackageDescription child = (PackageDescription) e.nextElement();
459             setFullPackageNameAtUninstall(child, packageNames);
460         }
461     }
462 
getRelocationString(PackageDescription packageData, String packageName)463     public String getRelocationString(PackageDescription packageData, String packageName) {
464         String relocationString = null;
465 
466         if ( packageData.isRelocatable() ) {
467             // String rpmQuery = "rpm -qp --qf %{PREFIXES}" + " " + packageName;
468             String[] rpmQueryArray = new String[5];
469             rpmQueryArray[0] = "rpm";
470             rpmQueryArray[1] = "-qp";
471             rpmQueryArray[2] = "--qf";
472             rpmQueryArray[3] = "%{PREFIXES}";
473             rpmQueryArray[4] = packageName;
474 
475             Vector returnVector = new Vector();
476             Vector returnErrorVector = new Vector();
477             int returnValue = ExecuteProcess.executeProcessReturnVector(rpmQueryArray, returnVector, returnErrorVector);
478             relocationString = (String) returnVector.get(0);
479         }
480 
481         return relocationString;
482     }
483 
createPackageNameFileAtPostinstall(InstallData data, PackageDescription packageData)484     public void createPackageNameFileAtPostinstall(InstallData data, PackageDescription packageData) {
485 
486         // The file "packageNames" must not be an own database! It must be possible to install
487         // and deinstall RPMs without this GUI installer. Therefore the file packageNames is
488         // not always up to date. Nevertheless it makes the deinstallation faster, because of
489         // all packages, whose "real" package name is not defined in xpd files (for example
490         // "openoffice-core01-2.0.3-159.rpm" hat the "real" name "openoffice-core01" that is
491         // used for deinstallation) this can be read in this file. Otherwise it would be
492         // neccessary to determine the "real" name with a database question.
493         // The version and release that are also stored in file "packageNames" must not be
494         // used for deinstallation because they are probably not up to date.
495 
496         File destDir = new File(data.getInstallDefaultDir(), data.getProductDir());
497         File uninstallDir = new File(destDir, data.getUninstallDirName());
498         String fileName = "packageNames";
499         File packageNamesFile = new File(uninstallDir, fileName);
500         Vector packageNames = new Vector();
501         getPackageNamesContent(packageData, packageNames);
502         SystemManager.saveCharFileVector(packageNamesFile.getPath(), packageNames);
503     }
504 
readPackageNamesFile()505     public HashMap readPackageNamesFile() {
506         // package names are stored in file "packageNames" in data.getInfoRoot() directory
507         String fileName = "packageNames";
508         InstallData data = InstallData.getInstance();
509         File dir = data.getInfoRoot();
510         File file = new File(dir, fileName);
511         Vector fileContent = SystemManager.readCharFileVector(file.getPath());
512         HashMap map = Converter.convertVectorToHashmap(fileContent);
513         return map;
514     }
515 
saveModulesLogFile(InstallData data)516     public void saveModulesLogFile(InstallData data) {
517         if ( data.logModuleStates() ) {
518             Vector logContent = LogManager.getModulesLogFile();
519             File destDir = new File(data.getInstallDefaultDir(), data.getProductDir());
520             File uninstallDir = new File(destDir, data.getUninstallDirName());
521             File modulesLogFile = new File(uninstallDir, "moduleSettingsLog.txt");
522             SystemManager.saveCharFileVector(modulesLogFile.getPath(), logContent);
523         }
524     }
525 
fixInstallationDirectory(String installDir)526     public String fixInstallationDirectory(String installDir) {
527         // inject a second slash to the last path segment to avoid rpm 3 concatenation bug
528         int lastSlashPos = installDir.lastIndexOf('/');
529         String sub1 = installDir.substring(0,lastSlashPos);
530         String sub2 = installDir.substring(lastSlashPos);
531         String fixedInstallDir = sub1 + "/" + sub2;
532         // fixedInstallDir.replaceAll(" ", "%20");
533         return fixedInstallDir;
534     }
535 
536 }
537