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