1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <mach/mach.h>
28#include <sys/types.h>
29#include <sys/sysctl.h>
30#include "stuff/errors.h"
31#include "stuff/allocate.h"
32#include "stuff/macosx_deployment_target.h"
33
34/* last value passed to put_macosx_deployment_target() */
35static char *command_line_macosx_deployment_target = NULL;
36
37/*
38 * put_macosx_deployment_target() is called with the command line argument to
39 * -macosx_version_min which the compiler uses to allow the user to asked for
40 * a particular macosx deployment target on the command-line to override the
41 * environment variable. This simply saves away the value requested.  The
42 * string passed is not copied. If NULL is passed, it removes any previous
43 * setting.
44 */
45__private_extern__
46void
47put_macosx_deployment_target(
48char *target)
49{
50	command_line_macosx_deployment_target = target;
51}
52
53/*
54 * get_macosx_deployment_target() sets the fields of the
55 * macosx_deployment_target struct passed to it based on the last
56 * command_line_macosx_deployment_target value set (if any) or the specified
57 * MACOSX_DEPLOYMENT_TARGET environment variable or the default which the
58 * the value the machine this is running on.  The name field in the struct is
59 * always pointing to memory allocated here so it can be free()'ed when no
60 * longer needed.
61 */
62__private_extern__
63void
64get_macosx_deployment_target(
65struct macosx_deployment_target *value)
66{
67    uint32_t ten, major, minor;
68    char *p, *q, *endp;
69    char osversion[32];
70    size_t osversion_len;
71    static int osversion_name[2];
72
73	/*
74	 * Pick up the Mac OS X deployment target set by the command line
75	 * or the environment variable if any.  If that does not parse out
76	 * use the default and generate a warning.  We accept "10.x" or "10.x.y"
77	 * where x and y are unsigned numbers. And x is non-zero.
78	 */
79	if(command_line_macosx_deployment_target != NULL)
80	    p = command_line_macosx_deployment_target;
81	else
82	    p = getenv("MACOSX_DEPLOYMENT_TARGET");
83	if(p != NULL){
84	    ten = strtoul(p, &endp, 10);
85	    if(*endp != '.')
86		goto use_default;
87	    if(ten != 10)
88		goto use_default;
89	    q = endp + 1;
90	    major = strtoul(q, &endp, 10);
91	    if(major == 0)
92		goto use_default;
93	    if(*endp != '.' && *endp != '\0')
94		goto use_default;
95	    if(*endp == '.'){
96		q = endp + 1;
97		minor = strtoul(q, &endp, 10);
98		if(*endp != '\0')
99		    goto use_default;
100	    }
101	    else{
102		minor = 0;
103	    }
104	    value->major = major;
105	    value->minor = minor;
106	    value->name = allocate(strlen(p) + 1);
107	    strcpy(value->name, p);
108	    return;
109	}
110
111use_default:
112	/*
113	 * The default value is the version of the running OS.
114	 */
115	osversion_name[0] = CTL_KERN;
116	osversion_name[1] = KERN_OSRELEASE;
117	osversion_len = sizeof(osversion) - 1;
118	if(sysctl(osversion_name, 2, osversion, &osversion_len, NULL, 0) == -1)
119	    system_error("sysctl for kern.osversion failed");
120
121	/*
122	 * Now parse this out.  It is expected to be of the form "x.y.z" where
123	 * x, y and z are unsigned numbers.  Where x-4 is the Mac OS X major
124	 * version number, and y is the minor version number.  We don't parse
125	 * out the value of z.
126	 */
127	major = strtoul(osversion, &endp, 10);
128	if(*endp != '.')
129	    goto bad_system_value;
130	if(major <= 4)
131	    goto bad_system_value;
132	major = major - 4;
133	q = endp + 1;
134	minor = strtoul(q, &endp, 10);
135	if(*endp != '.')
136	    goto bad_system_value;
137
138	value->major = major;
139	value->minor = minor;
140	value->name = allocate(32);
141	sprintf(value->name, "10.%u.%u", major, minor);
142	goto warn_if_bad_user_values;
143
144bad_system_value:
145	/*
146	 * As a last resort we set the default to the highest known shipping
147	 * system to date.
148	 */
149	value->major = 6;
150	value->minor = 0;
151	value->name = allocate(strlen("10.6") + 1);
152	strcpy(value->name, "10.6");
153	warning("unknown value returned by sysctl() for kern.osrelease: %s "
154		"ignored (using %s)", osversion, value->name);
155	/* fall through to also warn about a possble bad user value */
156
157warn_if_bad_user_values:
158	if(p != NULL){
159	    if(command_line_macosx_deployment_target != NULL)
160		warning("unknown -macosx_version_min parameter value: "
161			"%s ignored (using %s)", p, value->name);
162	    else
163		warning("unknown MACOSX_DEPLOYMENT_TARGET environment "
164			"variable value: %s ignored (using %s)", p,value->name);
165	}
166}
167#endif /* !defined(RLD) */
168