1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "Package.h"
27 #include "Executor.h"
28 #include "AppLauncher.h"
29 #include "ErrorHandling.h"
30 
31 
Package()32 Package::Package(): type(Unknown) {
33 }
34 
35 
36 namespace {
37 class FirstLineConsumer : public CommandOutputConsumer {
38 public:
FirstLineConsumer()39     FirstLineConsumer(): processed(false) {
40     }
41 
accept(const std::string & line)42     virtual bool accept(const std::string& line) {
43         if (!processed) {
44             value = line;
45             processed = true;
46         }
47         return processed;
48     };
49 
getValue() const50     std::string getValue() const {
51         if (!processed) {
52             JP_THROW("No output captured");
53         }
54         return value;
55     }
56 
57 private:
58     bool processed;
59     std::string value;
60 };
61 
62 
findOwnerOfFile(const std::nothrow_t &,const std::string & cmdline,const std::string & path)63 std::string findOwnerOfFile(const std::nothrow_t&, const std::string& cmdline,
64         const std::string& path) {
65     try {
66         FirstLineConsumer consumer;
67         int exitCode = executeCommandLineAndReadStdout(
68                 cmdline + " \'" + path + "\' 2>/dev/null", consumer);
69         if (exitCode == 0) {
70             return consumer.getValue();
71         }
72     } catch (...) {
73     }
74     return "";
75 }
76 
77 } // namespace
78 
findOwnerOfFile(const std::string & path)79 Package Package::findOwnerOfFile(const std::string& path) {
80     Package result;
81     result.theName = ::findOwnerOfFile(std::nothrow,
82             "rpm --queryformat '%{NAME}' -qf", path);
83     if (!result.theName.empty()) {
84         result.type = RPM;
85     } else {
86         tstring_array components = tstrings::split(::findOwnerOfFile(
87                 std::nothrow, "dpkg -S", path), ":");
88         if (!components.empty()) {
89             result.theName = components.front();
90             if (!result.theName.empty()) {
91                 result.type = DEB;
92             }
93         }
94     }
95 
96     return result;
97 }
98 
99 
100 namespace {
101 class AppLauncherInitializer : public CommandOutputConsumer {
102 public:
AppLauncherInitializer()103     AppLauncherInitializer() {
104     }
105 
accept(const std::string & line)106     virtual bool accept(const std::string& line) {
107         if (appDir.empty()) {
108             if (tstrings::endsWith(line, "/app")) {
109                 appDir = line;
110             }
111         }
112 
113         if (runtimeDir.empty()) {
114             if (tstrings::endsWith(line, "/runtime")) {
115                 runtimeDir = line;
116             }
117         }
118 
119         return !appDir.empty() && !runtimeDir.empty();
120     };
121 
apply(AppLauncher & launcher)122     void apply(AppLauncher& launcher) {
123         launcher.setDefaultRuntimePath(runtimeDir);
124         launcher.setAppDir(appDir);
125     }
126 
127 private:
128     std::string appDir;
129     std::string runtimeDir;
130 };
131 
132 } // namespace
133 
initAppLauncher(AppLauncher & appLauncher) const134 void Package::initAppLauncher(AppLauncher& appLauncher) const {
135     AppLauncherInitializer consumer;
136     int exitCode = -1;
137     if (type == RPM) {
138         exitCode = executeCommandLineAndReadStdout(
139                 "rpm -ql \'" + theName + "\'", consumer);
140     } else if (type == DEB) {
141         exitCode = executeCommandLineAndReadStdout(
142                 "dpkg -L \'" + theName + "\'", consumer);
143     }
144 
145     if (exitCode == 0) {
146         consumer.apply(appLauncher);
147     }
148 }
149