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