001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.exec;
018
019import java.io.File;
020import java.util.Locale;
021
022/**
023 * Condition that tests the OS type.
024 *
025 * Copied and adapted from Apache Ant 1.9.6 from org.apache.tools.ant.taskdefs.condition.OS.
026 */
027public final class OS {
028
029    /**
030     * OS family that can be tested for. {@value}
031     */
032    public static final String FAMILY_9X = "win9x";
033    /**
034     * OS family that can be tested for. {@value}
035     */
036    public static final String FAMILY_DOS = "dos";
037    /**
038     * OS family that can be tested for. {@value}
039     */
040    public static final String FAMILY_MAC = "mac";
041    /**
042     * OS family that can be tested for. {@value}
043     */
044    public static final String FAMILY_NETWARE = "netware";
045    /**
046     * OS family that can be tested for. {@value}
047     */
048    public static final String FAMILY_NT = "winnt";
049    /**
050     * OS family that can be tested for. {@value}
051     */
052    public static final String FAMILY_OS2 = "os/2";
053    /**
054     * OS family that can be tested for. {@value}
055     */
056    public static final String FAMILY_OS400 = "os/400";
057    /**
058     * OS family that can be tested for. {@value}
059     */
060    public static final String FAMILY_TANDEM = "tandem";
061    /**
062     * OS family that can be tested for. {@value}
063     */
064    public static final String FAMILY_UNIX = "unix";
065    /**
066     * OS family that can be tested for. {@value}
067     */
068    public static final String FAMILY_VMS = "openvms";
069    /**
070     * OS family that can be tested for. {@value}
071     */
072    public static final String FAMILY_WINDOWS = "windows";
073    /**
074     * OS family that can be tested for. {@value}
075     */
076    public static final String FAMILY_ZOS = "z/os";
077
078    private static final String DARWIN = "darwin";
079
080    private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
081    private static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(Locale.ENGLISH);
082    private static final String OS_VERSION = System.getProperty("os.version").toLowerCase(Locale.ENGLISH);
083    private static final String PATH_SEP = File.pathSeparator;
084
085    /**
086     * Tests whether the OS on which commons-exec is executing matches the given OS architecture.
087     *
088     * @param arch the OS architecture to check for.
089     * @return whether if the OS matches.
090     */
091    public static boolean isArch(final String arch) {
092        return isOs(null, null, arch, null);
093    }
094
095    /**
096     * Tests whether the OS on which commons-exec is executing matches the given OS family.
097     *
098     * @param family the family to check for.
099     * @return whether if the OS matches.
100     */
101    private static boolean isFamily(final String family) {
102        return isOs(family, null, null, null);
103    }
104
105    /**
106     * Tests whether the OS is in the DOS family.
107     *
108     * @return whether the OS is in the DOS family.
109     */
110    public static boolean isFamilyDOS() {
111        return isFamily(FAMILY_DOS);
112    }
113
114    /**
115     * Tests whether the OS is in the Mac family.
116     *
117     * @return whether the OS is in the Mac family.
118     */
119    public static boolean isFamilyMac() {
120        return isFamily(FAMILY_MAC);
121    }
122
123    /**
124     * Tests whether the OS is in the Netware family.
125     *
126     * @return whether the OS is in the Netware family.
127     */
128    public static boolean isFamilyNetware() {
129        return isFamily(FAMILY_NETWARE);
130    }
131
132    /**
133     * Tests whether the OS is in the OpenVMS family.
134     *
135     * @return whether the OS is in the OpenVMS family.
136     */
137    public static boolean isFamilyOpenVms() {
138        return isFamily(FAMILY_VMS);
139    }
140
141    /**
142     * Tests whether the OS is in the OS/2 family.
143     *
144     * @return whether the OS is in the OS/2 family.
145     */
146    public static boolean isFamilyOS2() {
147        return isFamily(FAMILY_OS2);
148    }
149
150    /**
151     * Tests whether the OS is in the OS/400 family.
152     *
153     * @return whether the OS is in the OS/400 family.
154     */
155    public static boolean isFamilyOS400() {
156        return isFamily(FAMILY_OS400);
157    }
158
159    /**
160     * Tests whether the OS is in the Tandem family.
161     *
162     * @return whether the OS is in the Tandem family.
163     */
164    public static boolean isFamilyTandem() {
165        return isFamily(FAMILY_TANDEM);
166    }
167
168    /**
169     * Tests whether the OS is in the Unix family.
170     *
171     * @return whether the OS is in the Unix family.
172     */
173    public static boolean isFamilyUnix() {
174        return isFamily(FAMILY_UNIX);
175    }
176
177    /**
178     * Tests whether the OS is in the Windows 9x family.
179     *
180     * @return whether the OS is in the Windows 9x family.
181     */
182    public static boolean isFamilyWin9x() {
183        return isFamily(FAMILY_9X);
184    }
185
186    /**
187     * Tests whether the OS is in the Windows family.
188     *
189     * @return whether the OS is in the Windows family.
190     */
191    public static boolean isFamilyWindows() {
192        return isFamily(FAMILY_WINDOWS);
193    }
194
195    /**
196     * Tests whether the OS is in the Windows NT family.
197     *
198     * @return whether the OS is in the Windows NT family.
199     */
200    public static boolean isFamilyWinNT() {
201        return isFamily(FAMILY_NT);
202    }
203
204    /**
205     * Tests whether the OS is in the z/OS family.
206     *
207     * @return whether the OS is in the z/OS family.
208     */
209    public static boolean isFamilyZOS() {
210        return isFamily(FAMILY_ZOS);
211    }
212
213    /**
214     * Tests whether if the OS on which commons-exec is executing matches the given OS name.
215     *
216     * @param name the OS name to check for.
217     * @return whether the OS matches.
218     */
219    public static boolean isName(final String name) {
220        return isOs(null, name, null, null);
221    }
222
223    /**
224     * Tests whether the OS on which commons-exec is executing matches the given OS family, name, architecture and version.
225     *
226     * @param family  The OS family.
227     * @param name    The OS name.
228     * @param arch    The OS architecture.
229     * @param version The OS version.
230     * @return whether the OS matches.
231     */
232    public static boolean isOs(final String family, final String name, final String arch, final String version) {
233        boolean retValue = false;
234        if (family != null || name != null || arch != null || version != null) {
235            boolean isFamily = true;
236            boolean isName = true;
237            boolean isArch = true;
238            boolean isVersion = true;
239            if (family != null) {
240                // Windows probing logic relies on the word 'windows' in the OS
241                final boolean isWindows = OS_NAME.contains(FAMILY_WINDOWS);
242                boolean is9x = false;
243                boolean isNT = false;
244                if (isWindows) {
245                    // there are only four 9x platforms that we look for
246                    is9x = OS_NAME.contains("95") || OS_NAME.contains("98") || OS_NAME.contains("me")
247                    // Windows CE isn't really 9x, but crippled enough to
248                    // be a muchness. Ant doesn't run on CE, anyway.
249                            || OS_NAME.contains("ce");
250                    isNT = !is9x;
251                }
252                switch (family) {
253                case FAMILY_WINDOWS:
254                    isFamily = isWindows;
255                    break;
256                case FAMILY_9X:
257                    isFamily = isWindows && is9x;
258                    break;
259                case FAMILY_NT:
260                    isFamily = isWindows && isNT;
261                    break;
262                case FAMILY_OS2:
263                    isFamily = OS_NAME.contains(FAMILY_OS2);
264                    break;
265                case FAMILY_NETWARE:
266                    isFamily = OS_NAME.contains(FAMILY_NETWARE);
267                    break;
268                case FAMILY_DOS:
269                    isFamily = PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE);
270                    break;
271                case FAMILY_MAC:
272                    isFamily = OS_NAME.contains(FAMILY_MAC) || OS_NAME.contains(DARWIN);
273                    break;
274                case FAMILY_TANDEM:
275                    isFamily = OS_NAME.contains("nonstop_kernel");
276                    break;
277                case FAMILY_UNIX:
278                    isFamily = PATH_SEP.equals(":") && !isFamily(FAMILY_VMS) && (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x") || OS_NAME.contains(DARWIN));
279                    break;
280                case FAMILY_ZOS:
281                    isFamily = OS_NAME.contains(FAMILY_ZOS) || OS_NAME.contains("os/390");
282                    break;
283                case FAMILY_OS400:
284                    isFamily = OS_NAME.contains(FAMILY_OS400);
285                    break;
286                case FAMILY_VMS:
287                    isFamily = OS_NAME.contains(FAMILY_VMS);
288                    break;
289                default:
290                    throw new IllegalArgumentException("Don\'t know how to detect OS family \"" + family + "\"");
291                }
292            }
293            if (name != null) {
294                isName = name.equals(OS_NAME);
295            }
296            if (arch != null) {
297                isArch = arch.equals(OS_ARCH);
298            }
299            if (version != null) {
300                isVersion = version.equals(OS_VERSION);
301            }
302            retValue = isFamily && isName && isArch && isVersion;
303        }
304        return retValue;
305    }
306
307    /**
308     * Tests whether the OS on which commonss-exec is executing matches the given OS version.
309     *
310     * @param version the OS version to check for.
311     * @return whether if the OS matches.
312     */
313    public static boolean isVersion(final String version) {
314        return isOs(null, null, null, version);
315    }
316
317    /**
318     * Avoids instances.
319     */
320    private OS() {
321    }
322}