1 /* @(#)archconf.cc	1.2 20/04/04 Copyright 1996-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)archconf.cc	1.2 20/04/04 Copyright 1996-2020 J. Schilling";
6 #endif
7 /*
8  *	Make program
9  *	Architecture autoconfiguration support
10  *
11  *	Copyright (c) 1996-2020 by J. Schilling
12  */
13 /*
14  * CDDL HEADER START
15  *
16  * This file and its contents are supplied under the terms of the
17  * Common Development and Distribution License ("CDDL"), version 1.0.
18  * You may use this file only in accordance with the terms of version
19  * 1.0 of the CDDL.
20  *
21  * A full copy of the text of the CDDL should have accompanied this
22  * source.  A copy of the CDDL is also available via the Internet at
23  * http://www.opensource.org/licenses/cddl1.txt
24  * See the License for the specific language governing permissions
25  * and limitations under the License.
26  *
27  * When distributing Covered Code, include this CDDL HEADER in each
28  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
29  * If applicable, add the following below this CDDL HEADER, with the
30  * fields enclosed by brackets "[]" replaced with your own identifying
31  * information: Portions Copyright [yyyy] [name of copyright owner]
32  *
33  * CDDL HEADER END
34  */
35 
36 #include <schily/stdio.h>
37 #include <schily/standard.h>
38 #include <schily/unistd.h>
39 #include <schily/string.h>
40 #include <schily/ctype.h>
41 
42 #include <schily/hostname.h>
43 #include <schily/utsname.h>
44 #include <schily/systeminfo.h>
45 
46 #include <schily/errno.h>
47 
48 #define	NAMEMAX		4096	/* Max size of a name POSIX linelen */
49 #define	Uchar		unsigned char
50 #define	streql(a, b)	(strcmp((a), (b)) == 0)
51 
52 #ifdef	DO_ARCHCONF
53 extern void define_var(const char *name, const char *value);
54 extern char *get_var(const char *name);
55 
56 #ifdef	HAVE_SYS_SYSCTL_H
57 #include <schily/types.h>
58 #include <schily/param.h>
59 #include <sys/sysctl.h>
60 
61 #ifdef	HAVE_MACH_MACHINE_H
62 #include <mach/machine.h>
63 #endif
64 #ifdef	IS_MACOS_X
65 #include <mach-o/arch.h>
66 #endif
67 #endif
68 
69 #ifdef __HAIKU__
70 #include <OS.h>
71 #endif
72 
73 #include <mksh/misc.h>
74 #include <mk/defs.h>
75 
76 #ifdef	NO_SYSINFO
77 #ifdef	HAVE_SYS_SYSTEMINFO_H
78 #undef	HAVE_SYS_SYSTEMINFO_H
79 #endif
80 #endif
81 
82 EXPORT	void	setup_arch(void);
83 LOCAL	BOOL	do_uname(void);
84 LOCAL	BOOL	do_sysinfo(void);
85 LOCAL	BOOL	do_sysctl(void);
86 LOCAL	BOOL	do_haiku(void);
87 LOCAL	void	do_gethostname(void);
88 LOCAL	void	do_defs(void);
89 LOCAL	void	do_archheuristics(void);
90 LOCAL	void	archcvt(char *);
91 #if defined(HAVE_SYS_SYSTEMINFO_H) || \
92 	(defined(HAVE_SYS_SYSCTL_H) && defined(HW_MODEL)) /* See do_sysctl() */
93 LOCAL	void	unblank(char *);
94 #endif
95 
96 /*
97  * External interface to archconf.c. The code tries its best to get the
98  * architecture definitions by calling sysinfo(), uname() or by heuristic.
99  */
100 EXPORT void
setup_arch()101 setup_arch()
102 {
103 	if (!do_sysinfo() &&		/* Call sysinfo(2): preferred	*/
104 			!do_uname()) {	/* Call uname(2): still OK	*/
105 		/*
106 		 * If nothing else helps, at least try to set up $(MAKE_HOST)
107 		 * and some other macros that may be retrieved from
108 		 * CPP definitions.
109 		 */
110 		do_gethostname();	/* Try to get host name		*/
111 		do_defs();		/* Evaluate CPP definitions	*/
112 	}
113 	do_sysctl();
114 	do_haiku();
115 
116 	do_archheuristics();
117 }
118 
119 /*
120  * NeXT Step has sys/utsname but not uname()
121  */
122 #if	defined(HAVE_UNAME) || defined(__MINGW32__) || defined(_MSC_VER)
123 /*
124  * This is the interface to the syscall uname(2).
125  * Note that the system call is done directly and not by calling the uname
126  * shell command. If your system returns wrong information with the uname(2)
127  * call, you need to fix it here.
128  */
129 LOCAL BOOL
do_uname()130 do_uname()
131 {
132 	struct	utsname	un;
133 
134 	if (uname(&un) < 0) {
135 		warning(gettext("Cannot get host arch (uname): %s"),
136 		    errmsg(errno));
137 		return (FALSE);
138 	}
139 #ifdef	__comment__
140 	printf("sysname: %s nodename: %s release: %s version: %s machine: %s\n",
141 	un.sysname,
142 	un.nodename,
143 	un.release,
144 	un.version,
145 	un.machine);
146 #endif
147 	archcvt(un.sysname);
148 	archcvt(un.release);
149 	archcvt(un.version);
150 	archcvt(un.machine);
151 
152 	define_var("MAKE_OS", un.sysname);		/* uname -s */
153 	define_var("MAKE_HOST", un.nodename);		/* uname -n */
154 	define_var("MAKE_OSREL", un.release);		/* uname -r */
155 	define_var("MAKE_OSVERSION", un.version);	/* uname -v */
156 	define_var("MAKE_MACH", un.machine);		/* uname -m */
157 
158 #ifdef	HAVE_UTSNAME_PROCESSOR
159 	archcvt(un.processor);
160 	define_var("MAKE_ARCH", un.processor);		/* uname -p */
161 #else
162 #ifdef	HAVE_UTSNAME_ARCH				/* OpenVMS */
163 	archcvt(un.arch);
164 	define_var("MAKE_ARCH", un.arch);		/* uname -p */
165 #endif
166 #endif
167 #ifdef	HAVE_UTSNAME_SYSNAME_HOST
168 	archcvt(un.sysname_host);
169 	define_var("MAKE_HOST_OS", un.sysname_host);	/* uname -Hs */
170 #endif
171 #ifdef	HAVE_UTSNAME_RELEASE_HOST
172 	archcvt(un.release_host);
173 	define_var("MAKE_HOST_OSREL", un.release_host);	/* uname -Hr */
174 #endif
175 #ifdef	HAVE_UTSNAME_VERSION_HOST
176 	archcvt(un.version_host);
177 	define_var("MAKE_HOST_OSVERSION", un.version_host); /* uname -Hv */
178 #endif
179 
180 	return (TRUE);
181 }
182 #else
183 
184 /*
185  * Dummy for platforms that don't implement uname(2).
186  */
187 LOCAL BOOL
do_uname()188 do_uname()
189 {
190 	return (FALSE);
191 }
192 #endif
193 
194 #ifdef	HAVE_SYS_SYSTEMINFO_H
195 /*
196  * sysinfo(2) is the preferred way to request architecture information.
197  * Unfortunately, it is only present on SVr4 compliant systems.
198  */
199 LOCAL BOOL
do_sysinfo()200 do_sysinfo()
201 {
202 	char	nbuf[NAMEMAX];
203 	BOOL	ret = TRUE;
204 
205 #ifdef	SI_SYSNAME
206 	if (sysinfo(SI_SYSNAME, nbuf, sizeof (nbuf)) < 0) {
207 		ret = FALSE;
208 	} else {
209 		archcvt(nbuf);
210 		define_var("MAKE_OS", nbuf);		/* uname -s */
211 	}
212 #else
213 	ret = FALSE;
214 #endif
215 
216 #ifdef	SI_HOSTNAME
217 	if (sysinfo(SI_HOSTNAME, nbuf, sizeof (nbuf)) < 0) {
218 		ret = FALSE;
219 	} else {
220 		define_var("MAKE_HOST", nbuf);		/* uname -n */
221 	}
222 #else
223 	ret = FALSE;
224 #endif
225 
226 #ifdef	SI_RELEASE
227 	if (sysinfo(SI_RELEASE, nbuf, sizeof (nbuf)) < 0) {
228 		ret = FALSE;
229 	} else {
230 		archcvt(nbuf);
231 		define_var("MAKE_OSREL", nbuf);		/* uname -r */
232 	}
233 #else
234 	ret = FALSE;
235 #endif
236 
237 #ifdef	SI_VERSION
238 	if (sysinfo(SI_VERSION, nbuf, sizeof (nbuf)) < 0) {
239 		ret = FALSE;
240 	} else {
241 		archcvt(nbuf);
242 		define_var("MAKE_OSVERSION", nbuf);	/* uname -v */
243 	}
244 #else
245 	ret = FALSE;
246 #endif
247 
248 #ifdef	SI_MACHINE
249 	if (sysinfo(SI_MACHINE, nbuf, sizeof (nbuf)) < 0) {
250 		ret = FALSE;
251 	} else {
252 		archcvt(nbuf);
253 		define_var("MAKE_MACH", nbuf);		/* uname -m */
254 	}
255 #else
256 	ret = FALSE;
257 #endif
258 
259 #ifdef	SI_ARCHITECTURE
260 	if (sysinfo(SI_ARCHITECTURE, nbuf, sizeof (nbuf)) >= 0) {
261 		archcvt(nbuf);
262 		define_var("MAKE_ARCH", nbuf);		/* uname -p */
263 	}
264 #endif
265 
266 #ifdef	SI_PLATFORM
267 	if (sysinfo(SI_PLATFORM, nbuf, sizeof (nbuf)) >= 0) {
268 		unblank(nbuf);
269 		define_var("MAKE_MODEL", nbuf);		/* uname -i */
270 	}
271 #endif
272 
273 #ifdef	SI_HW_PROVIDER
274 	if (sysinfo(SI_HW_PROVIDER, nbuf, sizeof (nbuf)) >= 0) {
275 		unblank(nbuf);
276 #if 0
277 		archcvt(nbuf);
278 #endif
279 		define_var("MAKE_BRAND", nbuf);
280 	}
281 #endif
282 
283 #ifdef  SI_HW_SERIAL
284 	if (sysinfo(SI_HW_SERIAL, nbuf, sizeof (nbuf)) >= 0) {
285 #if 0
286 		archcvt(nbuf);
287 #endif
288 		define_var("MAKE_HWSERIAL", nbuf);
289 	}
290 #endif
291 
292 #ifdef  SI_SRPC_DOMAIN
293 	if (sysinfo(SI_SRPC_DOMAIN, nbuf, sizeof (nbuf)) >= 0) {
294 		define_var("MAKE_DOMAIN", nbuf);
295 	}
296 #endif
297 
298 #ifdef  SI_ISALIST
299 	if (sysinfo(SI_ISALIST, nbuf, sizeof (nbuf)) >= 0) {
300 		define_var("MAKE_ISALIST", nbuf);
301 	}
302 #endif
303 
304 	return (ret);
305 }
306 #else
307 
308 /*
309  * Dummy for platforms that don't implement sysinfo(2).
310  */
311 LOCAL BOOL
do_sysinfo()312 do_sysinfo()
313 {
314 	return (FALSE);
315 }
316 #endif
317 
318 #ifdef	HAVE_SYS_SYSCTL_H
319 /*
320  * See #ifdef statement below in unblank()
321  */
322 LOCAL BOOL
do_sysctl()323 do_sysctl()
324 {
325 #if	defined(HW_MODEL) || defined(HW_MACHINE_ARCH)
326 	const char	*name;
327 	char	nbuf[NAMEMAX];
328 	size_t	len;
329 	int	mib[2];
330 #endif
331 
332 #if	defined(HW_MODEL)
333 	name = get_var("MAKE_MODEL");
334 	if (name == NULL) {
335 		mib[0] = CTL_HW;
336 		mib[1] = HW_MODEL;
337 		len = sizeof (nbuf);
338 		if (sysctl(mib, 2, nbuf, &len, 0, 0) >= 0) {
339 			unblank(nbuf);
340 			define_var("MAKE_MODEL", nbuf);
341 		}
342 	}
343 #endif	/* defined(HW_MODEL) */
344 
345 #if	defined(HW_MACHINE_ARCH)
346 	name = get_var("MAKE_ARCH");
347 	if (name == NULL) {
348 		mib[0] = CTL_HW;
349 		mib[1] = HW_MACHINE_ARCH;
350 		len = sizeof (nbuf);
351 		if (sysctl(mib, 2, nbuf, &len, 0, 0) >= 0) {
352 			archcvt(nbuf);
353 			define_var("MAKE_ARCH", nbuf);
354 		}
355 #ifdef	IS_MACOS_X
356 		/*
357 		 * Mac OS X fails with HW_MACHINE_ARCH
358 		 */
359 		else {
360 			cpu_type_t		cputype = 0;
361 			NXArchInfo const	*ai;
362 
363 			name = NULL;
364 			len = sizeof (cputype);
365 			if (sysctlbyname("hw.cputype", &cputype, &len,
366 								NULL, 0) == 0 &&
367 			    (ai = NXGetArchInfoFromCpuType(cputype,
368 					    CPU_SUBTYPE_MULTIPLE)) != NULL) {
369 				strlcpy(nbuf, (char *)ai->name, sizeof (nbuf));
370 				archcvt(nbuf);
371 				name = nbuf;
372 			}
373 			if (cputype == CPU_TYPE_POWERPC &&
374 			    name != NULL && strncmp(name, "ppc", 3) == 0) {
375 				name = "powerpc";
376 			}
377 			if (name != NULL)
378 				define_var("MAKE_ARCH", name);
379 		}
380 #endif	/* IS_MACOS_X */
381 	}
382 #endif	/* defined(HW_MACHINE_ARCH) */
383 	return (TRUE);
384 }
385 #else
386 /*
387  * Dummy for platforms that don't implement sysctl().
388  */
389 LOCAL BOOL
do_sysctl()390 do_sysctl()
391 {
392 	return (FALSE);
393 }
394 #endif
395 
396 
397 #ifdef __HAIKU__
398 LOCAL BOOL
do_haiku()399 do_haiku()
400 {
401 	char			*archname = "unknown";
402 	cpu_topology_node_info	root;
403 	uint32			count = 1;
404 	status_t		error = get_cpu_topology_info(&root, &count);
405 
406 	if (error == B_OK && count >= 1) {
407 		switch (root.data.root.platform) {
408 
409 		case B_CPU_x86:
410 			archname = "x86";
411 			break;
412 
413 		case B_CPU_x86_64:
414 			archname = "x86_64";
415 			break;
416 
417 		case B_CPU_PPC:
418 			archname = "ppc";
419 			break;
420 
421 		case B_CPU_PPC_64:
422 			archname = "ppc64";
423 			break;
424 
425 		case B_CPU_M68K:
426 			archname = "m68k";
427 			break;
428 
429 		case B_CPU_ARM:
430 			archname = "arm";
431 			break;
432 
433 		case B_CPU_ARM_64:
434 			archname = "arm64";
435 			break;
436 
437 		case B_CPU_ALPHA:
438 			archname = "alpha";
439 			break;
440 
441 		case B_CPU_MIPS:
442 			archname = "mips";
443 			break;
444 
445 		case B_CPU_SH:
446 			archname = "sh";
447 			break;
448 
449 		default:
450 			archname = "other";
451 			break;
452 		}
453 	}
454 
455 	define_var("MAKE_ARCH", archname);
456 	return (TRUE);
457 }
458 #else
459 /*
460  * Dummy for platforms that don't implement Haiku get_cpu_topology_info().
461  */
462 LOCAL BOOL
do_haiku()463 do_haiku()
464 {
465 	return (FALSE);
466 }
467 #endif
468 
469 #ifdef	HAVE_GETHOSTNAME
470 
471 /*
472  * Don't care for systems that implement a similar functionality in
473  * sysinfo(2) or uname(2). This function is only called if
474  * sysinfo(2) or uname(2) do not exist.
475  */
476 LOCAL void
do_gethostname()477 do_gethostname()
478 {
479 	char	nbuf[NAMEMAX];
480 
481 	if (gethostname(nbuf, sizeof (nbuf)) < 0)
482 		return;
483 
484 	define_var("MAKE_HOST", nbuf);
485 }
486 #else
487 
488 /*
489  * Dummy for platforms that don't implement gethostname(2).
490  */
491 LOCAL void
do_gethostname()492 do_gethostname()
493 {
494 }
495 #endif
496 
497 /*
498  * Try to retrieve some information from CPP definitions.
499  */
500 LOCAL void
do_defs()501 do_defs()
502 {
503 #ifdef	IS_MSDOS
504 	define_var("MAKE_OS", "msdos");
505 #define	FOUND_OS
506 #endif
507 #ifdef	IS_TOS
508 	define_var("MAKE_OS", "tos");
509 #define	FOUND_OS
510 #endif
511 #ifdef	IS_MAC
512 	define_var("MAKE_OS", "macos");
513 #define	FOUND_OS
514 #endif
515 #ifdef	__NeXT__
516 	define_var("MAKE_OS", "nextstep");
517 #define	FOUND_OS
518 	define_var("MAKE_OSREL", "3.0");
519 	define_var("MAKE_OSVERSION", "1");
520 #ifdef	__ARCHITECTURE__
521 	define_var("MAKE_MACH", __ARCHITECTURE__);
522 #define	FOUND_MACH
523 #endif
524 #endif	/* __NeXT__ */
525 #ifdef	__MINGW32__
526 	define_var("MAKE_OS", "mingw32_nt");
527 #define	FOUND_OS
528 #endif
529 
530 /*
531  * We need MAKE_OS to allow compilation with the Schily Makefile System
532  */
533 #if !defined(FOUND_OS)
534 	define_var("MAKE_OS", "unknown");
535 #define	FOUND_OS
536 #endif
537 
538 #if !defined(FOUND_MACH) && defined(__mc68010)
539 	define_var("MAKE_MACH", "mc68010");
540 #define	FOUND_MACH
541 #endif
542 #if !defined(FOUND_MACH) && defined(__mc68000)
543 	define_var("MAKE_MACH", "mc68000");
544 #define	FOUND_MACH
545 #endif
546 #if !defined(FOUND_MACH) && defined(__i386)
547 	define_var("MAKE_MACH", "i386");
548 #define	FOUND_MACH
549 #endif
550 #if !defined(FOUND_MACH) && defined(__sparc)
551 	define_var("MAKE_MACH", "sparc");
552 #define	FOUND_MACH
553 #endif
554 }
555 
556 /*
557  * Do some additional heuristic for systems that are already known
558  * but may need some more macro definitions for completion.
559  */
560 LOCAL void
do_archheuristics()561 do_archheuristics()
562 {
563 	char	*name;
564 
565 	/*
566 	 * Try to define global processor architecture
567 	 */
568 	name = get_var("MAKE_ARCH");		/* uname -p is an extension */
569 	if (name == NULL) {
570 		name = get_var("MAKE_MACH");	/* Check uname -m	*/
571 		if (name != NULL) {
572 			if (strstr(name, "sun3"))
573 				define_var("MAKE_ARCH", "mc68020");
574 			if (strstr(name, "sun4"))
575 				define_var("MAKE_ARCH", "sparc");
576 			if (strstr(name, "i86pc"))
577 				define_var("MAKE_ARCH", "i386");
578 		}
579 	}
580 
581 	/*
582 	 * Try to define global machine architecture
583 	 */
584 	name = get_var("MAKE_MACH");
585 	if (name != NULL) {
586 		if (strstr(name, "sun3"))
587 			define_var("MAKE_M_ARCH", "sun3");
588 		if (strstr(name, "sun4"))
589 			define_var("MAKE_M_ARCH", "sun4");
590 		if (strstr(name, "i86pc"))
591 			define_var("MAKE_M_ARCH", "i86pc");
592 	}
593 
594 	name = get_var("MAKE_OS");
595 	if (name != NULL) {
596 		if (streql(name, "os400")) {
597 			/*
598 			 * OS400 returns serial number in uname -m
599 			 */
600 			if (get_var("MAKE_HWSERIAL") == NULL) {
601 				name = get_var("MAKE_MACH");
602 				define_var("MAKE_HWSERIAL", name);
603 			}
604 			define_var("MAKE_MACH", "powerpc");
605 		}
606 		if (streql(name, "sunos")) {
607 			name = get_var("MAKE_OSREL");
608 			if (name != NULL && name[0] >= '5')
609 				define_var("MAKE_OSDEFS", "-D__SVR4");
610 		}
611 	}
612 }
613 
614 /*
615  * Convert all characters into lower case,
616  * convert '/' into '-',
617  * convert '\\' into '-',
618  * convert ' ' into '-'.
619  */
620 LOCAL void
archcvt(register char * p)621 archcvt(register char *p)
622 {
623 	register Uchar	c;
624 
625 	while ((c = (Uchar)*p) != '\0') {
626 		if (c == '/')
627 			*p = '-';
628 		if (c == '\\')
629 			*p = '-';
630 		if (c == ' ')
631 			*p = '-';
632 		if (isupper(c))
633 			*p = tolower(c);
634 		p++;
635 	}
636 }
637 
638 #if defined(HAVE_SYS_SYSTEMINFO_H) || \
639 	(defined(HAVE_SYS_SYSCTL_H) && defined(HW_MODEL)) /* See do_sysctl() */
640 /*
641  * Convert all spaces into '-'.
642  */
643 LOCAL void
unblank(register char * p)644 unblank(register char *p)
645 {
646 	register char	c;
647 
648 	while ((c = *p) != '\0') {
649 		if (c == ' ')
650 			*p = '-';
651 		p++;
652 	}
653 }
654 #endif
655 #endif	/* DO_ARCHCONF */
656