Merge branch 'origtgz', update printf.c, sync
mirabilos authored 2 years ago
mirabilos committed 2 years ago
0 | 0 | #!/bin/sh |
1 | srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.810 2021/10/11 22:23:01 tg Exp $' | |
1 | srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.821 2022/01/28 14:26:27 tg Exp $' | |
2 | set +evx | |
2 | 3 | #- |
3 | 4 | # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | 5 | # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, |
5 | # 2020, 2021 | |
6 | # 2020, 2021, 2022 | |
6 | 7 | # mirabilos <m@mirbsd.org> |
7 | 8 | # |
8 | 9 | # Provided that these terms and disclaimer and all copyright notices |
245 | 246 | CPPFLAGS <$CPPFLAGS> |
246 | 247 | LDFLAGS <$LDFLAGS> |
247 | 248 | LIBS <$LIBS> |
249 | LDSTATIC <$LDSTATIC> | |
248 | 250 | TARGET_OS <$TARGET_OS> TARGET_OSREV <$TARGET_OSREV> |
249 | 251 | |
250 | 252 | EOF |
384 | 386 | fi |
385 | 387 | vscan= |
386 | 388 | if test $phase = u; then |
387 | test $ct = gcc && vscan='unrecogni[sz]ed' | |
388 | test $ct = hpcc && vscan='unsupported' | |
389 | test $ct = pcc && vscan='unsupported' | |
390 | test $ct = sunpro && vscan='-e ignored -e turned.off' | |
389 | case $ct in | |
390 | gcc*) vscan='unrecogni[sz]ed' ;; | |
391 | hpcc) vscan='unsupported' ;; | |
392 | pcc) vscan='unsupported' ;; | |
393 | sunpro) vscan='-e ignored -e turned.off' ;; | |
394 | esac | |
391 | 395 | fi |
392 | 396 | test_n "$vscan" && grep $vscan vv.out >/dev/null 2>&1 && fv=$fr |
393 | 397 | return 0 |
827 | 831 | ;; |
828 | 832 | AIX) |
829 | 833 | add_cppflags -D_ALL_SOURCE |
830 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
831 | 834 | ;; |
832 | 835 | BeOS) |
833 | 836 | : "${CC=gcc}" |
864 | 867 | : "${HAVE_SETRESUGID=0}" |
865 | 868 | ;; |
866 | 869 | BSD/OS) |
867 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
870 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
868 | 871 | ;; |
869 | 872 | Coherent) |
870 | 873 | oswarn="; it has major issues" |
875 | 878 | cpp_define MKSH_DISABLE_TTY_WARNING 1 |
876 | 879 | ;; |
877 | 880 | CYGWIN*) |
878 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
881 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
879 | 882 | ;; |
880 | 883 | Darwin) |
881 | 884 | add_cppflags -D_DARWIN_C_SOURCE |
887 | 890 | FreeMiNT) |
888 | 891 | oswarn="; it has minor issues" |
889 | 892 | add_cppflags -D_GNU_SOURCE |
890 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
893 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
891 | 894 | ;; |
892 | 895 | GNU) |
893 | 896 | case $CC in |
909 | 912 | cpp_define MKSH_ASSUME_UTF8 1 |
910 | 913 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
911 | 914 | HAVE_ISOFF_MKSH_ASSUME_UTF8=0 |
912 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
913 | 915 | ;; |
914 | 916 | Harvey) |
915 | 917 | add_cppflags -D_POSIX_SOURCE |
920 | 922 | cpp_define MKSH_ASSUME_UTF8 1 |
921 | 923 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
922 | 924 | HAVE_ISOFF_MKSH_ASSUME_UTF8=0 |
923 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
925 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
924 | 926 | cpp_define MKSH__NO_SYMLINK 1 |
925 | 927 | check_categories="$check_categories nosymlink" |
926 | 928 | cpp_define MKSH_NO_CMDLINE_EDITING 1 |
943 | 945 | ccpl='-Y ' |
944 | 946 | add_cppflags -D_ALL_SOURCE |
945 | 947 | : "${LIBS=-lcrypt}" |
946 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
948 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
947 | 949 | ;; |
948 | 950 | IRIX*) |
949 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
950 | 951 | ;; |
951 | 952 | Jehanne) |
952 | 953 | cpp_define MKSH_ASSUME_UTF8 1 |
953 | 954 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
954 | 955 | HAVE_ISOFF_MKSH_ASSUME_UTF8=0 |
955 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
956 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
956 | 957 | cpp_define MKSH__NO_SYMLINK 1 |
957 | 958 | check_categories="$check_categories nosymlink" |
958 | 959 | cpp_define MKSH_NO_CMDLINE_EDITING 1 |
987 | 988 | : "${HAVE_SETRESUGID=0}" |
988 | 989 | cpp_define MKSH_UNEMPLOYED 1 |
989 | 990 | oldish_ed=no-stderr-ed # no /bin/ed, maybe see below |
990 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
991 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
991 | 992 | ;; |
992 | 993 | Minix3) |
993 | 994 | add_cppflags -D_POSIX_SOURCE -D_POSIX_1_SOURCE=2 -D_MINIX |
994 | 995 | cpp_define MKSH_UNEMPLOYED 1 |
995 | 996 | oldish_ed=no-stderr-ed # /usr/bin/ed(!) is broken |
996 | : "${HAVE_SETLOCALE_CTYPE=0}${MKSH_UNLIMITED=1}" #XXX recheck ulimit | |
997 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
998 | : "${MKSH_UNLIMITED=1}" #XXX recheck ulimit | |
997 | 999 | ;; |
998 | 1000 | Minoca) |
999 | 1001 | : "${CC=gcc}" |
1007 | 1009 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
1008 | 1010 | HAVE_ISOFF_MKSH_ASSUME_UTF8=1 |
1009 | 1011 | # almost same as CYGWIN* (from RT|Chatzilla) |
1010 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1012 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1011 | 1013 | # broken on this OE (from ir0nh34d) |
1012 | 1014 | : "${HAVE_STDINT_H=0}" |
1013 | 1015 | ;; |
1031 | 1033 | Ninix3) |
1032 | 1034 | # similar to Minix3 |
1033 | 1035 | cpp_define MKSH_UNEMPLOYED 1 |
1034 | : "${MKSH_UNLIMITED=1}" #XXX recheck ulimit | |
1036 | : "${MKSH_UNLIMITED=1}" #XXX recheck ulimit | |
1035 | 1037 | # but no idea what else could be needed |
1036 | 1038 | oswarn="; it has unknown issues" |
1037 | 1039 | ;; |
1038 | 1040 | OpenBSD) |
1039 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1040 | 1041 | ;; |
1041 | 1042 | OS/2) |
1042 | 1043 | cpp_define MKSH_ASSUME_UTF8 0 |
1043 | 1044 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
1044 | 1045 | HAVE_ISOFF_MKSH_ASSUME_UTF8=1 |
1045 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1046 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1047 | # cf. https://github.com/komh/pdksh-os2/commit/590f2b19b0ff92a9a373295bce914654f9f5bf22 | |
1046 | 1048 | HAVE_TERMIOS_H=0 |
1047 | 1049 | HAVE_MKNOD=0 # setmode() incompatible |
1048 | 1050 | check_categories="$check_categories nosymlink" |
1079 | 1081 | cpp_define MKSH_ASSUME_UTF8 0 |
1080 | 1082 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
1081 | 1083 | HAVE_ISOFF_MKSH_ASSUME_UTF8=1 |
1082 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1084 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1083 | 1085 | : "${CC=xlc}" |
1084 | 1086 | : "${SIZE=: size}" |
1085 | 1087 | cpp_define MKSH_FOR_Z_OS 1 |
1086 | 1088 | add_cppflags -D_ALL_SOURCE |
1089 | $ebcdic || add_cppflags -D_ENHANCED_ASCII_EXT=0xFFFFFFFF | |
1087 | 1090 | oswarn='; EBCDIC support is incomplete' |
1088 | 1091 | ;; |
1089 | 1092 | OSF1) |
1092 | 1095 | add_cppflags -D_POSIX_C_SOURCE=200112L |
1093 | 1096 | add_cppflags -D_XOPEN_SOURCE=600 |
1094 | 1097 | add_cppflags -D_XOPEN_SOURCE_EXTENDED |
1095 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1098 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1096 | 1099 | ;; |
1097 | 1100 | Plan9) |
1098 | 1101 | add_cppflags -D_POSIX_SOURCE |
1102 | 1105 | cpp_define MKSH_ASSUME_UTF8 1 |
1103 | 1106 | HAVE_ISSET_MKSH_ASSUME_UTF8=1 |
1104 | 1107 | HAVE_ISOFF_MKSH_ASSUME_UTF8=0 |
1105 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1108 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1106 | 1109 | cpp_define MKSH__NO_SYMLINK 1 |
1107 | 1110 | check_categories="$check_categories nosymlink" |
1108 | 1111 | cpp_define MKSH_NO_CMDLINE_EDITING 1 |
1116 | 1119 | PW32*) |
1117 | 1120 | HAVE_SIG_T=0 # incompatible |
1118 | 1121 | oswarn=' and will currently not work' |
1119 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1122 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1120 | 1123 | ;; |
1121 | 1124 | QNX) |
1122 | 1125 | add_cppflags -D__NO_EXT_QNX |
1126 | 1129 | oldish_ed=no-stderr-ed # oldish /bin/ed is broken |
1127 | 1130 | ;; |
1128 | 1131 | esac |
1129 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1132 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1130 | 1133 | ;; |
1131 | 1134 | scosysv) |
1132 | 1135 | cmplrflgs=-DMKSH_MAYBE_QUICK_C |
1135 | 1138 | cpp_define MKSH_BROKEN_OFFSETOF 1 |
1136 | 1139 | cpp_define MKSH_TYPEDEF_SSIZE_T int |
1137 | 1140 | cpp_define MKSH_UNEMPLOYED 1 |
1138 | : "${HAVE_SETLOCALE_CTYPE=0}${HAVE_TERMIOS_H=0}" | |
1141 | : "${HAVE_POSIX_UTF8_LOCALE=0}${HAVE_TERMIOS_H=0}" | |
1139 | 1142 | ;; |
1140 | 1143 | SCO_SV) |
1141 | 1144 | case $TARGET_OSREV in |
1154 | 1157 | : "${HAVE_SYS_SIGLIST=0}${HAVE__SYS_SIGLIST=0}" |
1155 | 1158 | ;; |
1156 | 1159 | SerenityOS) |
1157 | oswarn="; it has major issues" | |
1158 | cpp_define MKSH_NO_SIGSUSPEND 1 | |
1159 | cpp_define MKSH_POLL_FOR_PAUSE 1 | |
1160 | oswarn="; it has issues" | |
1160 | 1161 | : "${MKSH_UNLIMITED=1}${HAVE_GETRUSAGE=0}" |
1161 | 1162 | cpp_define MKSH_UNEMPLOYED 1 |
1162 | 1163 | cpp_define MKSH_DISABLE_TTY_WARNING 1 |
1163 | cpp_define MKSH_NO_SIGSETJMP 1 | |
1164 | cpp_define _setjmp setjmp | |
1165 | cpp_define _longjmp longjmp | |
1166 | cpp_define MKSH_USABLE_SIGNALFUNC signal | |
1167 | 1164 | ;; |
1168 | 1165 | skyos) |
1169 | 1166 | oswarn="; it has minor issues" |
1180 | 1177 | ULTRIX) |
1181 | 1178 | : "${CC=cc -YPOSIX}" |
1182 | 1179 | cpp_define MKSH_TYPEDEF_SSIZE_T int |
1183 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1180 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1184 | 1181 | ;; |
1185 | 1182 | UnixWare|UNIX_SV) |
1186 | 1183 | # SCO UnixWare |
1192 | 1189 | tsts=" 3<>/dev/tty" |
1193 | 1190 | oswarn="; it will compile, but the target" |
1194 | 1191 | oswarn="$oswarn${nl}platform itself is very flakey/unreliable" |
1195 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1192 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1196 | 1193 | ;; |
1197 | 1194 | XENIX) |
1198 | 1195 | # mostly when crosscompiling from scosysv |
1212 | 1209 | cpp_define MKSH_NOPROSPECTOFWORK 1 |
1213 | 1210 | cpp_define MKSH__NO_SYMLINK 1 |
1214 | 1211 | check_categories="$check_categories nosymlink" |
1215 | : "${HAVE_SETLOCALE_CTYPE=0}" | |
1212 | : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
1216 | 1213 | # these are broken |
1217 | 1214 | HAVE_TERMIOS_H=0 |
1218 | 1215 | ;; |
1339 | 1336 | ct="clang" |
1340 | 1337 | #elif defined(__NWCC__) |
1341 | 1338 | ct="nwcc" |
1339 | #elif defined(__GNUC__) && (__GNUC__ < 2) | |
1340 | ct="gcc1" | |
1342 | 1341 | #elif defined(__GNUC__) |
1343 | 1342 | ct="gcc" |
1344 | 1343 | #elif defined(_COMPILER_VERSION) |
1365 | 1364 | const char * |
1366 | 1365 | #if defined(__KLIBC__) && !defined(__OS2__) |
1367 | 1366 | et="klibc" |
1367 | #elif defined(__dietlibc__) | |
1368 | et="dietlibc" | |
1368 | 1369 | #else |
1369 | 1370 | et="unknown" |
1370 | 1371 | #endif |
1423 | 1424 | echo >&2 " of this platform. Continue at your own risk," |
1424 | 1425 | echo >&2 " please report success/failure to the developers." |
1425 | 1426 | ;; |
1427 | gcc1) | |
1428 | vv '|' "$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS" | |
1429 | vv '|' 'eval echo "\`$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN $LIBS -dumpmachine\`" \ | |
1430 | "gcc\`$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN $LIBS -dumpversion\`"' | |
1431 | : "${HAVE_ATTRIBUTE_EXTENSION=0}" # false positive | |
1432 | ;; | |
1426 | 1433 | gcc) |
1427 | 1434 | test_z "$Cg" || Cg='-g3 -fno-builtin' |
1428 | 1435 | vv '|' "$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS" |
1460 | 1467 | own risk, please report success/failure to the developers.' |
1461 | 1468 | ;; |
1462 | 1469 | mipspro) |
1470 | test_z "$Cg" || Cg='-g3' | |
1463 | 1471 | vv '|' "$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN $LIBS -version" |
1472 | : "${HAVE_STDINT_H=0}" # broken unless building with __c99 | |
1473 | : "${HAVE_ATTRIBUTE_EXTENSION=0}" # skip checking as we know it absent | |
1464 | 1474 | ;; |
1465 | 1475 | msc) |
1466 | 1476 | ccpr= # errorlevels are not reliable |
1517 | 1527 | tendra) |
1518 | 1528 | vv '|' "$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V 2>&1 | \ |
1519 | 1529 | grep -i -e version -e release" |
1530 | : "${HAVE_ATTRIBUTE_EXTENSION=0}" # false positive | |
1520 | 1531 | ;; |
1521 | 1532 | ucode) |
1522 | 1533 | vv '|' "$CC $CFLAGS $Cg $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V" |
1556 | 1567 | ;; |
1557 | 1568 | esac |
1558 | 1569 | etd=" on $et" |
1570 | # still imake style but… can’t be helped | |
1559 | 1571 | case $et in |
1572 | dietlibc) | |
1573 | # live, BSD, live❣ | |
1574 | add_cppflags -D_BSD_SOURCE | |
1575 | # broken | |
1576 | HAVE_POSIX_UTF8_LOCALE=0 | |
1577 | ;; | |
1560 | 1578 | klibc) |
1561 | 1579 | cpp_define MKSH_NO_SIGSETJMP 1 |
1562 | 1580 | cpp_define _setjmp setjmp |
1749 | 1767 | dmc) |
1750 | 1768 | ac_flags 1 decl "${ccpc}-r" 'for strict prototype checks' |
1751 | 1769 | ac_flags 1 schk "${ccpc}-s" 'for stack overflow checking' |
1770 | ;; | |
1771 | gcc1) | |
1772 | # The following tests run with -Werror (gcc only) if possible | |
1773 | NOWARN=$DOWARN; phase=u | |
1774 | ac_flags 1 wnodeprecateddecls -Wno-deprecated-declarations | |
1775 | # we do not even use CFrustFrust in MirBSD so don’t code in it… | |
1776 | ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables | |
1777 | ac_flags 1 fnostrictaliasing -fno-strict-aliasing | |
1778 | ac_flags 1 data_abi_align -malign-data=abi | |
1779 | i=1 | |
1752 | 1780 | ;; |
1753 | 1781 | gcc) |
1754 | 1782 | ac_flags 1 fnolto -fno-lto 'whether we can explicitly disable buggy GCC LTO' -fno-lto |
1822 | 1850 | ;; |
1823 | 1851 | mipspro) |
1824 | 1852 | ac_flags 1 fullwarn -fullwarn 'for remark output support' |
1853 | # unreachable-from-prevline loop, unused variable, enum vs int @exec.c | |
1854 | # unused parameter, conversion pointer/same-sized integer | |
1855 | ac_flags 1 diagsupp '-diag_suppress 1127,1174,1185,3201,3970' 'to quieten MIPSpro down' | |
1825 | 1856 | ;; |
1826 | 1857 | msc) |
1827 | 1858 | ac_flags 1 strpool "${ccpc}/GF" 'if string pooling can be enabled' |
1902 | 1933 | # Compiler: check for stuff that only generates warnings |
1903 | 1934 | # |
1904 | 1935 | ac_test attribute_bounded attribute_extension 0 'for __attribute__((__bounded__))' <<-'EOF' |
1905 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1906 | extern int thiswillneverbedefinedIhope(void); | |
1907 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1908 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1909 | #else | |
1910 | 1936 | #include <string.h> |
1911 | 1937 | #undef __attribute__ |
1912 | 1938 | int xcopy(const void *, void *, size_t) |
1920 | 1946 | */ |
1921 | 1947 | memmove(d, s, n); return ((int)n); |
1922 | 1948 | } |
1923 | #endif | |
1924 | 1949 | EOF |
1925 | 1950 | ac_test attribute_format attribute_extension 0 'for __attribute__((__format__))' <<-'EOF' |
1926 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1927 | extern int thiswillneverbedefinedIhope(void); | |
1928 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1929 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1930 | #else | |
1931 | 1951 | #define fprintf printfoo |
1932 | 1952 | #include <stdio.h> |
1933 | 1953 | #undef __attribute__ |
1935 | 1955 | extern int fprintf(FILE *, const char *format, ...) |
1936 | 1956 | __attribute__((__format__(__printf__, 2, 3))); |
1937 | 1957 | int main(int ac, char *av[]) { return (fprintf(stderr, "%s%d", *av, ac)); } |
1938 | #endif | |
1939 | 1958 | EOF |
1940 | 1959 | ac_test attribute_noreturn attribute_extension 0 'for __attribute__((__noreturn__))' <<-'EOF' |
1941 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1942 | extern int thiswillneverbedefinedIhope(void); | |
1943 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1944 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1945 | #else | |
1946 | 1960 | #include <stdlib.h> |
1947 | 1961 | #undef __attribute__ |
1948 | 1962 | void fnord(void) __attribute__((__noreturn__)); |
1949 | 1963 | int main(void) { fnord(); } |
1950 | 1964 | void fnord(void) { exit(0); } |
1951 | #endif | |
1952 | 1965 | EOF |
1953 | 1966 | ac_test attribute_pure attribute_extension 0 'for __attribute__((__pure__))' <<-'EOF' |
1954 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1955 | extern int thiswillneverbedefinedIhope(void); | |
1956 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1957 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1958 | #else | |
1959 | 1967 | #include <unistd.h> |
1960 | 1968 | #undef __attribute__ |
1961 | 1969 | int foo(const char *) __attribute__((__pure__)); |
1962 | 1970 | int main(int ac, char *av[]) { return (foo(av[ac - 1]) + isatty(0)); } |
1963 | 1971 | int foo(const char *s) { return ((int)s[0]); } |
1964 | #endif | |
1965 | 1972 | EOF |
1966 | 1973 | ac_test attribute_unused attribute_extension 0 'for __attribute__((__unused__))' <<-'EOF' |
1967 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1968 | extern int thiswillneverbedefinedIhope(void); | |
1969 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1970 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1971 | #else | |
1972 | 1974 | #include <unistd.h> |
1973 | 1975 | #undef __attribute__ |
1974 | 1976 | int main(int ac __attribute__((__unused__)), char *av[] |
1975 | 1977 | __attribute__((__unused__))) { return (isatty(0)); } |
1976 | #endif | |
1977 | 1978 | EOF |
1978 | 1979 | ac_test attribute_used attribute_extension 0 'for __attribute__((__used__))' <<-'EOF' |
1979 | #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) | |
1980 | extern int thiswillneverbedefinedIhope(void); | |
1981 | /* force a failure: TenDRA and gcc 1.42 have false positive here */ | |
1982 | int main(void) { return (thiswillneverbedefinedIhope()); } | |
1983 | #else | |
1984 | 1980 | #include <unistd.h> |
1985 | 1981 | #undef __attribute__ |
1986 | 1982 | static const char fnord[] __attribute__((__used__)) = "42"; |
1987 | 1983 | int main(void) { return (isatty(0)); } |
1988 | #endif | |
1989 | 1984 | EOF |
1990 | 1985 | |
1991 | 1986 | # End of tests run with -Werror |
2011 | 2006 | "if mksh will be built without job signals" && \ |
2012 | 2007 | check_categories="$check_categories arge nojsig" |
2013 | 2008 | ac_ifcpp 'ifdef MKSH_ASSUME_UTF8' isset_MKSH_ASSUME_UTF8 '' \ |
2014 | 'if the default UTF-8 mode is specified' && : "${HAVE_SETLOCALE_CTYPE=0}" | |
2009 | 'if the default UTF-8 mode is specified' && : "${HAVE_POSIX_UTF8_LOCALE=0}" | |
2015 | 2010 | ac_ifcpp 'if !MKSH_ASSUME_UTF8' isoff_MKSH_ASSUME_UTF8 \ |
2016 | 2011 | isset_MKSH_ASSUME_UTF8 0 \ |
2017 | 2012 | 'if the default UTF-8 mode is disabled' && \ |
2073 | 2068 | # |
2074 | 2069 | echo '#include <sys/types.h> |
2075 | 2070 | #include <unistd.h> |
2076 | /* check that off_t can represent 2^63-1 correctly, thx FSF */ | |
2077 | #define LARGE_OFF_T ((((off_t)1 << 31) << 31) - 1 + (((off_t)1 << 31) << 31)) | |
2078 | int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && | |
2079 | LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; | |
2080 | int main(void) { return (isatty(0)); }' >lft.c | |
2071 | struct ctassert_offt { | |
2072 | off_t min63bits:63; | |
2073 | }; | |
2074 | int main(void) { return ((int)sizeof(struct ctassert_offt)); }' >lft.c | |
2081 | 2075 | ac_testn can_lfs '' "for large file support" <lft.c |
2082 | 2076 | save_CPPFLAGS=$CPPFLAGS |
2083 | 2077 | add_cppflags -D_FILE_OFFSET_BITS=64 |
2096 | 2090 | # |
2097 | 2091 | ac_test can_inttypes '!' stdint_h 1 "for standard 32-bit integer types" <<-'EOF' |
2098 | 2092 | #include <sys/types.h> |
2093 | #include <limits.h> | |
2099 | 2094 | #include <stddef.h> |
2100 | int main(int ac, char *av[]) { return ((uint32_t)(size_t)*av + (int32_t)ac); } | |
2101 | EOF | |
2102 | ac_test can_ucbints '!' can_inttypes 1 "for UCB 32-bit integer types" <<-'EOF' | |
2103 | #include <sys/types.h> | |
2104 | #include <stddef.h> | |
2105 | int main(int ac, char *av[]) { return ((u_int32_t)(size_t)*av + (int32_t)ac); } | |
2095 | int main(int ac, char *av[]) { | |
2096 | return ((int)((uint32_t)(size_t)*av + | |
2097 | ((int32_t)ac - INT32_MAX))); | |
2098 | } | |
2106 | 2099 | EOF |
2107 | 2100 | |
2108 | 2101 | # only testn: added later below |
2193 | 2186 | # |
2194 | 2187 | # Environment: errors and signals |
2195 | 2188 | # |
2196 | test x"NetBSD" = x"$TARGET_OS" && $e Ignore the compatibility warning. | |
2197 | ||
2198 | ac_testn sys_errlist '' "the sys_errlist[] array and sys_nerr" <<-'EOF' | |
2189 | ||
2190 | HAVE_SOME_ERRLIST=0 | |
2191 | ||
2192 | ac_test strerrordesc_np '!' some_errlist 0 "GNU strerrordesc_np()" <<-'EOF' | |
2193 | extern const char *strerrordesc_np(int); | |
2194 | int main(int ac, char *av[]) { return (*strerrordesc_np(*av[ac])); } | |
2195 | EOF | |
2196 | test 1 = "$HAVE_STRERRORDESC_NP" && HAVE_SOME_ERRLIST=1 | |
2197 | ||
2198 | ac_testn sys_errlist '!' some_errlist 0 "the sys_errlist[] array and sys_nerr" <<-'EOF' | |
2199 | 2199 | extern const int sys_nerr; |
2200 | 2200 | extern const char * const sys_errlist[]; |
2201 | 2201 | extern int isatty(int); |
2202 | 2202 | int main(void) { return (*sys_errlist[sys_nerr - 1] + isatty(0)); } |
2203 | 2203 | EOF |
2204 | ac_testn _sys_errlist '!' sys_errlist 0 "the _sys_errlist[] array and _sys_nerr" <<-'EOF' | |
2204 | test 1 = "$HAVE_SYS_ERRLIST" && HAVE_SOME_ERRLIST=1 | |
2205 | ||
2206 | ac_testn _sys_errlist '!' some_errlist 0 "the _sys_errlist[] array and _sys_nerr" <<-'EOF' | |
2205 | 2207 | extern const int _sys_nerr; |
2206 | 2208 | extern const char * const _sys_errlist[]; |
2207 | 2209 | extern int isatty(int); |
2211 | 2213 | cpp_define sys_nerr _sys_nerr |
2212 | 2214 | cpp_define sys_errlist _sys_errlist |
2213 | 2215 | HAVE_SYS_ERRLIST=1 |
2214 | fi | |
2216 | HAVE_SOME_ERRLIST=1 | |
2217 | fi | |
2218 | ||
2215 | 2219 | ac_cppflags SYS_ERRLIST |
2216 | 2220 | |
2217 | 2221 | for what in name list; do |
2218 | 2222 | uwhat=`upper $what` |
2219 | ac_testn sys_sig$what '' "the sys_sig$what[] array" <<-EOF | |
2223 | eval HAVE_SOME_SIG$uwhat=0 | |
2224 | ||
2225 | case $what in name) x=sigabbrev_np ;; list) x=sigdescr_np ;; esac | |
2226 | ac_test $x '!' some_sig$what 0 "GNU $x()" <<-EOF | |
2227 | extern const char *$x(int); | |
2228 | int main(int ac, char *av[]) { return (*$x(*av[ac])); } | |
2229 | EOF | |
2230 | test x"1" = x"$fv" && eval HAVE_SOME_SIG$uwhat=1 | |
2231 | ||
2232 | ac_testn sys_sig$what '!' some_sig$what 0 "the sys_sig$what[] array" <<-EOF | |
2220 | 2233 | extern const char * const sys_sig$what[]; |
2221 | 2234 | extern int isatty(int); |
2222 | 2235 | int main(void) { return (sys_sig$what[0][0] + isatty(0)); } |
2223 | 2236 | EOF |
2224 | ac_testn _sys_sig$what '!' sys_sig$what 0 "the _sys_sig$what[] array" <<-EOF | |
2237 | test x"1" = x"$fv" && eval HAVE_SOME_SIG$uwhat=1 | |
2238 | ||
2239 | ac_testn _sys_sig$what '!' some_sig$what 0 "the _sys_sig$what[] array" <<-EOF | |
2225 | 2240 | extern const char * const _sys_sig$what[]; |
2226 | 2241 | extern int isatty(int); |
2227 | 2242 | int main(void) { return (_sys_sig$what[0][0] + isatty(0)); } |
2228 | 2243 | EOF |
2229 | eval uwhat_v=\$HAVE__SYS_SIG$uwhat | |
2230 | if test 1 = "$uwhat_v"; then | |
2244 | if test x"1" = x"$fv"; then | |
2231 | 2245 | cpp_define sys_sig$what _sys_sig$what |
2232 | 2246 | eval HAVE_SYS_SIG$uwhat=1 |
2247 | eval HAVE_SOME_SIG$uwhat=1 | |
2233 | 2248 | fi |
2234 | 2249 | ac_cppflags SYS_SIG$uwhat |
2235 | 2250 | done |
2380 | 2395 | int main(int ac, char *av[]) { return (ac + revoke(av[0])); } |
2381 | 2396 | EOF |
2382 | 2397 | |
2383 | ac_test setlocale_ctype '' 'setlocale(LC_CTYPE, "")' <<-'EOF' | |
2398 | ac_test posix_utf8_locale '' 'for setlocale(LC_CTYPE, "") and nl_langinfo(CODESET)' <<-'EOF' | |
2384 | 2399 | #include <locale.h> |
2385 | #include <stddef.h> | |
2386 | int main(void) { return ((int)(size_t)(void *)setlocale(LC_CTYPE, "")); } | |
2387 | EOF | |
2388 | ||
2389 | ac_test langinfo_codeset setlocale_ctype 0 'nl_langinfo(CODESET)' <<-'EOF' | |
2390 | 2400 | #include <langinfo.h> |
2391 | #include <stddef.h> | |
2392 | int main(void) { return ((int)(size_t)(void *)nl_langinfo(CODESET)); } | |
2401 | int main(void) { return (!setlocale(LC_CTYPE, "") || !nl_langinfo(CODESET)); } | |
2402 | EOF | |
2403 | ||
2404 | $ebcdic && ac_test setlocale_lcall <<-'EOF' | |
2405 | #include <locale.h> | |
2406 | int main(void) { return (!setlocale(LC_ALL, "")); } | |
2393 | 2407 | EOF |
2394 | 2408 | |
2395 | 2409 | ac_test select <<-'EOF' |
2489 | 2503 | fi |
2490 | 2504 | fi |
2491 | 2505 | |
2492 | ac_test strerror '!' sys_errlist 0 <<-'EOF' | |
2506 | ac_test strerror '!' some_errlist 0 <<-'EOF' | |
2493 | 2507 | extern char *strerror(int); |
2494 | 2508 | int main(int ac, char *av[]) { return (*strerror(*av[ac])); } |
2495 | 2509 | EOF |
2496 | 2510 | |
2497 | ac_test strsignal '!' sys_siglist 0 <<-'EOF' | |
2511 | ac_test strsignal '!' some_siglist 0 <<-'EOF' | |
2498 | 2512 | #include <string.h> |
2499 | 2513 | #include <signal.h> |
2500 | 2514 | int main(void) { return (strsignal(1)[0]); } |
2584 | 2598 | #ifndef CHAR_BIT |
2585 | 2599 | #define CHAR_BIT 0 |
2586 | 2600 | #endif |
2587 | struct ctasserts { | |
2588 | #define cta(name,assertion) char name[(assertion) ? 1 : -1] | |
2589 | cta(char_is_8_bits, (CHAR_BIT) == 8); | |
2590 | cta(long_is_32_bits, sizeof(long) == 4); | |
2601 | mbiCTAS(conftest) { | |
2602 | mbiCTA(char_is_8_bits, (CHAR_BIT) == 8); | |
2603 | mbiCTA(long_is_4_chars, sizeof(long) == 4); | |
2604 | mbiCTA(ulong_is_32_bits, mbiTYPE_UBITS(unsigned long) == 32U); | |
2605 | mbiCTA(slong_is_31_bits, mbiMASK_BITS(LONG_MAX) == 31U); | |
2591 | 2606 | }; |
2592 | int main(void) { return (sizeof(struct ctasserts)); } | |
2607 | int main(void) { return (sizeof(struct ctassert_conftest)); } | |
2593 | 2608 | EOF |
2594 | 2609 | |
2595 | 2610 | ac_test long_64bit '!' long_32bit 0 'whether long is 64 bit wide' <<-'EOF' |
2598 | 2613 | #ifndef CHAR_BIT |
2599 | 2614 | #define CHAR_BIT 0 |
2600 | 2615 | #endif |
2601 | struct ctasserts { | |
2602 | #define cta(name,assertion) char name[(assertion) ? 1 : -1] | |
2603 | cta(char_is_8_bits, (CHAR_BIT) == 8); | |
2604 | cta(long_is_64_bits, sizeof(long) == 8); | |
2616 | mbiCTAS(conftest) { | |
2617 | mbiCTA(char_is_8_bits, (CHAR_BIT) == 8); | |
2618 | mbiCTA(long_is_8_chars, sizeof(long) == 8); | |
2619 | mbiCTA(ulong_is_64_bits, mbiTYPE_UBITS(unsigned long) == 64U); | |
2620 | mbiCTA(slong_is_63_bits, mbiMASK_BITS(LONG_MAX) == 63U); | |
2605 | 2621 | }; |
2606 | int main(void) { return (sizeof(struct ctasserts)); } | |
2622 | int main(void) { return (sizeof(struct ctassert_conftest)); } | |
2607 | 2623 | EOF |
2608 | 2624 | |
2609 | 2625 | case $HAVE_LONG_32BIT$HAVE_LONG_64BIT in |
2616 | 2632 | # |
2617 | 2633 | # Compiler: Praeprocessor (only if needed) |
2618 | 2634 | # |
2619 | test 0 = $HAVE_SYS_SIGNAME && if ac_testinit cpp_dd '' \ | |
2635 | test 0 = $HAVE_SOME_SIGNAME && if ac_testinit cpp_dd '' \ | |
2620 | 2636 | 'checking if the C Preprocessor supports -dD'; then |
2621 | 2637 | echo '#define foo bar' >conftest.c |
2622 | 2638 | vv ']' "$CPP $CFLAGS $Cg $CPPFLAGS $NOWARN -dD conftest.c >x" |
2637 | 2653 | check_categories="$check_categories $oldish_ed" |
2638 | 2654 | rmf x vv.out |
2639 | 2655 | |
2640 | if test 0 = $HAVE_SYS_SIGNAME; then | |
2656 | if test 0 = $HAVE_SOME_SIGNAME; then | |
2641 | 2657 | if test 1 = $HAVE_CPP_DD; then |
2642 | 2658 | $e Generating list of signal names... |
2643 | 2659 | else |
2908 | 2924 | echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh |
2909 | 2925 | if test $cm = makefile; then |
2910 | 2926 | extras='emacsfn.h exprtok.h rlimits.opt sh.h sh_flags.opt ulimits.opt var_spec.h' |
2911 | test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc" | |
2927 | test 0 = $HAVE_SOME_SIGNAME && extras="$extras signames.inc" | |
2912 | 2928 | gens= genq= |
2913 | 2929 | for file in $optfiles; do |
2914 | 2930 | genf=`basename "$file" | sed 's/.opt$/.gen/'` |
0 | # $MirOS: src/bin/mksh/check.t,v 1.883 2021/10/10 21:33:50 tg Exp $ | |
0 | # $MirOS: src/bin/mksh/check.t,v 1.892 2022/01/28 10:28:14 tg Exp $ | |
1 | 1 | # -*- mode: sh -*- |
2 | 2 | #- |
3 | 3 | # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
30 | 30 | # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date |
31 | 31 | |
32 | 32 | expected-stdout: |
33 | KSH R59 2021/10/15 | |
33 | KSH R59 2022/01/27 | |
34 | 34 | description: |
35 | 35 | Check base version of full shell |
36 | 36 | stdin: |
440 | 440 | expected-stderr: |
441 | 441 | 1 |
442 | 442 | --- |
443 | name: arith-divnull | |
444 | description: | |
445 | Check what happens if dividing by 0 | |
446 | stdin: | |
447 | echo 1 $((0 ? 2/0 : 666)) . | |
448 | echo 2 $? | |
449 | echo 3 $((1 ? 2/0 : 666)) . | |
450 | echo 4 $? | |
451 | expected-stdout: | |
452 | 1 666 . | |
453 | 2 0 | |
454 | expected-exit: e != 0 | |
455 | expected-stderr-pattern: | |
456 | /^[^\n]*: zero divisor$/ | |
457 | --- | |
443 | 458 | name: arith-lazy-1 |
444 | 459 | description: |
445 | 460 | Check that only one side of ternary operator is evaluated |
611 | 626 | name: arith-div-intmin-by-minusone |
612 | 627 | description: |
613 | 628 | Check division overflow wraps around silently |
614 | category: int:32 | |
629 | category: shell:legacy-no | |
615 | 630 | stdin: |
616 | 631 | echo signed:$((-2147483648 / -1))r$((-2147483648 % -1)). |
617 | 632 | echo unsigned:$((# -2147483648 / -1))r$((# -2147483648 % -1)). |
618 | 633 | expected-stdout: |
619 | 634 | signed:-2147483648r0. |
620 | 635 | unsigned:0r2147483648. |
621 | --- | |
622 | name: arith-div-intmin-by-minusone-64 | |
623 | description: | |
624 | Check division overflow wraps around silently | |
625 | category: int:64 | |
626 | stdin: | |
627 | echo signed:$((-9223372036854775808 / -1))r$((-9223372036854775808 % -1)). | |
628 | echo unsigned:$((# -9223372036854775808 / -1))r$((# -9223372036854775808 % -1)). | |
629 | expected-stdout: | |
630 | signed:-9223372036854775808r0. | |
631 | unsigned:0r9223372036854775808. | |
632 | 636 | --- |
633 | 637 | name: arith-assop-assoc-1 |
634 | 638 | description: |
1492 | 1496 | XXX=_ |
1493 | 1497 | PS1=X |
1494 | 1498 | false && echo hmmm |
1495 | need-ctty: yes | |
1496 | 1499 | arguments: !-i! |
1497 | 1500 | stdin: |
1498 | 1501 | echo hi${XXX}there |
1499 | 1502 | expected-stdout: |
1500 | 1503 | hi_there |
1501 | expected-stderr: ! | |
1502 | XX | |
1504 | expected-stderr-pattern: | |
1505 | /^(?:W: [^\n]*(?:find tty fd|have full job control)[^\n]*\n)*XX$/ | |
1503 | 1506 | --- |
1504 | 1507 | name: expand-ugly |
1505 | 1508 | description: |
5081 | 5084 | Syntax errors in expressions and effects on bases |
5082 | 5085 | (interactive so errors don't cause exits) |
5083 | 5086 | (ksh88 fails this test - shell exits, even with -i) |
5084 | need-ctty: yes | |
5085 | 5087 | arguments: !-i! |
5086 | 5088 | stdin: |
5087 | 5089 | PS1= # minimise prompt hassles |
5092 | 5094 | typeset -i2 a=2+ |
5093 | 5095 | echo $a |
5094 | 5096 | expected-stderr-pattern: |
5095 | /^([#\$] )?.*:.*2+.*\n.*:.*2+.*\n$/ | |
5097 | /^(?:W: [^\n]*(?:find tty fd|have full job control)[^\n]*\n)*([#\$] )?.*:.*2\+.*\n.*:.*2\+.*\n$/ | |
5096 | 5098 | expected-stdout: |
5097 | 5099 | 4#22 |
5098 | 5100 | 4#22 |
5598 | 5600 | echo =1 |
5599 | 5601 | trap "echo trap 2 executed" UNKNOWNSIGNAL EXIT 999999 FNORD |
5600 | 5602 | echo = $? |
5601 | ) 2>&1 | sed "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG" | |
5602 | expected-stdout: | |
5603 | PROG: trap: bad signal 'UNKNOWNSIGNAL' | |
5603 | ) 2>&1 | sed \ | |
5604 | -e "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG" \ | |
5605 | -e "s^[EW]: ${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG" \ | |
5606 | -e "s/bad signal '\\(.*\\)'\$/bad signal: \\1/" | |
5607 | expected-stdout: | |
5608 | PROG: trap: bad signal: UNKNOWNSIGNAL | |
5604 | 5609 | foo |
5605 | 5610 | =1 |
5606 | PROG: trap: bad signal 'UNKNOWNSIGNAL' | |
5607 | PROG: trap: bad signal '999999' | |
5608 | PROG: trap: bad signal 'FNORD' | |
5611 | PROG: trap: bad signal: UNKNOWNSIGNAL | |
5612 | PROG: trap: bad signal: 999999 | |
5613 | PROG: trap: bad signal: FNORD | |
5609 | 5614 | = 1 |
5610 | 5615 | trap 2 executed |
5611 | 5616 | --- |
6339 | 6344 | --- |
6340 | 6345 | name: regression-42 |
6341 | 6346 | description: |
6342 | Can't use command line assignments to assign readonly parameters. | |
6347 | Can't use command line assignments to assign read-only parameters. | |
6343 | 6348 | stdin: |
6344 | 6349 | print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \ |
6345 | 6350 | 'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \ |
6976 | 6981 | echo 1 $(( a ^<= 1 )) , $(( b ^<= 1 )) . |
6977 | 6982 | echo 2 $(( a ^>= 2 )) , $(( b ^>= 2 )) . |
6978 | 6983 | echo 3 $(( 5 ^< 1 )) . |
6979 | echo 4 $(( 5 ^> 1 )) . | |
6984 | echo 4 $(( 5 ^> 1 )) , $((# 5 ^> 1 )) . | |
6980 | 6985 | expected-stdout: |
6981 | 6986 | 1 10 , 11 . |
6982 | 6987 | 2 -2147483646 , -1073741822 . |
6983 | 6988 | 3 10 . |
6984 | 4 -2147483646 . | |
6989 | 4 -2147483646 , 2147483650 . | |
6985 | 6990 | --- |
6986 | 6991 | name: export-1 |
6987 | 6992 | description: |
7543 | 7548 | description: |
7544 | 7549 | Check special names are output correctly |
7545 | 7550 | stdin: |
7551 | prgsub() { | |
7552 | sed \ | |
7553 | -e "s^${__progname%.exe}\.*e*x*e*: PROG: " \ | |
7554 | -e "s^[EW]: ${__progname%.exe}\.*e*x*e*: PROG: " \ | |
7555 | -e 's/^qmark_foo: /E: &/' \ | |
7556 | -e "s/^/$1: /g" | |
7557 | } | |
7546 | 7558 | doit() { |
7547 | 7559 | "$__progname" -c "$@" >o1 2>o2 |
7548 | 7560 | rv=$? |
7549 | 7561 | echo RETVAL: $rv |
7550 | sed -e "s^${__progname%.exe}\.*e*x*e*: PROG: " -e 's/^/STDOUT: /g' <o1 | |
7551 | sed -e "s^${__progname%.exe}\.*e*x*e*: PROG: " -e 's/^/STDERR: /g' <o2 | |
7562 | prgsub STDOUT <o1 | |
7563 | prgsub STDERR <o2 | |
7552 | 7564 | } |
7553 | 7565 | doit 'echo ${1x}' |
7554 | 7566 | doit 'echo "${1x}"' |
7555 | 7567 | doit 'echo ${1?}' |
7556 | 7568 | doit 'echo ${19?}' |
7557 | 7569 | doit 'echo ${!:?}' |
7558 | doit -u 'echo ${*:?}' foo "" | |
7570 | doit -u 'echo ${*:?}' qmark_foo "" | |
7559 | 7571 | expected-stdout: |
7560 | 7572 | RETVAL: 1 |
7561 | 7573 | STDERR: PROG: ${1x}: bad substitution |
7568 | 7580 | RETVAL: 1 |
7569 | 7581 | STDERR: PROG: !: parameter null or not set |
7570 | 7582 | RETVAL: 1 |
7571 | STDERR: foo: ${*:?}: bad substitution | |
7583 | STDERR: E: qmark_foo: ${*:?}: bad substitution | |
7572 | 7584 | --- |
7573 | 7585 | name: xxx-param-_-1 |
7574 | 7586 | # fails due to weirdness of execv stuff |
8056 | 8068 | Check that ERR and EXIT traps are run just like GNU bash does. |
8057 | 8069 | ksh93 runs ERtrap after “parameter null or not set” (which mksh |
8058 | 8070 | used to do) but (bug) continues “and out”, exit 0, in +e eval-undef. |
8059 | file-setup: file 644 "x" | |
8071 | file-setup: file 644 "xe" | |
8060 | 8072 | v=; unset v |
8061 | 8073 | trap 'echo EXtrap' EXIT |
8062 | 8074 | trap 'echo ERtrap' ERR |
8097 | 8109 | ) 2>&1 | sed \ |
8098 | 8110 | -e 's/parameter not set/parameter null or not set/' \ |
8099 | 8111 | -e 's/[[]6]//' -e 's/: eval: line 1//' -e 's/: line 6//' \ |
8112 | -e 's/^x[etfu]: /E: &/' \ | |
8100 | 8113 | -e "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG" |
8101 | 8114 | } |
8102 | 8115 | xe=-e |
8103 | 8116 | echo : $xe |
8104 | runtest x $xe true | |
8117 | runtest xe $xe true | |
8105 | 8118 | echo = eval-true $(<rc) . |
8106 | runtest x $xe false | |
8119 | runtest xe $xe false | |
8107 | 8120 | echo = eval-false $(<rc) . |
8108 | runtest x $xe '${v?}' | |
8121 | runtest xe $xe '${v?}' | |
8109 | 8122 | echo = eval-undef $(<rc) . |
8110 | 8123 | runtest xt $xe |
8111 | 8124 | echo = noeval-true $(<rc) . |
8115 | 8128 | echo = noeval-undef $(<rc) . |
8116 | 8129 | xe=+e |
8117 | 8130 | echo : $xe |
8118 | runtest x $xe true | |
8131 | runtest xe $xe true | |
8119 | 8132 | echo = eval-true $(<rc) . |
8120 | runtest x $xe false | |
8133 | runtest xe $xe false | |
8121 | 8134 | echo = eval-false $(<rc) . |
8122 | runtest x $xe '${v?}' | |
8135 | runtest xe $xe '${v?}' | |
8123 | 8136 | echo = eval-undef $(<rc) . |
8124 | 8137 | runtest xt $xe |
8125 | 8138 | echo = noeval-true $(<rc) . |
8138 | 8151 | EXtrap |
8139 | 8152 | = eval-false 1 . |
8140 | 8153 | and run ${v?} |
8141 | x: v: parameter null or not set | |
8154 | E: xe: v: parameter null or not set | |
8142 | 8155 | EXtrap |
8143 | 8156 | = eval-undef 1 . |
8144 | 8157 | and run true |
8150 | 8163 | EXtrap |
8151 | 8164 | = noeval-false 1 . |
8152 | 8165 | and run ${v?} |
8153 | xu: v: parameter null or not set | |
8166 | E: xu: v: parameter null or not set | |
8154 | 8167 | EXtrap |
8155 | 8168 | = noeval-undef 1 . |
8156 | 8169 | : +e |
8165 | 8178 | EXtrap |
8166 | 8179 | = eval-false 0 . |
8167 | 8180 | and run ${v?} |
8168 | x: v: parameter null or not set | |
8181 | E: xe: v: parameter null or not set | |
8169 | 8182 | EXtrap |
8170 | 8183 | = eval-undef 1 . |
8171 | 8184 | and run true |
8178 | 8191 | EXtrap |
8179 | 8192 | = noeval-false 0 . |
8180 | 8193 | and run ${v?} |
8181 | xu: v: parameter null or not set | |
8194 | E: xu: v: parameter null or not set | |
8182 | 8195 | EXtrap |
8183 | 8196 | = noeval-undef 1 . |
8184 | 8197 | --- |
9056 | 9069 | name: utf8opt-2 |
9057 | 9070 | description: |
9058 | 9071 | Check that the utf8-mode flag is set at interactive startup. |
9059 | If your OS is old, try passing HAVE_SETLOCALE_CTYPE=0 to Build.sh | |
9072 | If your OS is old and fails this, contact the mksh developer. | |
9060 | 9073 | need-pass: no |
9061 | 9074 | category: !noutf8 |
9062 | 9075 | need-ctty: yes |
10056 | 10069 | unset baz |
10057 | 10070 | print ${foo@#} ${bar@#} ${baz@#} . |
10058 | 10071 | expected-stdout: |
10059 | 9B15FBFB CFBDD32B 00000000 . | |
10072 | D2F7C7B5 FE93FA63 03010102 . | |
10060 | 10073 | --- |
10061 | 10074 | name: varexpand-special-hash-ebcdic |
10062 | 10075 | description: |
10068 | 10081 | unset baz |
10069 | 10082 | print ${foo@#} ${bar@#} ${baz@#} . |
10070 | 10083 | expected-stdout: |
10071 | 016AE33D 9769C4AF 00000000 . | |
10084 | 7819D62A E1FC0712 00000000 . | |
10072 | 10085 | --- |
10073 | 10086 | name: varexpand-special-quote |
10074 | 10087 | description: |
11376 | 11389 | expected-stdout: |
11377 | 11390 | === |
11378 | 11391 | mir |
11379 | expected-stderr-pattern: /.*: can't (create|overwrite) .*/ | |
11392 | expected-stderr-pattern: /.*: foo: (create: |cannot overwrite existing file).*/ | |
11380 | 11393 | --- |
11381 | 11394 | name: bashiop-3b |
11382 | 11395 | description: |
13115 | 13128 | echo =14 |
13116 | 13129 | (mypid=$$; try mypid) |
13117 | 13130 | echo =15 |
13118 | ) 2>&1 | sed -e 's/^[A-Za-z]://' -e 's/^[^]]*]//' -e 's/^[^:]*: *//' | |
13131 | ) 2>&1 | sed \ | |
13132 | -e "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROGl" \ | |
13133 | -e "s^[EW]: ${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROGl" \ | |
13134 | -e "s^${__progname%.exe}\.*e*x*e*: PROGn: " \ | |
13135 | -e "s^[EW]: ${__progname%.exe}\.*e*x*e*: PROGn: " | |
13119 | 13136 | exit ${PIPESTATUS[0]} |
13120 | 13137 | expected-stdout: |
13121 | 13138 | y |
13122 | 13139 | =1 |
13123 | y: parameter not set | |
13140 | PROGl: y: parameter not set | |
13124 | 13141 | =2 |
13125 | 13142 | x=nz |
13126 | 13143 | =3 |
13127 | y: parameter not set | |
13144 | PROGn: y: parameter not set | |
13128 | 13145 | =4 |
13129 | 13146 | 0=nz |
13130 | 13147 | =5 |
13131 | 2: parameter not set | |
13148 | PROGn: 2: parameter not set | |
13132 | 13149 | =6 |
13133 | 1: parameter not set | |
13150 | PROGl: 1: parameter not set | |
13134 | 13151 | =7 |
13135 | 13152 | at= |
13136 | 13153 | =8 |
13138 | 13155 | =9 |
13139 | 13156 | 0 |
13140 | 13157 | =10 |
13141 | !: parameter not set | |
13158 | PROGl: !: parameter not set | |
13142 | 13159 | =11 |
13143 | 13160 | ush |
13144 | 13161 | =12 |
14052 | 14069 | [[ -o utf8-mode ]]; local u=$? |
14053 | 14070 | set +U |
14054 | 14071 | local c s="$*" t= |
14055 | [[ -n $s ]] || { s=$(cat;print x); s=${s%x}; } | |
14072 | [[ -n $s ]] || { s=$(cat;print .); s=${s%.}; } | |
14056 | 14073 | local -i i=0 n=${#s} p=0 v x |
14057 | 14074 | local -i16 o |
14058 | 14075 |
0 | 0 | mksh (59c-15) unstable; urgency=medium |
1 | 1 | |
2 | 2 | * Require usable libklibc-dev (cf. #1004465) |
3 | ||
4 | -- Thorsten Glaser <tg@mirbsd.de> Fri, 28 Jan 2022 05:17:28 +0100 | |
3 | * Update to CVS HEAD: | |
4 | - [tg, Redfoxmoon] Fixes for the MIPSpro compiler | |
5 | - [tg] Clean up the pre-initio() codepaths | |
6 | - [tg] Advance less-UB-y arithmetics project: shf_vfprintf et al. | |
7 | - [tg] Overhaul error reporting functions avoiding some name doubling | |
8 | - [tg] Fix if FCEDIT when TMPDIR contains whitespace | |
9 | - [tg] Tighten locale and charset checks | |
10 | - [tg] Handle gracefully users doing integer EPOCHREALTIME= | |
11 | - [tg] Fix newer GCC warning on compile-time asserts | |
12 | - [tg] Support GNU strerrordesc_np(3) replacement for _sys_errlist[] | |
13 | - [tg] Better configure-time detection (TenDRA, dietlibc, …) | |
14 | - [tg] Fix possible setsid(2) failure in chvt code by always forking, | |
15 | with waiting if !, and communicate child process errors back | |
16 | - [tg] Change some more numbers to unsigned, signed is evil in C | |
17 | - [tg] Improve flags documentation, also fixes Debian #999706 | |
18 | - [tg] Clear nonblocking flag on entry for FIFOs as well, as POSIX says | |
19 | - [komh, tg] Fix termio chvt flushing and link to Ilya Zakharevich’s | |
20 | docs why no shell can use termios(4) on OS/2 | |
21 | - [tg] Introduce k32 type and arithmetics, used in hash, indicēs, … | |
22 | - [tg] Add explicit masking for 8-bit to KBY and KBI macros | |
23 | - [tg] Change remaining users off stdint.h types, except old arith | |
24 | - [tg, bwh] Limit object size to the smaller of (size_t)PTRDIFF_MAX and | |
25 | SIZE_MAX, so byte representation pointer offsets cannot cause UB | |
26 | - [tg] PRNG improvements: track traps and history input | |
27 | - [tg] Limit variable name length to INT_MAX-X_EXTRA to guarantee export | |
28 | - [tg] Update portability glue for manpage | |
29 | - [tg] Document local array howto and behaviour in the FAQ | |
30 | - [tg] Fix missing backslash in posix-mode FAQ locale example code | |
31 | - [tg] Change short hash from BAFH0-1 to BAFH1-0 (faster at no loss) | |
32 | - [tg] Improve UB-safe type property detection and arithmetics; switch | |
33 | more parts of lksh to UB-y (POSIXly “correct” though…) arithmetics | |
34 | - [tg] Support GNU sigdescr_np(3) replacement for _sys_siglist[] and | |
35 | sigabbrev_np(3) for _sys_signame[] (avoid glibc regression) | |
36 | - [RT] Port to SerenityOS | |
37 | * debian/printf.c: Update from MirBSD CVS to support new warning framework | |
38 | * Sync debian/copyright accordingly | |
39 | ||
40 | -- Thorsten Glaser <tg@mirbsd.de> Sun, 30 Jan 2022 18:02:53 +0100 | |
5 | 41 | |
6 | 42 | mksh (59c-14) unstable; urgency=low |
7 | 43 |
24 | 24 | The MirBSD Korn Shell (mksh) is |
25 | 25 | Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
26 | 26 | 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
27 | 2020, 2021 | |
27 | 2020, 2021, 2022 | |
28 | 28 | mirabilos <m@mirbsd.org> |
29 | 29 | Copyright (c) 2015, 2017, 2020 |
30 | 30 | KO Myung-Hun <komh@chollian.net> |
76 | 76 | |
77 | 77 | |
78 | 78 | printf.c is |
79 | Copyright (c) 2005, 2009, 2010, 2011, 2012, 2020, 2021 | |
80 | mirabilos <m@mirbsd.org> | |
79 | 81 | Copyright (c) 1989 |
80 | 82 | The Regents of the University of California. |
81 | 83 | All rights reserved. |
1 | 1 | |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 1989 The Regents of the University of California. |
4 | * Copyright (c) 2005, 2009, 2010, 2011, 2012, 2020, 2021 | |
5 | * mirabilos <m@mirbsd.org> | |
4 | 6 | * All rights reserved. |
5 | 7 | * |
6 | 8 | * Redistribution and use in source and binary forms, with or without |
46 | 48 | #define vstrchr strchr |
47 | 49 | #endif |
48 | 50 | |
49 | __RCSID("$MirOS: src/usr.bin/printf/printf.c,v 1.21 2020/01/22 01:57:44 tg Exp $"); | |
51 | __RCSID("$MirOS: src/usr.bin/printf/printf.c,v 1.24 2021/11/21 03:47:51 tg Exp $"); | |
50 | 52 | |
51 | 53 | static int print_escape_str(const char *); |
52 | 54 | static int print_escape(const char *); |
73 | 75 | static void s_prt(int); |
74 | 76 | |
75 | 77 | static const char *s_ptr; |
76 | ||
77 | #define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) | |
78 | #endif | |
79 | ||
78 | #else | |
80 | 79 | #define isodigit(c) ((c) >= '0' && (c) <= '7') |
81 | 80 | #define octtobin(c) ((c) - '0') |
82 | 81 | #define hextobin(c) ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0') |
82 | #endif | |
83 | 83 | |
84 | 84 | #define PF(f, func) do { \ |
85 | 85 | if (fieldwidth) \ |
97 | 97 | #define vstrchr strchr |
98 | 98 | #endif |
99 | 99 | |
100 | #ifndef cstrerror | |
101 | #define cstrerror(e) ((const char *)strerror(e)) | |
102 | #endif | |
103 | ||
104 | 100 | #ifdef MKSH_PRINTF_BUILTIN |
105 | 101 | #define ufprintf shf_fprintf |
106 | 102 | #define uprintf shprintf |
107 | #define uputc(c) shf_putchar((c), shl_stdout) | |
103 | #define uputc(c) shf_putc((c), shl_stdout) | |
108 | 104 | #define ustderr shl_out |
109 | #define uwarnx warningf | |
110 | #define UWARNX false, | |
105 | #define uwarn1 kwarnf | |
106 | #define UWARN1 (KWF_WARNING | KWF_PREFIX | KWF_FILELINE | \ | |
107 | KWF_BUILTIN | KWF_ONEMSG), | |
108 | #define uwarnx kwarnf0 | |
109 | #define UWARNX (KWF_WARNING | KWF_PREFIX | KWF_FILELINE | \ | |
110 | KWF_BUILTIN | KWF_NOERRNO), | |
111 | 111 | |
112 | 112 | int |
113 | 113 | c_printf(const char **wp) |
139 | 139 | #define uprintf printf |
140 | 140 | #define uputc putchar |
141 | 141 | #define ustderr stderr |
142 | #define uwarn1 warn | |
143 | #define UWARN1 "%s", | |
142 | 144 | #define uwarnx warnx |
143 | 145 | #define UWARNX /* nothing */ |
144 | 146 | |
422 | 424 | value <<= 4; |
423 | 425 | value += hextobin(*str); |
424 | 426 | } |
425 | if (value > UCHAR_MAX) { | |
427 | if ((unsigned int)value > (unsigned int)UCHAR_MAX) { | |
426 | 428 | uwarnx(UWARNX "escape sequence out of range for character"); |
427 | 429 | rval = 1; |
428 | 430 | } |
608 | 610 | uwarnx(UWARNX "%s: not completely converted", s); |
609 | 611 | rval = 1; |
610 | 612 | } else if (errno == ERANGE) { |
611 | uwarnx(UWARNX "%s: %s", s, cstrerror(ERANGE)); | |
613 | uwarn1(UWARN1 s); | |
612 | 614 | rval = 1; |
613 | 615 | } |
614 | 616 | } |
636 | 638 | static void |
637 | 639 | s_prt(int c) |
638 | 640 | { |
639 | char ts[4]; | |
640 | ||
641 | if ((unsigned int)c < 0x100) { | |
642 | ts[0] = c; | |
643 | c = 1; | |
644 | } else | |
641 | if ((unsigned int)c < 0x100) | |
642 | shf_putc((char)c, shl_stdout); | |
643 | else { | |
644 | char ts[5]; | |
645 | ||
645 | 646 | c = (int)utf_wctomb(ts, c - 0x100); |
646 | ||
647 | shf_write(ts, c, shl_stdout); | |
648 | } | |
649 | #endif | |
647 | shf_write(ts, c, shl_stdout); | |
648 | } | |
649 | } | |
650 | #endif |
0 | 0 | # $Id$ |
1 | # $MirOS: src/bin/mksh/dot.mkshrc,v 1.136 2021/01/24 20:38:30 tg Exp $ | |
1 | # $MirOS: src/bin/mksh/dot.mkshrc,v 1.139 2022/01/26 13:02:35 tg Exp $ | |
2 | 2 | #- |
3 | 3 | # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, |
4 | 4 | # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, |
5 | # 2020, 2021 | |
5 | # 2020, 2021, 2022 | |
6 | 6 | # mirabilos <m@mirbsd.org> |
7 | 7 | # |
8 | 8 | # Provided that these terms and disclaimer and all copyright notices |
48 | 48 | \cat "$@" | "$fn" |
49 | 49 | fi |
50 | 50 | } |
51 | function _dot_mkshrc_cat_for_readN { | |
52 | \\builtin typeset fn=$1 | |
51 | function _dot_mkshrc_cat_for_readNa { | |
52 | \\builtin typeset fn=$1 s | |
53 | 53 | \\builtin shift |
54 | 54 | |
55 | 55 | if (( $# )); then |
56 | \\builtin print -nr -- "$*" | "$fn" | |
56 | \\builtin read -raN-1 s <<<"$*" || \\builtin return $? | |
57 | \\builtin unset s[${#s[*]}-1] | |
57 | 58 | elif [[ -t 0 ]]; then |
58 | \cat | "$fn" | |
59 | s=$(\cat || \builtin exit $?; \\builtin print .) || \ | |
60 | \\builtin return $? | |
61 | \\builtin read -raN-1 s <<<"$s" || \\builtin return $? | |
62 | \\builtin unset s[${#s[*]}-1] | |
63 | \\builtin unset s[${#s[*]}-1] | |
59 | 64 | else |
60 | "$fn" | |
61 | fi | |
65 | \\builtin read -raN-1 s || \\builtin return $? | |
66 | fi | |
67 | "$fn" | |
62 | 68 | } |
63 | 69 | |
64 | 70 | # pager (not control character safe) |
376 | 382 | if (( $# )); then |
377 | 383 | s="$*" |
378 | 384 | elif [[ -t 0 ]]; then |
379 | s=$(\cat || \\builtin exit $?; \\builtin print x) || \ | |
385 | s=$(\cat || \\builtin exit $?; \\builtin print .) || \ | |
380 | 386 | \\builtin return $? |
381 | s=${s%x} | |
387 | s=${s%.} | |
382 | 388 | else |
383 | 389 | \\builtin read -rN-1 s || \\builtin return $? |
384 | 390 | fi |
413 | 419 | \\builtin print -n -- "$t" |
414 | 420 | } |
415 | 421 | function Lb64encode { |
416 | \_dot_mkshrc_cat_for_readN _dot_mkshrc_b64encode "$@" | |
422 | \\builtin set +U | |
423 | \_dot_mkshrc_cat_for_readNa _dot_mkshrc_b64encode "$@" | |
417 | 424 | } |
418 | 425 | function _dot_mkshrc_b64encode { |
419 | \\builtin set +Ue | |
420 | \\builtin typeset c s t table | |
426 | \\builtin set +e | |
427 | \\builtin typeset c t table | |
421 | 428 | \\builtin set -A table -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \ |
422 | 429 | a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + / |
423 | \\builtin read -raN-1 s || \\builtin return $? | |
424 | 430 | \\builtin typeset -i i=0 n=${#s[*]} v |
425 | 431 | |
426 | 432 | while (( i < n )); do |
444 | 450 | \: |
445 | 451 | } |
446 | 452 | |
447 | # Better Avalanche for the Jenkins Hash | |
453 | # Better Avalanche for the Jenkins Hash, IV=1 INC=0 | |
448 | 454 | \\builtin typeset -Z11 -Uui16 Lbafh_v |
449 | 455 | function Lbafh_init { |
450 | Lbafh_v=0 | |
456 | Lbafh_v=1 | |
451 | 457 | } |
452 | 458 | function Lbafh_add { |
453 | \_dot_mkshrc_cat_for_readN _dot_mkshrc_bafh_add "$@" | |
459 | \\builtin set +U | |
460 | \_dot_mkshrc_cat_for_readNa _dot_mkshrc_bafh_add "$@" | |
454 | 461 | } |
455 | 462 | function _dot_mkshrc_bafh_add { |
456 | \\builtin set +Ue | |
457 | \\builtin typeset s | |
458 | \\builtin read -raN-1 s || \\builtin return $? | |
463 | \\builtin set +e | |
459 | 464 | \\builtin typeset -i i=0 n=${#s[*]} |
460 | 465 | |
461 | 466 | while (( i < n )); do |
462 | ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 )) | |
467 | ((# Lbafh_v = (Lbafh_v + s[i++]) * 1025 )) | |
463 | 468 | ((# Lbafh_v ^= Lbafh_v >> 6 )) |
464 | 469 | done |
465 | 470 | \: |
5 | 5 | /*- |
6 | 6 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
7 | 7 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
8 | * 2019, 2020, 2021 | |
8 | * 2019, 2020, 2021, 2022 | |
9 | 9 | * mirabilos <m@mirbsd.org> |
10 | 10 | * |
11 | 11 | * Provided that these terms and disclaimer and all copyright notices |
28 | 28 | |
29 | 29 | #ifndef MKSH_NO_CMDLINE_EDITING |
30 | 30 | |
31 | __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.392 2021/10/16 01:28:05 tg Exp $"); | |
31 | __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.397 2022/01/06 22:34:53 tg Exp $"); | |
32 | 32 | |
33 | 33 | /* |
34 | 34 | * in later versions we might use libtermcap for this, but since external |
418 | 418 | source = s; |
419 | 419 | if (yylex(ONEWORD | LQCHAR) != LWORD) { |
420 | 420 | source = sold; |
421 | internal_warningf(Tfg_badsubst); | |
421 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_ONEMSG | KWF_NOERRNO, | |
422 | Tfg_badsubst); | |
422 | 423 | nwords = 0; |
423 | 424 | goto out; |
424 | 425 | } |
1058 | 1059 | |
1059 | 1060 | static int x_ins(const void *); |
1060 | 1061 | static void x_delete(size_t, bool); |
1061 | static void x_bword(uint32_t, bool); | |
1062 | static void x_fword(uint32_t, bool); | |
1062 | static void x_bword(kui, bool); | |
1063 | static void x_fword(kui, bool); | |
1063 | 1064 | static void x_goto(char *); |
1064 | 1065 | static void x_bs3(char **); |
1065 | 1066 | static void x_uescs(char *); |
1078 | 1079 | static void x_e_putb(int); |
1079 | 1080 | static void x_e_puts(const char *); |
1080 | 1081 | #ifndef MKSH_SMALL |
1081 | static int x_fold_case(int, uint32_t); | |
1082 | static int x_fold_case(int, kui); | |
1082 | 1083 | #endif |
1083 | 1084 | static char *x_lastcp(void); |
1084 | 1085 | static void x_lastpos(void); |
1664 | 1665 | #endif |
1665 | 1666 | |
1666 | 1667 | static void |
1667 | x_bword(uint32_t separator, bool erase) | |
1668 | x_bword(kui separator, bool erase) | |
1668 | 1669 | { |
1669 | 1670 | size_t nb = 0; |
1670 | 1671 | char *cp = xcp; |
1689 | 1690 | } |
1690 | 1691 | |
1691 | 1692 | static void |
1692 | x_fword(uint32_t separator, bool erase) | |
1693 | x_fword(kui separator, bool erase) | |
1693 | 1694 | { |
1694 | 1695 | char *cp = xcp; |
1695 | 1696 | |
2367 | 2368 | if ((x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) || |
2368 | 2369 | killstack[killtp] == 0) { |
2369 | 2370 | killtp = killsp; |
2370 | x_e_puts("\nyank something first"); | |
2371 | x_e_puts(Tyankfirst); | |
2371 | 2372 | x_redraw('\n'); |
2372 | 2373 | return (KSTD); |
2373 | 2374 | } |
2634 | 2635 | x_bind(const char *s SMALLP(bool macro)) |
2635 | 2636 | { |
2636 | 2637 | register kui t; |
2637 | struct x_bind_getc state = { s, 0 }; | |
2638 | struct x_bind_getc state; | |
2638 | 2639 | kui c, key, prefix; |
2639 | 2640 | #ifndef MKSH_SMALL |
2640 | 2641 | bool hastilde = false; |
2641 | 2642 | char *ms = NULL; |
2642 | 2643 | #endif |
2643 | 2644 | |
2645 | state.cp = s; | |
2646 | state.next = 0; | |
2644 | 2647 | prefix = 0; |
2645 | 2648 | c = x_bind_getc(&state); |
2646 | 2649 | if (!c || c == ORD('=')) { |
3368 | 3371 | * None |
3369 | 3372 | */ |
3370 | 3373 | static int |
3371 | x_fold_case(int c, uint32_t separator) | |
3374 | x_fold_case(int c, kui separator) | |
3372 | 3375 | { |
3373 | 3376 | char *cp = xcp; |
3374 | 3377 | |
4073 | 4076 | case 0: |
4074 | 4077 | if (insert != 0) { |
4075 | 4078 | if (lastcmd[0] == 's' || |
4076 | ksh_eq(lastcmd[0], 'C', 'c')) { | |
4079 | isCh(lastcmd[0], 'C', 'c')) { | |
4077 | 4080 | if (redo_insert(1) != 0) |
4078 | 4081 | vi_error(); |
4079 | 4082 | } else { |
4202 | 4205 | lastcmd[0] = 'a'; |
4203 | 4206 | lastac = 1; |
4204 | 4207 | } |
4205 | if (lastcmd[0] == 's' || ksh_eq(lastcmd[0], 'C', 'c')) | |
4208 | if (lastcmd[0] == 's' || isCh(lastcmd[0], 'C', 'c')) | |
4206 | 4209 | return (redo_insert(0)); |
4207 | 4210 | else |
4208 | 4211 | return (redo_insert(lastac - 1)); |
4362 | 4365 | else { |
4363 | 4366 | if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0) |
4364 | 4367 | return (-1); |
4365 | if (*cmd == 'c' && ksh_eq(cmd[1], 'W', 'w') && | |
4368 | if (*cmd == 'c' && isCh(cmd[1], 'W', 'w') && | |
4366 | 4369 | !ctype(vs->cbuf[vs->cursor], C_SPACE)) { |
4367 | 4370 | do { |
4368 | 4371 | --ncursor; |
4793 | 4796 | case ORD(';'): |
4794 | 4797 | if (fsavecmd == ORD(' ')) |
4795 | 4798 | return (-1); |
4796 | i = ksh_eq(fsavecmd, 'F', 'f'); | |
4799 | i = isCh(fsavecmd, 'F', 'f'); | |
4797 | 4800 | t = rtt2asc(fsavecmd) > rtt2asc('a'); |
4798 | 4801 | if (*cmd == ',') |
4799 | 4802 | t = !t; |
5208 | 5211 | } |
5209 | 5212 | (void)histnum(n); |
5210 | 5213 | if ((hptr = *histpos()) == NULL) { |
5211 | internal_warningf("grabhist: bad history array"); | |
5214 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_ONEMSG | KWF_NOERRNO, | |
5215 | "grabhist: bad history array"); | |
5212 | 5216 | return (-1); |
5213 | 5217 | } |
5214 | 5218 | if (save) |
23 | 23 | |
24 | 24 | #include "sh.h" |
25 | 25 | |
26 | __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.243 2021/10/10 21:36:52 tg Exp $"); | |
26 | __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.247 2021/11/21 04:15:00 tg Exp $"); | |
27 | 27 | |
28 | 28 | /* |
29 | 29 | * string expansion |
131 | 131 | s->start = s->str = cp; |
132 | 132 | source = s; |
133 | 133 | if (yylex(ONEWORD) != LWORD) |
134 | internal_errorf(Tbadsubst); | |
134 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
135 | Tbadsubst); | |
135 | 136 | source = sold; |
136 | 137 | afree(s, ATEMP); |
137 | 138 | return (evalstr(yylval.cp, f)); |
254 | 255 | char *cp; |
255 | 256 | |
256 | 257 | if (ccp == NULL) |
257 | internal_errorf("expand(NULL)"); | |
258 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
259 | "expand(NULL)"); | |
258 | 260 | /* for alias, readonly, set, typeset commands */ |
259 | 261 | if ((f & DOVACHECK) && is_wdvarassign(ccp)) { |
260 | 262 | f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE); |
405 | 407 | *end = EOS; |
406 | 408 | str = snptreef(NULL, 64, Tf_S, beg); |
407 | 409 | afree(beg, ATEMP); |
408 | errorf(Tf_sD_s, str, Tbadsubst); | |
410 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
411 | KWF_FILELINE | KWF_TWOMSG | | |
412 | KWF_NOERRNO, str, Tbadsubst); | |
409 | 413 | } |
410 | 414 | if (f & DOBLANK) |
411 | 415 | doblank++; |
704 | 708 | break; |
705 | 709 | case ORD('?'): |
706 | 710 | if (*sp == CSUBST) |
707 | errorf("%s: parameter null or not set", | |
708 | st->var->name); | |
711 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
712 | KWF_FILELINE | KWF_TWOMSG | | |
713 | KWF_NOERRNO, st->var->name, | |
714 | "parameter null or not set"); | |
709 | 715 | f &= ~DOBLANK; |
710 | 716 | f |= DOTEMP; |
711 | 717 | /* FALLTHROUGH */ |
786 | 792 | * in AT&T ksh. |
787 | 793 | */ |
788 | 794 | /* |
789 | * XXX POSIX says readonly is only | |
795 | * XXX POSIX says read-only is only | |
790 | 796 | * fatal for special builtins (setstr |
791 | * does readonly check). | |
797 | * does read-only check). | |
792 | 798 | */ |
793 | 799 | len = strlen(dp) + 1; |
794 | 800 | setstr(st->var, |
804 | 810 | case ORD('?'): |
805 | 811 | dp = Xrestpos(ds, dp, st->base); |
806 | 812 | |
807 | errorf(Tf_sD_s, st->var->name, | |
813 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
814 | KWF_FILELINE | KWF_TWOMSG | | |
815 | KWF_NOERRNO, st->var->name, | |
808 | 816 | debunk(dp, dp, strlen(dp) + 1)); |
809 | 817 | break; |
810 | 818 | case ORD('#') | STYPE_AT: |
1319 | 1327 | } |
1320 | 1328 | xp->var = global(sp); |
1321 | 1329 | /* use saved p from above */ |
1322 | xp->str = p ? shf_smprintf("%s[%lu]", xp->var->name, | |
1330 | xp->str = p ? shf_smprintf(Tf_sSQlu, xp->var->name, | |
1323 | 1331 | arrayindex(xp->var)) : xp->var->name; |
1324 | 1332 | break; |
1325 | 1333 | #ifdef DEBUG |
1326 | 1334 | default: |
1327 | internal_errorf("stype mismatch"); | |
1335 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
1336 | "stype mismatch"); | |
1328 | 1337 | /* NOTREACHED */ |
1329 | 1338 | #endif |
1330 | 1339 | case ORD('%'): |
1370 | 1379 | } |
1371 | 1380 | /* ${%var} also here */ |
1372 | 1381 | if (Flag(FNOUNSET) && sc == 0 && !zero_ok) |
1373 | errorf(Tf_parm, sp); | |
1382 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
1383 | KWF_FILELINE | KWF_TWOMSG | | |
1384 | KWF_NOERRNO, sp, Tf_parm); | |
1374 | 1385 | xp->str = shf_smprintf(Tf_d, sc); |
1375 | 1386 | break; |
1376 | 1387 | } |
1513 | 1524 | state = XBASE; |
1514 | 1525 | if (Flag(FNOUNSET) && xp->str == null && !zero_ok && |
1515 | 1526 | (ctype(c, C_SUB2) || (state != XBASE && c != ORD('+')))) |
1516 | errorf(Tf_parm, sp); | |
1527 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
1528 | KWF_NOERRNO, sp, Tf_parm); | |
1517 | 1529 | *stypep = stype; |
1518 | 1530 | *slenp = slen; |
1519 | 1531 | return (state); |
1567 | 1579 | shf = shf_open(name = evalstr(io->ioname, DOTILDE), |
1568 | 1580 | O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC); |
1569 | 1581 | if (shf == NULL) |
1570 | warningf(!Flag(FTALKING), Tf_sD_sD_s, | |
1571 | name, Tcant_filesub, cstrerror(errno)); | |
1582 | kwarnf(KWF_PREFIX | (Flag(FTALKING) ? | |
1583 | KWF_FILELINE : 0) | KWF_TWOMSG, | |
1584 | name, Tcant_filesub); | |
1572 | 1585 | break; |
1573 | 1586 | case IOHERE: |
1574 | 1587 | if (!herein(io, &name)) { |
1583 | 1596 | shf = NULL; |
1584 | 1597 | break; |
1585 | 1598 | default: |
1586 | errorf(Tf_sD_s, T_funny_command, | |
1599 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
1600 | KWF_TWOMSG | KWF_NOERRNO, T_funny_command, | |
1587 | 1601 | snptreef(NULL, 32, Tft_R, io)); |
1588 | 1602 | } |
1589 | 1603 | } else if (fn == FUNSUB) { |
1595 | 1609 | * with an shf open for reading (buffered) but yet unused |
1596 | 1610 | */ |
1597 | 1611 | maketemp(ATEMP, TT_FUNSUB, &tf); |
1598 | if (!tf->shf) { | |
1599 | errorf(Tf_temp, | |
1600 | Tcreate, tf->tffn, cstrerror(errno)); | |
1601 | } | |
1612 | if (!tf->shf) | |
1613 | kerrf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE, | |
1614 | Tf_temp, Tcreate, tf->tffn); | |
1602 | 1615 | /* extract shf from temporary file, unlink and free it */ |
1603 | 1616 | shf = tf->shf; |
1604 | 1617 | unlink(tf->tffn); |
1757 | 1770 | char *xp = *xpp; |
1758 | 1771 | char *se; |
1759 | 1772 | char odirsep; |
1773 | DIR *dirp; | |
1774 | size_t prefix_len; | |
1760 | 1775 | |
1761 | 1776 | /* This to allow long expansions to be interrupted */ |
1762 | 1777 | intrcheck(); |
1815 | 1830 | Xcheck(*xs, xp); |
1816 | 1831 | *xp++ = *sp++; |
1817 | 1832 | } |
1833 | *xp = '\0'; | |
1818 | 1834 | np = mksh_sdirsep(sp); |
1819 | 1835 | if (np != NULL) { |
1820 | 1836 | se = np; |
1839 | 1855 | xp = strnul(xp); |
1840 | 1856 | *xpp = xp; |
1841 | 1857 | globit(xs, xpp, np, wp, check); |
1842 | } else { | |
1843 | DIR *dirp; | |
1858 | } else if ((dirp = opendir((prefix_len = Xlength(*xs, xp)) ? | |
1859 | Xstring(*xs, xp) : Tdot))) { | |
1844 | 1860 | struct dirent *d; |
1845 | char *name; | |
1846 | size_t len, prefix_len; | |
1847 | ||
1848 | /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ | |
1849 | *xp = '\0'; | |
1850 | prefix_len = Xlength(*xs, xp); | |
1851 | dirp = opendir(prefix_len ? Xstring(*xs, xp) : Tdot); | |
1852 | if (dirp == NULL) | |
1853 | goto Nodir; | |
1861 | ||
1854 | 1862 | while ((d = readdir(dirp)) != NULL) { |
1855 | name = d->d_name; | |
1856 | if (name[0] == '.' && | |
1857 | (name[1] == 0 || (name[1] == '.' && name[2] == 0))) | |
1863 | size_t len; | |
1864 | ||
1865 | if (isch(d->d_name[0], '.') && (!d->d_name[1] || | |
1866 | (isch(d->d_name[1], '.') && !d->d_name[2]))) | |
1858 | 1867 | /* always ignore . and .. */ |
1859 | 1868 | continue; |
1860 | if ((*name == '.' && *sp != '.') || | |
1861 | !gmatchx(name, sp, true)) | |
1869 | if ((isch(d->d_name[0], '.') && !isch(*sp, '.')) || | |
1870 | !gmatchx(d->d_name, sp, true)) | |
1862 | 1871 | continue; |
1863 | 1872 | |
1864 | 1873 | len = strlen(d->d_name) + 1; |
1865 | 1874 | XcheckN(*xs, xp, len); |
1866 | memcpy(xp, name, len); | |
1875 | memcpy(xp, d->d_name, len); | |
1867 | 1876 | *xpp = xp + len - 1; |
1868 | 1877 | globit(xs, xpp, np, wp, (check & GF_MARKDIR) | |
1869 | 1878 | GF_GLOBBED | (np ? GF_EXCHECK : GF_NONE)); |
1870 | 1879 | xp = Xstring(*xs, xp) + prefix_len; |
1871 | 1880 | } |
1872 | 1881 | closedir(dirp); |
1873 | Nodir: | |
1874 | ; | |
1875 | 1882 | } |
1876 | 1883 | |
1877 | 1884 | if (np != NULL) |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | 4 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
5 | * 2019, 2020, 2021 | |
5 | * 2019, 2020, 2021, 2022 | |
6 | 6 | * mirabilos <m@mirbsd.org> |
7 | 7 | * |
8 | 8 | * Provided that these terms and disclaimer and all copyright notices |
23 | 23 | |
24 | 24 | #include "sh.h" |
25 | 25 | |
26 | __RCSID("$MirOS: src/bin/mksh/exec.c,v 1.234 2021/10/10 21:35:04 tg Exp $"); | |
26 | __RCSID("$MirOS: src/bin/mksh/exec.c,v 1.237 2022/01/06 22:34:55 tg Exp $"); | |
27 | 27 | |
28 | 28 | #ifndef MKSH_DEFAULT_EXECSHELL |
29 | 29 | #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" |
150 | 150 | */ |
151 | 151 | if (tp && tp->type == CSHELL && |
152 | 152 | (tp->flag & SPEC_BI)) |
153 | errorfz(); | |
153 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
154 | KWF_FILELINE | KWF_ONEMSG | | |
155 | KWF_NOERRNO, "redirection failure"); | |
154 | 156 | /* Deal with FERREXIT, quitenv(), etc. */ |
155 | 157 | goto Break; |
156 | 158 | } |
225 | 227 | #endif |
226 | 228 | /* Already have a (live) co-process? */ |
227 | 229 | if (coproc.job && coproc.write >= 0) |
228 | errorf("coprocess already exists"); | |
230 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
231 | KWF_FILELINE | KWF_ONEMSG | | |
232 | KWF_NOERRNO, "coprocess already exists"); | |
229 | 233 | |
230 | 234 | /* Can we re-use the existing co-process pipe? */ |
231 | 235 | coproc_cleanup(true); |
434 | 438 | for (iowp = t->left->ioact; *iowp != NULL; iowp++) |
435 | 439 | if (((*iowp)->ioflag & IODUPSELF) && |
436 | 440 | fcntl((*iowp)->unit, F_SETFD, 0) == -1) |
437 | internal_warningf(Tcloexec_failed, | |
438 | "clear", (*iowp)->unit, | |
439 | cstrerror(errno)); | |
441 | kwarnf0(KWF_INTERNAL | KWF_WARNING, | |
442 | Tcloexec_failed, "clear", | |
443 | (*iowp)->unit); | |
440 | 444 | /* try to execute */ |
441 | 445 | { |
442 | 446 | union mksh_ccphack cargs; |
448 | 452 | if (rv == ENOEXEC) |
449 | 453 | scriptexec(t, (const char **)up); |
450 | 454 | else |
451 | errorfx(126, Tf_sD_s, t->str, cstrerror(rv)); | |
455 | kerrf(KWF_VERRNO | KWF_ERR(126) | KWF_PREFIX | | |
456 | KWF_FILELINE | KWF_ONEMSG, rv, t->str); | |
452 | 457 | } |
453 | 458 | Break: |
454 | 459 | exstat = rv & 0xFF; |
534 | 539 | break; |
535 | 540 | } |
536 | 541 | if ((tp = findcom(cp, FC_BI)) == NULL) |
537 | errorf(Tf_sD_sD_s, Tbuiltin, cp, Tnot_found); | |
542 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
543 | KWF_THREEMSG | KWF_NOERRNO, Tbuiltin, cp, | |
544 | Tnot_found); | |
538 | 545 | if (tp->type == CSHELL && (tp->flag & LOW_BI)) |
539 | 546 | break; |
540 | 547 | continue; |
578 | 585 | fcflags = FC_BI | FC_PATH; |
579 | 586 | if (saw_p) { |
580 | 587 | if (Flag(FRESTRICTED)) { |
581 | warningf(true, Tf_sD_s, | |
588 | kwarnf(KWF_PREFIX | KWF_FILELINE | | |
589 | KWF_TWOMSG | KWF_NOERRNO, | |
582 | 590 | "command -p", "restricted"); |
583 | 591 | rv = 1; |
584 | 592 | goto Leave; |
675 | 683 | goto Leave; |
676 | 684 | } else if (!tp) { |
677 | 685 | if (Flag(FRESTRICTED) && mksh_vdirsep(cp)) { |
678 | warningf(true, Tf_sD_s, cp, "restricted"); | |
686 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
687 | KWF_NOERRNO, cp, "restricted"); | |
679 | 688 | rv = 1; |
680 | 689 | goto Leave; |
681 | 690 | } |
694 | 703 | |
695 | 704 | /* function call */ |
696 | 705 | case CFUNC: { |
697 | volatile uint32_t old_inuse; | |
706 | volatile kui old_inuse; | |
698 | 707 | const char * volatile old_kshname; |
699 | 708 | volatile kby old_flags[FNFLAGS]; |
700 | 709 | |
704 | 713 | if (!tp->u.fpath) { |
705 | 714 | fpath_error: |
706 | 715 | rv = (tp->u2.errnov == ENOENT) ? 127 : 126; |
707 | warningf(true, | |
708 | "%s: can't find function definition file: %s", | |
709 | cp, cstrerror(tp->u2.errnov)); | |
716 | kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_FILELINE | | |
717 | KWF_TWOMSG, tp->u2.errnov, cp, | |
718 | "can't find function definition file"); | |
710 | 719 | break; |
711 | 720 | } |
712 | 721 | errno = 0; |
725 | 734 | cp = tp->u.fpath; |
726 | 735 | goto fpath_error; |
727 | 736 | } |
728 | warningf(true, Tf_sD_s_s, cp, | |
737 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, | |
738 | Tf_sD_s_s, cp, | |
729 | 739 | "function not defined by", tp->u.fpath); |
730 | 740 | rv = 127; |
731 | 741 | break; |
816 | 826 | /* NOTREACHED */ |
817 | 827 | default: |
818 | 828 | quitenv(NULL); |
819 | internal_errorf(Tunexpected_type, Tunwind, Tfunction, i); | |
829 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
830 | Tunexpected_type, Tunwind, Tfunction, i); | |
820 | 831 | } |
821 | 832 | break; |
822 | 833 | } |
828 | 839 | if (!(tp->flag&ISSET)) { |
829 | 840 | if (tp->u2.errnov == ENOENT) { |
830 | 841 | rv = 127; |
831 | warningf(true, Tf_sD_s_s, cp, | |
832 | "inaccessible or", Tnot_found); | |
842 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
843 | KWF_NOERRNO, cp, Tinacc_not_found); | |
833 | 844 | } else { |
834 | 845 | rv = 126; |
835 | warningf(true, Tf_sD_sD_s, cp, "can't execute", | |
836 | cstrerror(tp->u2.errnov)); | |
846 | kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_FILELINE | | |
847 | KWF_TWOMSG, tp->u2.errnov, cp, | |
848 | "can't execute"); | |
837 | 849 | } |
838 | 850 | break; |
839 | 851 | } |
969 | 981 | #ifndef MKSH_EBCDIC |
970 | 982 | m = buf[0] << 8 | buf[1]; |
971 | 983 | if (m == 0x7F45 && buf[2] == 'L' && buf[3] == 'F') |
972 | errorf("%s: not executable: %d-bit ELF file", tp->str, | |
973 | 32 * buf[4]); | |
984 | kerrf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
985 | KWF_NOERRNO, "%s: not executable: %d-bit ELF file", | |
986 | tp->str, 32 * buf[4]); | |
974 | 987 | if ((m == /* OMAGIC */ 0407) || |
975 | 988 | (m == /* NMAGIC */ 0410) || |
976 | 989 | (m == /* ZMAGIC */ 0413) || |
987 | 1000 | (m == /* UTF-8 BOM */ 0xEFBB && buf[2] == 0xBF) || |
988 | 1001 | (m == /* UCS-4, may also be general binary */ 0x0000) || |
989 | 1002 | (m == /* UCS-2LE */ 0xFFFE) || (m == /* UCS-2BE */ 0xFEFF)) |
990 | errorf("%s: not executable: magic %04X", tp->str, m); | |
1003 | kerrf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
1004 | KWF_NOERRNO, "%s: not executable: magic %04X", | |
1005 | tp->str, m); | |
991 | 1006 | #endif |
992 | 1007 | #ifdef __OS2__ |
993 | 1008 | cp = _getext(tp->str); |
1013 | 1028 | execve(args.rw[0], args.rw, cap.rw); |
1014 | 1029 | |
1015 | 1030 | /* report both the program that was run and the bogus interpreter */ |
1016 | errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno)); | |
1031 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG, tp->str, sh); | |
1017 | 1032 | } |
1018 | 1033 | |
1019 | 1034 | /* actual 'builtin' built-in utility call is handled in comexec() */ |
1034 | 1049 | * is created if none is found. |
1035 | 1050 | */ |
1036 | 1051 | struct tbl * |
1037 | findfunc(const char *name, uint32_t h, bool create) | |
1052 | findfunc(const char *name, k32 h, bool create) | |
1038 | 1053 | { |
1039 | 1054 | struct block *l; |
1040 | 1055 | struct tbl *tp = NULL; |
1061 | 1076 | int |
1062 | 1077 | define(const char *name, struct op *t) |
1063 | 1078 | { |
1064 | uint32_t nhash; | |
1079 | k32 nhash; | |
1065 | 1080 | struct tbl *tp; |
1066 | 1081 | bool was_set = false; |
1067 | 1082 | |
1111 | 1126 | builtin(const char *name, int (*func) (const char **)) |
1112 | 1127 | { |
1113 | 1128 | struct tbl *tp; |
1114 | uint32_t flag = DEFINED; | |
1129 | kui flag = DEFINED; | |
1115 | 1130 | |
1116 | 1131 | /* see if any flags should be set for this builtin */ |
1117 | 1132 | flags_loop: |
1169 | 1184 | findcom(const char *name, int flags) |
1170 | 1185 | { |
1171 | 1186 | static struct tbl temp; |
1172 | uint32_t h = hash(name); | |
1187 | k32 h = hash(name); | |
1173 | 1188 | struct tbl *tp = NULL, *tbi; |
1174 | 1189 | /* insert if not found */ |
1175 | 1190 | unsigned char insert = Flag(FTRACKALL); |
1384 | 1399 | int rv; |
1385 | 1400 | |
1386 | 1401 | if (!tp) |
1387 | internal_errorf(Tf_sD_s, where, wp[0]); | |
1402 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG | KWF_NOERRNO, | |
1403 | where, wp[0]); | |
1388 | 1404 | builtin_argv0 = wp[0]; |
1389 | 1405 | builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI)); |
1390 | 1406 | shf_reopen(1, SHF_WR, shl_stdout); |
1487 | 1503 | &emsg)) < 0) { |
1488 | 1504 | char *sp; |
1489 | 1505 | |
1490 | warningf(true, Tf_sD_s, | |
1491 | (sp = snptreef(NULL, 32, Tft_R, &iotmp)), emsg); | |
1506 | sp = snptreef(NULL, 32, Tft_R, &iotmp); | |
1507 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
1508 | KWF_NOERRNO, sp, emsg); | |
1492 | 1509 | afree(sp, ATEMP); |
1493 | 1510 | return (-1); |
1494 | 1511 | } |
1503 | 1520 | |
1504 | 1521 | if (do_open) { |
1505 | 1522 | if (Flag(FRESTRICTED) && (flags & O_CREAT)) { |
1506 | warningf(true, Tf_sD_s, cp, "restricted"); | |
1523 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
1524 | KWF_NOERRNO, cp, "restricted"); | |
1507 | 1525 | return (-1); |
1508 | 1526 | } |
1509 | 1527 | u = binopen3(cp, flags, 0666); |
1520 | 1538 | if (u < 0) { |
1521 | 1539 | /* herein() may already have printed message */ |
1522 | 1540 | if (u == -1) { |
1523 | u = errno; | |
1524 | warningf(true, Tf_cant_ss_s, | |
1541 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG, cp, | |
1542 | (iotype == IOREAD || iotype == IOHERE) ? Topen : | |
1525 | 1543 | #if 0 |
1526 | 1544 | /* can't happen */ |
1527 | 1545 | iotype == IODUP ? "dup" : |
1528 | 1546 | #endif |
1529 | (iotype == IOREAD || iotype == IOHERE) ? | |
1530 | Topen : Tcreate, cp, cstrerror(u)); | |
1547 | Tcreate); | |
1531 | 1548 | } |
1532 | 1549 | return (-1); |
1533 | 1550 | } |
1550 | 1567 | char *sp; |
1551 | 1568 | |
1552 | 1569 | eno = errno; |
1553 | warningf(true, Tf_s_sD_s, Tredirection_dup, | |
1554 | (sp = snptreef(NULL, 32, Tft_R, &iotmp)), | |
1555 | cstrerror(eno)); | |
1570 | sp = snptreef(NULL, 32, Tft_s_R, Tredirection_dup, | |
1571 | &iotmp); | |
1572 | kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_FILELINE | | |
1573 | KWF_ONEMSG, eno, sp); | |
1556 | 1574 | afree(sp, ATEMP); |
1557 | 1575 | if (iotype != IODUP) |
1558 | 1576 | close(u); |
1606 | 1624 | s->start = s->str = ccp; |
1607 | 1625 | source = s; |
1608 | 1626 | if (yylex(sub) != LWORD) |
1609 | internal_errorf("herein: yylex"); | |
1627 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
1628 | "herein: yylex"); | |
1610 | 1629 | source = osource; |
1611 | 1630 | ccp = evalstr(yylval.cp, DOSCALAR | DOHEREDOC); |
1612 | 1631 | } |
1641 | 1660 | */ |
1642 | 1661 | h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps); |
1643 | 1662 | if (!(shf = h->shf) || (fd = binopen3(h->tffn, O_RDONLY, 0)) < 0) { |
1644 | i = errno; | |
1645 | warningf(true, Tf_temp, | |
1646 | !shf ? Tcreate : Topen, h->tffn, cstrerror(i)); | |
1663 | kwarnf0(KWF_PREFIX | KWF_FILELINE, Tf_temp, | |
1664 | !shf ? Tcreate : Topen, h->tffn); | |
1647 | 1665 | if (shf) |
1648 | 1666 | shf_close(shf); |
1649 | 1667 | /* special to iosetup(): don't print error */ |
1659 | 1677 | if (shf_close(shf) == -1) { |
1660 | 1678 | i = errno; |
1661 | 1679 | close(fd); |
1662 | warningf(true, Tf_temp, | |
1663 | Twrite, h->tffn, cstrerror(i)); | |
1680 | kwarnf1(KWF_VERRNO | KWF_PREFIX | KWF_FILELINE, i, | |
1681 | Tf_temp, Twrite, h->tffn); | |
1664 | 1682 | /* special to iosetup(): don't print error */ |
1665 | 1683 | return (-2); |
1666 | 1684 | } |
1868 | 1886 | dbteste_error(Test_env *te, int offset, const char *msg) |
1869 | 1887 | { |
1870 | 1888 | te->flags |= TEF_ERROR; |
1871 | internal_warningf("dbteste_error: %s (offset %d)", msg, offset); | |
1872 | } | |
1889 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1890 | "dbteste_error: %s (offset %d)", msg, offset); | |
1891 | } |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | 4 | * 2011, 2012, 2013, 2014, 2016, 2017, 2018, 2019, |
5 | * 2021 | |
5 | * 2021, 2022 | |
6 | 6 | * mirabilos <m@mirbsd.org> |
7 | 7 | * |
8 | 8 | * Provided that these terms and disclaimer and all copyright notices |
23 | 23 | |
24 | 24 | #include "sh.h" |
25 | 25 | |
26 | __RCSID("$MirOS: src/bin/mksh/expr.c,v 1.114 2021/10/10 20:41:16 tg Exp $"); | |
26 | __RCSID("$MirOS: src/bin/mksh/expr.c,v 1.119 2022/01/28 07:01:12 tg Exp $"); | |
27 | 27 | |
28 | 28 | #define EXPRTOK_DEFNS |
29 | 29 | #include "exprtok.h" |
141 | 141 | if (i == LAEXPR) { |
142 | 142 | if (error_ok == KSH_RETURN_ERROR) |
143 | 143 | return (0); |
144 | errorfz(); | |
144 | /* error already printed */ | |
145 | /* (cf. syn.c for why) */ | |
146 | exstat = 1; | |
147 | shl_stdout_ok = false; | |
148 | i = LERROR; | |
145 | 149 | } |
146 | 150 | unwind(i); |
147 | 151 | /* NOTREACHED */ |
162 | 166 | if (vp->flag & INTEGER) |
163 | 167 | setint_v(vp, v, es->arith); |
164 | 168 | else |
165 | /* can fail if readonly */ | |
169 | /* can fail if read-only */ | |
166 | 170 | setstr(vp, str_val(v), error_ok); |
167 | 171 | |
168 | 172 | quitenv(NULL); |
197 | 201 | default: |
198 | 202 | s = opname[(int)es->tok]; |
199 | 203 | } |
200 | warningf(true, Tf_sD_s_qs, es->expression, | |
201 | Tunexpected, s); | |
204 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, Tf_sD_s_qs, | |
205 | es->expression, Tunexpected, s); | |
202 | 206 | break; |
203 | 207 | |
204 | 208 | case ET_BADLIT: |
205 | warningf(true, Tf_sD_s_qs, es->expression, | |
206 | Tbadnum, str); | |
209 | if (!strcmp(es->expression, str)) | |
210 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG, | |
211 | es->expression, Tbadnum); | |
212 | else | |
213 | kwarnf0(KWF_PREFIX | KWF_FILELINE, Tf_sD_s_qs, | |
214 | es->expression, Tbadnum, str); | |
207 | 215 | break; |
208 | 216 | |
209 | 217 | case ET_RECURSIVE: |
210 | warningf(true, Tf_sD_s_qs, es->expression, | |
211 | "expression recurses on parameter", str); | |
218 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, Tf_sD_s_qs, | |
219 | es->expression, "expression recurses on parameter", str); | |
212 | 220 | break; |
213 | 221 | |
214 | 222 | case ET_LVALUE: |
215 | warningf(true, Tf_sD_s_s, | |
223 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, Tf_sD_s_s, | |
216 | 224 | es->expression, str, "requires lvalue"); |
217 | 225 | break; |
218 | 226 | |
219 | 227 | case ET_RDONLY: |
220 | warningf(true, Tf_sD_s_s, | |
228 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, Tf_sD_s_s, | |
221 | 229 | es->expression, str, "applied to read-only variable"); |
222 | 230 | break; |
223 | 231 | |
224 | 232 | default: /* keep gcc happy */ |
225 | 233 | case ET_STR: |
226 | warningf(true, Tf_sD_s, es->expression, str); | |
234 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
235 | es->expression, str); | |
227 | 236 | break; |
228 | 237 | } |
229 | 238 | unwind(LAEXPR); |
262 | 271 | { |
263 | 272 | struct tbl *vl, *vr = NULL, *vasn; |
264 | 273 | enum token op; |
265 | mksh_uari_t res = 0, t1, t2, t3; | |
274 | mksh_uari_t res = 0; | |
266 | 275 | |
267 | 276 | if (prec == P_PRIMARY) { |
268 | 277 | switch ((int)(op = es->tok)) { |
365 | 374 | } else if (op != O_LAND && op != O_LOR) |
366 | 375 | vr = intvar(es, evalexpr(es, prec - 1)); |
367 | 376 | |
368 | /* common ops setup */ | |
377 | /* op calculation */ | |
378 | #define cmpop(op) (es->natural ? \ | |
379 | (mksh_uari_t)(vl->val.u op vr->val.u) : \ | |
380 | (mksh_uari_t)(vl->val.i op vr->val.i) \ | |
381 | ) | |
382 | #ifndef MKSH_LEGACY_MODE | |
383 | #define ariop(op) (vl->val.u op vr->val.u) | |
384 | #else | |
385 | #define ariop(op) cmpop(op) | |
386 | #endif | |
369 | 387 | switch ((int)op) { |
388 | case O_PLUS: | |
389 | case O_PLUSASN: | |
390 | res = ariop(+); | |
391 | break; | |
392 | case O_MINUS: | |
393 | case O_MINUSASN: | |
394 | res = ariop(-); | |
395 | break; | |
396 | case O_TIMES: | |
397 | case O_TIMESASN: | |
398 | res = ariop(*); | |
399 | break; | |
370 | 400 | case O_DIV: |
371 | 401 | case O_DIVASN: |
372 | 402 | case O_MOD: |
373 | 403 | case O_MODASN: |
374 | if (vr->val.u == 0) { | |
404 | if (vr->val.i == 0) { | |
375 | 405 | if (!es->noassign) |
376 | 406 | evalerr(es, ET_STR, "zero divisor"); |
377 | vr->val.u = 1; | |
378 | } | |
379 | /* calculate the absolute values */ | |
380 | t1 = vl->val.i < 0 ? -vl->val.u : vl->val.u; | |
381 | t2 = vr->val.i < 0 ? -vr->val.u : vr->val.u; | |
382 | break; | |
383 | #ifndef MKSH_LEGACY_MODE | |
384 | case O_LSHIFT: | |
385 | case O_LSHIFTASN: | |
386 | case O_RSHIFT: | |
387 | case O_RSHIFTASN: | |
388 | case O_ROL: | |
389 | case O_ROLASN: | |
390 | case O_ROR: | |
391 | case O_RORASN: | |
392 | t1 = vl->val.u; | |
393 | t2 = vr->val.u & 31; | |
394 | if (!t2) { | |
395 | res = t1; | |
396 | goto rotate_by_zero; | |
397 | } | |
398 | break; | |
399 | #endif | |
400 | case O_LAND: | |
401 | case O_LOR: | |
402 | t1 = vl->val.u; | |
403 | t2 = 0; /* gcc */ | |
404 | break; | |
405 | default: | |
406 | t1 = vl->val.u; | |
407 | t2 = vr->val.u; | |
408 | break; | |
409 | } | |
410 | ||
411 | #define cmpop(op) (es->natural ? \ | |
412 | (mksh_uari_t)(vl->val.u op vr->val.u) : \ | |
413 | (mksh_uari_t)(vl->val.i op vr->val.i) \ | |
414 | ) | |
415 | ||
416 | /* op calculation */ | |
417 | switch ((int)op) { | |
418 | case O_TIMES: | |
419 | case O_TIMESASN: | |
420 | res = t1 * t2; | |
421 | break; | |
422 | case O_MOD: | |
423 | case O_MODASN: | |
424 | if (es->natural) { | |
425 | res = vl->val.u % vr->val.u; | |
407 | res = vl->val.u; /* dummy value, could be 1 */ | |
426 | 408 | break; |
427 | 409 | } |
428 | goto signed_division; | |
429 | case O_DIV: | |
430 | case O_DIVASN: | |
431 | if (es->natural) { | |
432 | res = vl->val.u / vr->val.u; | |
433 | break; | |
434 | } | |
435 | signed_division: | |
436 | /* | |
437 | * a / b = abs(a) / abs(b) * sgn((u)a^(u)b) | |
438 | */ | |
439 | t3 = t1 / t2; | |
440 | 410 | #ifndef MKSH_LEGACY_MODE |
441 | res = ((vl->val.u ^ vr->val.u) & 0x80000000) ? -t3 : t3; | |
442 | #else | |
443 | res = ((t1 == vl->val.u ? 0 : 1) ^ | |
444 | (t2 == vr->val.u ? 0 : 1)) ? -t3 : t3; | |
411 | if (!es->natural) { | |
412 | mksh_uari_t u1, u2; | |
413 | ||
414 | mbiVASdivrem(mksh_uari_t, mksh_ari_t, | |
415 | u1, u2, vl->val.i, vr->val.i); | |
416 | if (op == O_DIV || op == O_DIVASN) | |
417 | res = u1; | |
418 | else | |
419 | res = u2; | |
420 | } else | |
445 | 421 | #endif |
446 | if (op == O_MOD || op == O_MODASN) { | |
447 | /* | |
448 | * primitive modulo, to get the sign of | |
449 | * the result correct: | |
450 | * (a % b) = a - ((a / b) * b) | |
451 | * the subtraction and multiplication | |
452 | * are, amazingly enough, sign ignorant | |
453 | */ | |
454 | res = vl->val.u - (res * vr->val.u); | |
455 | } | |
456 | break; | |
457 | case O_PLUS: | |
458 | case O_PLUSASN: | |
459 | res = t1 + t2; | |
460 | break; | |
461 | case O_MINUS: | |
462 | case O_MINUSASN: | |
463 | res = t1 - t2; | |
422 | if (op == O_DIV || op == O_DIVASN) | |
423 | res = ariop(/); | |
424 | else | |
425 | res = ariop(%); | |
464 | 426 | break; |
465 | 427 | #ifndef MKSH_LEGACY_MODE |
466 | 428 | case O_ROL: |
467 | 429 | case O_ROLASN: |
468 | res = (t1 << t2) | (t1 >> (32 - t2)); | |
430 | mbiVAUrol(mksh_uari_t, res, vl->val.u, vr->val.u); | |
469 | 431 | break; |
470 | 432 | case O_ROR: |
471 | 433 | case O_RORASN: |
472 | res = (t1 >> t2) | (t1 << (32 - t2)); | |
473 | rotate_by_zero: | |
434 | mbiVAUror(mksh_uari_t, res, vl->val.u, vr->val.u); | |
474 | 435 | break; |
475 | 436 | #endif |
476 | 437 | case O_LSHIFT: |
477 | 438 | case O_LSHIFTASN: |
478 | res = t1 << t2; | |
439 | #ifndef MKSH_LEGACY_MODE | |
440 | mbiVAUshl(mksh_uari_t, res, vl->val.u, vr->val.u); | |
441 | #else | |
442 | res = ariop(<<); | |
443 | #endif | |
479 | 444 | break; |
480 | 445 | case O_RSHIFT: |
481 | 446 | case O_RSHIFTASN: |
482 | res = es->natural || vl->val.i >= 0 ? | |
483 | t1 >> t2 : | |
484 | ~(~t1 >> t2); | |
447 | #ifndef MKSH_LEGACY_MODE | |
448 | mbiVAUshr(mksh_uari_t, res, | |
449 | !es->natural && vl->val.i < 0, | |
450 | vl->val.u, vr->val.u); | |
451 | #else | |
452 | res = ariop(>>); | |
453 | #endif | |
485 | 454 | break; |
486 | 455 | case O_LT: |
487 | 456 | res = cmpop(<); |
496 | 465 | res = cmpop(>=); |
497 | 466 | break; |
498 | 467 | case O_EQ: |
499 | res = t1 == t2; | |
468 | res = ariop(==); | |
500 | 469 | break; |
501 | 470 | case O_NE: |
502 | res = t1 != t2; | |
471 | res = ariop(!=); | |
503 | 472 | break; |
504 | 473 | case O_BAND: |
505 | 474 | case O_BANDASN: |
506 | res = t1 & t2; | |
475 | res = ariop(&); | |
507 | 476 | break; |
508 | 477 | case O_BXOR: |
509 | 478 | case O_BXORASN: |
510 | res = t1 ^ t2; | |
479 | res = ariop(^); | |
511 | 480 | break; |
512 | 481 | case O_BOR: |
513 | 482 | case O_BORASN: |
514 | res = t1 | t2; | |
483 | res = ariop(|); | |
515 | 484 | break; |
516 | 485 | case O_LAND: |
517 | if (!t1) | |
486 | if (!vl->val.u) | |
518 | 487 | es->noassign++; |
519 | 488 | exprtoken(es); |
520 | 489 | vr = intvar(es, evalexpr(es, prec - 1)); |
521 | res = t1 && vr->val.u; | |
522 | if (!t1) | |
490 | res = vl->val.u && vr->val.u; | |
491 | if (!vl->val.u) | |
523 | 492 | es->noassign--; |
524 | 493 | break; |
525 | 494 | case O_LOR: |
526 | if (t1) | |
495 | if (vl->val.u) | |
527 | 496 | es->noassign++; |
528 | 497 | exprtoken(es); |
529 | 498 | vr = intvar(es, evalexpr(es, prec - 1)); |
530 | res = t1 || vr->val.u; | |
531 | if (t1) | |
499 | res = vl->val.u || vr->val.u; | |
500 | if (vl->val.u) | |
532 | 501 | es->noassign--; |
533 | 502 | break; |
534 | 503 | case O_ASN: |
535 | 504 | case O_COMMA: |
536 | res = t2; | |
505 | res = vr->val.u; | |
537 | 506 | break; |
538 | 507 | } |
539 | ||
540 | 508 | #undef cmpop |
541 | 509 | |
542 | 510 | if (IS_ASSIGNOP(op)) { |
669 | 637 | struct tbl *vp; |
670 | 638 | size_t vsize; |
671 | 639 | |
672 | vsize = strlen(vname) + 1; | |
640 | /* vname is either "" or vtemp->name which maxes at 12 */ | |
641 | vsize = strlen(vname) + 1U; | |
673 | 642 | vp = alloc(offsetof(struct tbl, name[0]) + vsize, ATEMP); |
674 | 643 | memcpy(vp->name, vname, vsize); |
675 | 644 | vp->flag = ISSET|INTEGER; |
4 | 4 | /*- |
5 | 5 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
6 | 6 | * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, |
7 | * 2019, 2020, 2021 | |
7 | * 2019, 2020, 2021, 2022 | |
8 | 8 | * mirabilos <m@mirbsd.org> |
9 | 9 | * |
10 | 10 | * Provided that these terms and disclaimer and all copyright notices |
34 | 34 | #endif |
35 | 35 | #endif |
36 | 36 | |
37 | __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.393 2021/10/10 20:30:33 tg Exp $"); | |
37 | __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.401 2022/01/28 10:28:17 tg Exp $"); | |
38 | 38 | |
39 | 39 | #if HAVE_KILLPG |
40 | 40 | /* |
163 | 163 | const struct t_op u_ops[] = { |
164 | 164 | /* 0*/ {"-a", TO_FILAXST }, |
165 | 165 | {"-b", TO_FILBDEV }, |
166 | {"-c", TO_FILCDEV }, | |
166 | /* 2*/ {"-c", TO_FILCDEV }, | |
167 | 167 | {"-d", TO_FILID }, |
168 | 168 | {"-e", TO_FILEXST }, |
169 | 169 | {"-f", TO_FILREG }, |
176 | 176 | /*12*/ {"-n", TO_STNZE }, |
177 | 177 | {"-O", TO_FILUID }, |
178 | 178 | /*14*/ {"-o", TO_OPTION }, |
179 | {"-p", TO_FILFIFO }, | |
179 | /*15*/ {"-p", TO_FILFIFO }, | |
180 | 180 | /*16*/ {"-r", TO_FILRD }, |
181 | 181 | {"-S", TO_FILSOCK }, |
182 | 182 | {"-s", TO_FILGZ }, |
188 | 188 | {"-z", TO_STZER }, |
189 | 189 | {"", TO_NONOP } |
190 | 190 | }; |
191 | cta(u_ops_size, NELEM(u_ops) == 26); | |
191 | mbiCTAS(funcs_c) { | |
192 | mbiCTA(u_ops_size, NELEM(u_ops) == 26); | |
193 | }; | |
192 | 194 | const struct t_op b_ops[] = { |
193 | 195 | {"=", TO_STEQL }, |
194 | 196 | {"==", TO_STEQL }, |
385 | 387 | break; |
386 | 388 | case 'p': |
387 | 389 | if ((po.fd = coproc_getfd(W_OK, &emsg)) < 0) { |
388 | bi_errorf(Tf_coproc, emsg); | |
390 | bi_errorf("%s: %s", Tdp, emsg); | |
389 | 391 | return (1); |
390 | 392 | } |
391 | 393 | break; |
618 | 620 | static int |
619 | 621 | do_whence(const char **wp, int fcflags, bool vflag, bool iscommand) |
620 | 622 | { |
621 | uint32_t h; | |
623 | k32 h; | |
622 | 624 | int rv = 0; |
623 | 625 | struct tbl *tp; |
624 | 626 | const char *id; |
670 | 672 | break; |
671 | 673 | case CEXEC: |
672 | 674 | case CTALIAS: |
675 | if (vflag) | |
676 | shf_puts(id, shl_stdout); | |
673 | 677 | if (tp->flag & ISSET) { |
674 | 678 | if (vflag) { |
675 | shprintf("%s is ", id); | |
679 | shf_puts(" is ", shl_stdout); | |
676 | 680 | if (tp->type == CTALIAS) |
677 | 681 | shprintf("a tracked %s%s for ", |
678 | 682 | (tp->flag & EXPORT) ? |
681 | 685 | } |
682 | 686 | if (!mksh_abspath(tp->val.s)) { |
683 | 687 | const char *xcwd = current_wd[0] ? |
684 | current_wd : "."; | |
688 | current_wd : Tdot; | |
685 | 689 | size_t xlen = strlen(xcwd); |
686 | 690 | size_t clen = strlen(tp->val.s) + 1; |
687 | 691 | char *xp = alloc(xlen + 1 + clen, ATEMP); |
698 | 702 | shf_puts(tp->val.s, shl_stdout); |
699 | 703 | } else { |
700 | 704 | if (vflag) |
701 | shprintf(Tnot_found_s, id); | |
705 | shf_puts(Tsp_not_found, shl_stdout); | |
702 | 706 | rv = 1; |
703 | 707 | } |
704 | 708 | break; |
757 | 761 | struct table *t = &aliases; |
758 | 762 | int rv = 0, prefix = 0; |
759 | 763 | bool rflag = false, tflag, Uflag = false, pflag = false, chkalias; |
760 | uint32_t xflag = 0; | |
764 | kui xflag = 0; | |
761 | 765 | int optc; |
762 | 766 | |
763 | 767 | builtin_opt.flags |= GF_PLUSOPT; |
844 | 848 | const char *alias = *wp, *val, *newval; |
845 | 849 | char *xalias = NULL; |
846 | 850 | struct tbl *ap; |
847 | uint32_t h; | |
851 | k32 h; | |
848 | 852 | |
849 | 853 | if ((val = cstrchr(alias, '='))) { |
850 | 854 | strndupx(xalias, alias, val++ - alias, ATEMP); |
1065 | 1069 | int i, n, rv, sig; |
1066 | 1070 | |
1067 | 1071 | /* assume old style options if -digits or -UPPERCASE */ |
1068 | if ((p = wp[1]) && *p == '-' && ctype(p[1], C_DIGIT | C_UPPER)) { | |
1069 | if (!(t = gettrap(p + 1, false, false))) { | |
1070 | bi_errorf(Tbad_sig_s, p + 1); | |
1072 | if ((p = wp[1]) && isch(*p, '-') && ctype(p[1], C_DIGIT | C_UPPER)) { | |
1073 | ++p; | |
1074 | if (!(t = gettrap(p, false, false))) { | |
1075 | kwarnf(KWF_BIERR | KWF_TWOMSG | KWF_NOERRNO, | |
1076 | Tbad_sig, p); | |
1071 | 1077 | return (1); |
1072 | 1078 | } |
1073 | 1079 | i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; |
1082 | 1088 | case 's': |
1083 | 1089 | if (!(t = gettrap(builtin_opt.optarg, |
1084 | 1090 | true, false))) { |
1085 | bi_errorf(Tbad_sig_s, | |
1091 | kwarnf(KWF_BIERR | KWF_TWOMSG | | |
1092 | KWF_NOERRNO, Tbad_sig, | |
1086 | 1093 | builtin_opt.optarg); |
1087 | 1094 | return (1); |
1088 | 1095 | } |
1098 | 1105 | " { job | pid | pgrp } ...\n" |
1099 | 1106 | "\tkill -l [exit_status ...]\n", shl_out); |
1100 | 1107 | #endif |
1101 | bi_errorfz(); | |
1108 | bi_unwind(1); | |
1102 | 1109 | return (1); |
1103 | 1110 | } |
1104 | 1111 | |
1216 | 1223 | } |
1217 | 1224 | |
1218 | 1225 | if (e->loc->next == NULL) { |
1219 | internal_warningf(Tf_sD_s, Tgetopts, Tno_args); | |
1226 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_TWOMSG | KWF_NOERRNO, | |
1227 | Tgetopts, Tno_args); | |
1220 | 1228 | return (1); |
1221 | 1229 | } |
1222 | 1230 | /* Which arguments are we parsing... */ |
1340 | 1348 | n = 1; |
1341 | 1349 | else if (!evaluate(arg, &val, KSH_RETURN_ERROR, false)) { |
1342 | 1350 | /* error already printed */ |
1343 | bi_errorfz(); | |
1351 | bi_unwind(1); | |
1344 | 1352 | return (1); |
1345 | 1353 | } else if (!(n = val)) { |
1346 | 1354 | /* nothing to do */ |
1573 | 1581 | bool rawmode = false, expanding = false; |
1574 | 1582 | bool lastparmmode = false, lastparmused = false; |
1575 | 1583 | enum { LINES, BYTES, UPTO, READALL } readmode = LINES; |
1576 | char delim = '\n'; | |
1584 | kby delim = ORD('\n'); | |
1577 | 1585 | size_t bytesleft = 128, bytesread; |
1578 | 1586 | struct tbl *vp /* FU gcc */ = NULL, *vq = NULL; |
1579 | 1587 | char *cp, *allocd = NULL, *xp; |
1584 | 1592 | bool restore_tios = false; |
1585 | 1593 | /* to catch read -aN2 foo[i] */ |
1586 | 1594 | bool subarray = false; |
1595 | k32 idx = 0; | |
1587 | 1596 | #if HAVE_SELECT |
1588 | 1597 | bool hastimeout = false; |
1589 | 1598 | struct timeval tv, tvlim; |
1597 | 1606 | #endif |
1598 | 1607 | |
1599 | 1608 | while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1) |
1600 | switch (c) { | |
1601 | case 'a': | |
1609 | switch (ord(c)) { | |
1610 | case ORD('a'): | |
1602 | 1611 | aschars = true; |
1603 | 1612 | /* FALLTHROUGH */ |
1604 | case 'A': | |
1613 | case ORD('A'): | |
1605 | 1614 | intoarray = true; |
1606 | 1615 | break; |
1607 | case 'd': | |
1608 | delim = builtin_opt.optarg[0]; | |
1616 | case ORD('d'): | |
1617 | delim = ord(builtin_opt.optarg[0]); | |
1609 | 1618 | break; |
1610 | case 'N': | |
1611 | case 'n': | |
1612 | readmode = c == 'N' ? BYTES : UPTO; | |
1619 | case ORD('N'): | |
1620 | readmode = BYTES; | |
1621 | if (0) | |
1622 | /* FALLTHROUGH */ | |
1623 | case ORD('n'): | |
1624 | readmode = UPTO; | |
1613 | 1625 | if (!bi_getn(builtin_opt.optarg, &c)) |
1614 | 1626 | return (2); |
1615 | 1627 | if (c == -1) { |
1620 | 1632 | break; |
1621 | 1633 | case 'p': |
1622 | 1634 | if ((fd = coproc_getfd(R_OK, &ccp)) < 0) { |
1623 | bi_errorf(Tf_coproc, ccp); | |
1635 | bi_errorf("%s: %s", Tdp, ccp); | |
1624 | 1636 | return (2); |
1625 | 1637 | } |
1626 | 1638 | break; |
1644 | 1656 | if (!builtin_opt.optarg[0]) |
1645 | 1657 | fd = 0; |
1646 | 1658 | else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) { |
1647 | bi_errorf(Tf_sD_sD_s, Tdu, builtin_opt.optarg, ccp); | |
1659 | kwarnf(KWF_ERR(2) | KWF_PREFIX | KWF_FILELINE | | |
1660 | KWF_BUILTIN | KWF_BIUNWIND | KWF_THREEMSG, | |
1661 | Tdu, builtin_opt.optarg, ccp); | |
1648 | 1662 | return (2); |
1649 | 1663 | } |
1650 | 1664 | break; |
1790 | 1804 | } |
1791 | 1805 | if (expanding) { |
1792 | 1806 | expanding = false; |
1793 | if (c == delim) { | |
1807 | if (ord(c) == ord(delim)) { | |
1794 | 1808 | if (Flag(FTALKING_I) && isatty(fd)) { |
1795 | 1809 | /* |
1796 | 1810 | * set prompt in case this is |
1804 | 1818 | /* and the delimiter */ |
1805 | 1819 | break; |
1806 | 1820 | } |
1807 | } else if (c == delim) { | |
1821 | } else if (ord(c) == ord(delim)) { | |
1808 | 1822 | goto c_read_readdone; |
1809 | } else if (!rawmode && c == '\\') { | |
1823 | } else if (!rawmode && ord(c) == ORD('\\')) { | |
1810 | 1824 | expanding = true; |
1811 | 1825 | } |
1812 | 1826 | Xcheck(xs, xp); |
1844 | 1858 | subarray = last_lookup_was_array; |
1845 | 1859 | if (vp->flag & RDONLY) { |
1846 | 1860 | c_read_splitro: |
1847 | bi_errorf(Tf_ro, *wp); | |
1861 | kwarnf(KWF_BIERR | KWF_TWOMSG | KWF_NOERRNO, | |
1862 | Tread_only, *wp); | |
1848 | 1863 | c_read_spliterr: |
1849 | 1864 | rv = 2; |
1850 | 1865 | afree(cp, ATEMP); |
1851 | 1866 | goto c_read_out; |
1852 | 1867 | } |
1853 | 1868 | /* counter for array index */ |
1854 | c = subarray ? arrayindex(vp) : 0; | |
1869 | if (subarray) | |
1870 | idx = arrayindex(vp); | |
1855 | 1871 | /* exporting an array is currently pointless */ |
1856 | 1872 | unset(vp, subarray ? 0 : 1); |
1857 | 1873 | } |
1967 | 1983 | goto c_read_spliterr; |
1968 | 1984 | } |
1969 | 1985 | vq = vp; |
1970 | if (c) | |
1986 | if (idx) | |
1971 | 1987 | /* [0] doesn't */ |
1972 | 1988 | vq->flag |= AINDEX; |
1973 | } else | |
1974 | vq = arraysearch(vp, c++); | |
1989 | } else { | |
1990 | vq = arraysearch(vp, idx); | |
1991 | idx = K32(idx + 1); | |
1992 | } | |
1975 | 1993 | } else { |
1976 | 1994 | vq = global(*wp); |
1977 | 1995 | /* must be checked before exporting */ |
2096 | 2114 | i = 0; |
2097 | 2115 | while (*wp) |
2098 | 2116 | if (!(p = gettrap(*wp++, true, true))) { |
2099 | warningf(true, Tbad_sig_ss, builtin_argv0, wp[-1]); | |
2117 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_BUILTIN | | |
2118 | KWF_TWOMSG | KWF_NOERRNO, Tbad_sig, wp[-1]); | |
2100 | 2119 | i = 1; |
2101 | 2120 | } else |
2102 | 2121 | settrap(p, s); |
2184 | 2203 | * scripts, but don't generate an error (ie, keep going). |
2185 | 2204 | */ |
2186 | 2205 | if ((unsigned int)n == quit) { |
2187 | warningf(true, Tf_cant_s, wp[0], wp[0]); | |
2206 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, | |
2207 | Tf_cant_s, wp[0], wp[0]); | |
2188 | 2208 | return (0); |
2189 | 2209 | } |
2190 | 2210 | /* |
2194 | 2214 | */ |
2195 | 2215 | if (last_ep) |
2196 | 2216 | last_ep->flags &= ~EF_BRKCONT_PASS; |
2197 | warningf(true, "%s: can only %s %u level(s)", | |
2217 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, | |
2218 | "%s: can only %s %u level(s)", | |
2198 | 2219 | wp[0], wp[0], (unsigned int)n - quit); |
2199 | 2220 | } |
2200 | 2221 | |
2274 | 2295 | unset_var = true; |
2275 | 2296 | break; |
2276 | 2297 | case '?': |
2277 | /*XXX not reached due to GF_ERROR */ | |
2298 | /*XXX not reached due to GF_ERROR in spec_bi */ | |
2278 | 2299 | return (2); |
2279 | 2300 | } |
2280 | 2301 | wp += builtin_opt.optind; |
2299 | 2320 | afree(cp, ATEMP); |
2300 | 2321 | |
2301 | 2322 | if ((vp->flag&RDONLY)) { |
2302 | warningf(true, Tf_ro, vp->name); | |
2323 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
2324 | KWF_NOERRNO, Tread_only, vp->name); | |
2303 | 2325 | rv = 1; |
2304 | 2326 | } else |
2305 | 2327 | unset(vp, optc); |
2360 | 2382 | mksh_TIME(tv0); |
2361 | 2383 | if (ksh_getrusage(RUSAGE_SELF, &ru0) || |
2362 | 2384 | ksh_getrusage(RUSAGE_CHILDREN, &cru0)) { |
2363 | warningf(true, "time: getrusage: %s", cstrerror(errno)); | |
2385 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, | |
2386 | Ttime_getrusage); | |
2364 | 2387 | return (125); |
2365 | 2388 | } |
2366 | 2389 | if (t->left) { |
2380 | 2403 | mksh_TIME(tv1); |
2381 | 2404 | if (ksh_getrusage(RUSAGE_SELF, &ru1) || |
2382 | 2405 | ksh_getrusage(RUSAGE_CHILDREN, &cru1)) { |
2383 | warningf(true, "time: getrusage: %s", cstrerror(errno)); | |
2406 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, | |
2407 | Ttime_getrusage); | |
2384 | 2408 | return (rv); |
2385 | 2409 | } |
2386 | 2410 | } else |
2440 | 2464 | t->str[0] |= TF_POSIX; |
2441 | 2465 | break; |
2442 | 2466 | case '?': |
2443 | errorf(Tf_optfoo, Ttime, Tcolsp, | |
2444 | opt.optarg[0], Tunknown_option); | |
2467 | ksh_getopt_opterr(opt.optarg[0], Ttime, | |
2468 | Tunknown_option); | |
2469 | unwind(LERROR); | |
2445 | 2470 | case ':': |
2446 | errorf(Tf_optfoo, Ttime, Tcolsp, | |
2447 | opt.optarg[0], Treq_arg); | |
2471 | ksh_getopt_opterr(opt.optarg[0], Ttime, | |
2472 | Treq_arg); | |
2473 | unwind(LERROR); | |
2448 | 2474 | } |
2449 | 2475 | /* Copy command words down over options. */ |
2450 | 2476 | if (opt.optind != 0) { |
2479 | 2505 | close((int)sfd); |
2480 | 2506 | if (i > 2 && !(e->savedfd[i] & FDICLMASK) && |
2481 | 2507 | fcntl(i, F_SETFD, FD_CLOEXEC) == -1) |
2482 | internal_warningf(Tcloexec_failed, "set", i, | |
2483 | cstrerror(errno)); | |
2508 | kwarnf0(KWF_INTERNAL | KWF_WARNING, | |
2509 | Tcloexec_failed, "set", i); | |
2484 | 2510 | } |
2485 | 2511 | } else { |
2486 | 2512 | /* … but not for POSIX or legacy/kludge sh */ |
2545 | 2571 | |
2546 | 2572 | majnum = strtoul(argv[2], &c, 0); |
2547 | 2573 | if ((c == argv[2]) || (*c != '\0')) { |
2548 | bi_errorf(Tf_nonnum, "device", "major", argv[2]); | |
2574 | bi_errorf("%s: %s: %s", "major", "non-numeric", argv[2]); | |
2549 | 2575 | goto c_mknod_err; |
2550 | 2576 | } |
2551 | 2577 | minnum = strtoul(argv[3], &c, 0); |
2552 | 2578 | if ((c == argv[3]) || (*c != '\0')) { |
2553 | bi_errorf(Tf_nonnum, "device", "minor", argv[3]); | |
2579 | bi_errorf("%s: %s: %s", "minor", "non-numeric", argv[3]); | |
2554 | 2580 | goto c_mknod_err; |
2555 | 2581 | } |
2556 | 2582 | dv = makedev(majnum, minnum); |
2557 | 2583 | if ((unsigned long)(major(dv)) != majnum) { |
2558 | bi_errorf(Tf_toolarge, "device", "major", majnum); | |
2584 | bi_errorf(Tf_toolarge, "major", majnum); | |
2559 | 2585 | goto c_mknod_err; |
2560 | 2586 | } |
2561 | 2587 | if ((unsigned long)(minor(dv)) != minnum) { |
2562 | bi_errorf(Tf_toolarge, "device", "minor", minnum); | |
2588 | bi_errorf(Tf_toolarge, "minor", minnum); | |
2563 | 2589 | goto c_mknod_err; |
2564 | 2590 | } |
2565 | 2591 | if (mknod(argv[0], mode, dv)) |
3 | 3 | /*- |
4 | 4 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
5 | 5 | * 2011, 2012, 2014, 2015, 2016, 2017, 2018, 2019, |
6 | * 2021 | |
6 | * 2021, 2022 | |
7 | 7 | * mirabilos <m@mirbsd.org> |
8 | 8 | * |
9 | 9 | * Provided that these terms and disclaimer and all copyright notices |
23 | 23 | */ |
24 | 24 | |
25 | 25 | #include "sh.h" |
26 | #include "mirhash.h" | |
26 | 27 | #if HAVE_SYS_FILE_H |
27 | 28 | #include <sys/file.h> |
28 | 29 | #endif |
29 | 30 | |
30 | __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.176 2021/10/10 20:41:16 tg Exp $"); | |
31 | __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.185 2022/01/28 03:54:35 tg Exp $"); | |
31 | 32 | |
32 | 33 | Trap sigtraps[ksh_NSIG + 1]; |
33 | 34 | |
108 | 109 | size_t len = strlen(p); |
109 | 110 | |
110 | 111 | /* almost certainly not overflowing */ |
111 | editor = alloc(len + 4, ATEMP); | |
112 | editor = alloc(len + 6U, ATEMP); | |
112 | 113 | memcpy(editor, p, len); |
113 | memcpy(editor + len, Tspdollaru, 4); | |
114 | memcpy(editor + len, Tspdollaru, 6U); | |
114 | 115 | } |
115 | 116 | break; |
116 | 117 | |
293 | 294 | |
294 | 295 | tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps); |
295 | 296 | if (!(shf = tf->shf)) { |
296 | bi_errorf(Tf_temp, Tcreate, tf->tffn, cstrerror(errno)); | |
297 | kwarnf0(KWF_BIERR, Tf_temp, Tcreate, tf->tffn); | |
297 | 298 | return (1); |
298 | 299 | } |
299 | 300 | for (hp = rflag ? hlast : hfirst; |
300 | 301 | hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) |
301 | 302 | shf_fprintf(shf, Tf_sN, *hp); |
302 | 303 | if (shf_close(shf) == -1) { |
303 | bi_errorf(Tf_temp, Twrite, tf->tffn, cstrerror(errno)); | |
304 | kwarnf0(KWF_BIERR, Tf_temp, Twrite, tf->tffn); | |
304 | 305 | return (1); |
305 | 306 | } |
306 | 307 | |
317 | 318 | ssize_t n; |
318 | 319 | |
319 | 320 | if (!(shf = shf_open(tf->tffn, O_RDONLY, 0, 0))) { |
320 | bi_errorf(Tf_temp, Topen, tf->tffn, cstrerror(errno)); | |
321 | kwarnf0(KWF_BIERR, Tf_temp, Topen, tf->tffn); | |
321 | 322 | return (1); |
322 | 323 | } |
323 | 324 | |
324 | 325 | if (stat(tf->tffn, &statb) < 0) |
325 | 326 | n = 128; |
326 | 327 | else if ((off_t)statb.st_size > MKSH_MAXHISTFSIZE) { |
327 | bi_errorf(Tf_toolarge, Thistory, | |
328 | Tfile, (unsigned long)statb.st_size); | |
328 | bi_errorf(Tf_toolarge, Tfile, | |
329 | (unsigned long)statb.st_size); | |
329 | 330 | goto errout; |
330 | 331 | } else |
331 | 332 | n = (size_t)statb.st_size + 1; |
336 | 337 | XcheckN(xs, xp, Xlength(xs, xp)); |
337 | 338 | } |
338 | 339 | if (n < 0) { |
339 | bi_errorf(Tf_temp, Tread, tf->tffn, | |
340 | cstrerror(shf_errno(shf))); | |
340 | kwarnf1(KWF_VERRNO | KWF_BIERR, shf_errno(shf), | |
341 | Tf_temp, Tread, tf->tffn); | |
341 | 342 | errout: |
342 | 343 | shf_close(shf); |
343 | 344 | return (1); |
870 | 871 | goto retry; |
871 | 872 | } |
872 | 873 | if (hs != hist_init_retry) |
873 | bi_errorf(Tf_cant_ss_s, | |
874 | bi_errorf("can't %s %s: %s", | |
874 | 875 | "unlink HISTFILE", hname, cstrerror(errno)); |
875 | 876 | histfsize = 0; |
876 | 877 | return; |
1036 | 1037 | |
1037 | 1038 | /* +++ signals +++ */ |
1038 | 1039 | |
1039 | #if !HAVE_SYS_SIGNAME | |
1040 | #if !HAVE_SIGABBREV_NP && !HAVE_SYS_SIGNAME | |
1040 | 1041 | static const struct mksh_sigpair { |
1041 | 1042 | const char * const name; |
1042 | 1043 | int nr; |
1046 | 1047 | }; |
1047 | 1048 | #endif |
1048 | 1049 | |
1049 | #if HAVE_SYS_SIGLIST | |
1050 | #if !HAVE_SYS_SIGLIST_DECL | |
1051 | extern const char * const sys_siglist[]; | |
1052 | #endif | |
1053 | #endif | |
1054 | ||
1055 | 1050 | void |
1056 | 1051 | inittraps(void) |
1057 | 1052 | { |
1058 | 1053 | int i; |
1059 | 1054 | const char *cs; |
1060 | #if !HAVE_SYS_SIGNAME | |
1055 | #if !HAVE_SIGABBREV_NP && !HAVE_SYS_SIGNAME | |
1061 | 1056 | const struct mksh_sigpair *pair; |
1062 | 1057 | #endif |
1063 | 1058 | |
1066 | 1061 | /* populate sigtraps based on sys_signame and sys_siglist */ |
1067 | 1062 | for (i = 1; i < ksh_NSIG; i++) { |
1068 | 1063 | sigtraps[i].signal = i; |
1069 | #if HAVE_SYS_SIGNAME | |
1064 | #if HAVE_SIGABBREV_NP | |
1065 | cs = sigabbrev_np(i); | |
1066 | #elif HAVE_SYS_SIGNAME | |
1070 | 1067 | cs = sys_signame[i]; |
1071 | 1068 | #else |
1072 | 1069 | pair = mksh_sigpairs; |
1081 | 1078 | char *s; |
1082 | 1079 | |
1083 | 1080 | /* this is not optimal, what about SIGSIG1? */ |
1084 | if (ksh_eq(cs[0], 'S', 's') && | |
1085 | ksh_eq(cs[1], 'I', 'i') && | |
1086 | ksh_eq(cs[2], 'G', 'g') && | |
1081 | if (isCh(cs[0], 'S', 's') && | |
1082 | isCh(cs[1], 'I', 'i') && | |
1083 | isCh(cs[2], 'G', 'g') && | |
1087 | 1084 | cs[3] != '\0') { |
1088 | 1085 | /* skip leading "SIG" */ |
1089 | 1086 | cs += 3; |
1096 | 1093 | if (!strcmp(sigtraps[i].name, "EXIT") || |
1097 | 1094 | !strcmp(sigtraps[i].name, "ERR")) { |
1098 | 1095 | #ifndef MKSH_SMALL |
1099 | internal_warningf(Tinvname, sigtraps[i].name, | |
1100 | "signal"); | |
1096 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1097 | Tinvname, sigtraps[i].name, "signal"); | |
1101 | 1098 | #endif |
1102 | 1099 | sigtraps[i].name = null; |
1103 | 1100 | } |
1104 | 1101 | } |
1105 | 1102 | if (sigtraps[i].name == null) |
1106 | 1103 | sigtraps[i].name = shf_smprintf(Tf_d, i); |
1107 | #if HAVE_SYS_SIGLIST | |
1108 | sigtraps[i].mess = sys_siglist[i]; | |
1109 | #elif HAVE_STRSIGNAL | |
1110 | sigtraps[i].mess = strsignal(i); | |
1111 | #else | |
1112 | sigtraps[i].mess = NULL; | |
1113 | #endif | |
1114 | if ((sigtraps[i].mess == NULL) || | |
1115 | (sigtraps[i].mess[0] == '\0')) | |
1104 | sigtraps[i].mess = ksh_sigmess(i); | |
1105 | if (ksh_sigmessf(sigtraps[i].mess)) | |
1116 | 1106 | sigtraps[i].mess = shf_smprintf(Tf_sd, |
1117 | 1107 | "Signal", i); |
1118 | 1108 | } |
1180 | 1170 | /* do a lookup by name then */ |
1181 | 1171 | |
1182 | 1172 | /* this breaks SIGSIG1, but we do that above anyway */ |
1183 | if (ksh_eq(cs[0], 'S', 's') && | |
1184 | ksh_eq(cs[1], 'I', 'i') && | |
1185 | ksh_eq(cs[2], 'G', 'g') && | |
1173 | if (isCh(cs[0], 'S', 's') && | |
1174 | isCh(cs[1], 'I', 'i') && | |
1175 | isCh(cs[2], 'G', 'g') && | |
1186 | 1176 | cs[3] != '\0') { |
1187 | 1177 | /* skip leading "SIG" */ |
1188 | 1178 | cs += 3; |
1219 | 1209 | return (p); |
1220 | 1210 | } |
1221 | 1211 | |
1212 | static k32 | |
1213 | traphash(int signo, int extra) | |
1214 | { | |
1215 | register k32 h; | |
1216 | static volatile k32 state; | |
1217 | k32 o; | |
1218 | struct { | |
1219 | struct timeval tv; | |
1220 | void *sp; | |
1221 | int i; | |
1222 | int j; | |
1223 | } z; | |
1224 | ||
1225 | memset(&z, 0, sizeof(z)); | |
1226 | mksh_TIME(z.tv); | |
1227 | z.sp = &z; | |
1228 | z.i = signo; | |
1229 | z.j = extra; | |
1230 | ||
1231 | o = h = state; | |
1232 | BAFHUpdateMem(h, &z, sizeof(z)); | |
1233 | while (state != o) { | |
1234 | o = state; | |
1235 | BAFHUpdateMem(h, &o, sizeof(o)); | |
1236 | } | |
1237 | state = h; | |
1238 | return (h); | |
1239 | } | |
1240 | ||
1222 | 1241 | /* |
1223 | 1242 | * trap signal handler |
1224 | 1243 | */ |
1225 | 1244 | void |
1226 | 1245 | trapsig(int i) |
1227 | 1246 | { |
1228 | Trap *p = &sigtraps[i]; | |
1229 | int eno = errno; | |
1230 | ||
1247 | Trap *p; | |
1248 | int eno; | |
1249 | ||
1250 | eno = errno; | |
1251 | traphash(i, eno); | |
1252 | p = &sigtraps[i]; | |
1231 | 1253 | trap = p->set = 1; |
1232 | 1254 | if (p->flags & TF_DFL_INTR) |
1233 | 1255 | intrsig = 1; |
1300 | 1322 | { |
1301 | 1323 | Trap *p = sigtraps; |
1302 | 1324 | int i = ksh_NSIG + 1; |
1325 | k32 h; | |
1326 | ||
1327 | h = traphash(-666, (int)ksh_tmout_state); | |
1328 | rndpush(&h, sizeof(h)); | |
1303 | 1329 | |
1304 | 1330 | if (ksh_tmout_state == TMOUT_LEAVING) { |
1305 | 1331 | ksh_tmout_state = TMOUT_EXECUTING; |
1306 | warningf(false, "timed out waiting for input"); | |
1332 | kwarnf(KWF_PREFIX | KWF_ONEMSG | KWF_NOERRNO, | |
1333 | "timed out waiting for input"); | |
1307 | 1334 | unwind(LEXIT); |
1308 | 1335 | } else |
1309 | 1336 | /* |
1547 | 1574 | { |
1548 | 1575 | /* XXX debugging */ |
1549 | 1576 | if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) |
1550 | internal_errorf("setexecsig: unset signal %d(%s)", | |
1551 | p->signal, p->name); | |
1577 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
1578 | "setexecsig: unset signal %d(%s)", p->signal, p->name); | |
1552 | 1579 | |
1553 | 1580 | /* restore original value for exec'd kids */ |
1554 | 1581 | p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); |
25 | 25 | #include <poll.h> |
26 | 26 | #endif |
27 | 27 | |
28 | __RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.145 2021/10/10 20:41:17 tg Exp $"); | |
28 | __RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.151 2022/01/28 10:28:18 tg Exp $"); | |
29 | 29 | |
30 | 30 | #if HAVE_KILLPG |
31 | 31 | #define mksh_killpg killpg |
261 | 261 | mksh_tcset(tty_fd, &tty_state); |
262 | 262 | if (restore_ttypgrp >= 0) { |
263 | 263 | if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) { |
264 | warningf(false, Tf_ssfaileds, | |
265 | Tj_suspend, "tcsetpgrp", cstrerror(errno)); | |
264 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
265 | Tj_suspend, "tcsetpgrp"); | |
266 | 266 | } else if (setpgid(0, restore_ttypgrp) < 0) { |
267 | warningf(false, Tf_ssfaileds, | |
268 | Tj_suspend, "setpgid", cstrerror(errno)); | |
267 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
268 | Tj_suspend, "setpgid"); | |
269 | 269 | } |
270 | 270 | } |
271 | 271 | } |
279 | 279 | if (ttypgrp_ok) { |
280 | 280 | if (restore_ttypgrp >= 0) { |
281 | 281 | if (setpgid(0, kshpid) < 0) { |
282 | warningf(false, Tf_ssfaileds, | |
283 | Tj_suspend, "setpgid", cstrerror(errno)); | |
282 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
283 | Tj_suspend, "setpgid"); | |
284 | 284 | ttypgrp_ok = false; |
285 | 285 | } else if (tcsetpgrp(tty_fd, kshpid) < 0) { |
286 | warningf(false, Tf_ssfaileds, | |
287 | Tj_suspend, "tcsetpgrp", cstrerror(errno)); | |
286 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
287 | Tj_suspend, "tcsetpgrp"); | |
288 | 288 | ttypgrp_ok = false; |
289 | 289 | } |
290 | 290 | } |
369 | 369 | pid_t ttypgrp; |
370 | 370 | |
371 | 371 | if ((ttypgrp = tcgetpgrp(tty_fd)) < 0) { |
372 | warningf(false, Tf_ssfaileds, | |
373 | "j_init", "tcgetpgrp", | |
374 | cstrerror(errno)); | |
372 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
373 | "j_init", "tcgetpgrp"); | |
375 | 374 | ttypgrp_ok = false; |
376 | 375 | break; |
377 | 376 | } |
385 | 384 | SS_RESTORE_DFL|SS_FORCE); |
386 | 385 | if (ttypgrp_ok && kshpgrp != kshpid) { |
387 | 386 | if (setpgid(0, kshpid) < 0) { |
388 | warningf(false, Tf_ssfaileds, | |
389 | "j_init", "setpgid", cstrerror(errno)); | |
387 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
388 | "j_init", "setpgid"); | |
390 | 389 | ttypgrp_ok = false; |
391 | 390 | } else { |
392 | 391 | if (tcsetpgrp(tty_fd, kshpid) < 0) { |
393 | warningf(false, Tf_ssfaileds, | |
394 | "j_init", "tcsetpgrp", | |
395 | cstrerror(errno)); | |
392 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
393 | "j_init", "tcsetpgrp"); | |
396 | 394 | ttypgrp_ok = false; |
397 | 395 | } else |
398 | 396 | restore_ttypgrp = kshpgrp; |
401 | 399 | } |
402 | 400 | #ifndef MKSH_DISABLE_TTY_WARNING |
403 | 401 | if (use_tty && !ttypgrp_ok) |
404 | warningf(false, Tf_sD_s, "warning", | |
402 | kwarnf(KWF_PREFIX | KWF_ONEMSG | KWF_NOERRNO, | |
405 | 403 | "won't have full job control"); |
406 | 404 | #endif |
407 | 405 | } else { |
435 | 433 | errno = 0; |
436 | 434 | /* this is gonna annoy users; complain to your distro, people! */ |
437 | 435 | if (nice(ness) == -1 && (eno = errno) != 0) |
438 | warningf(false, Tf_sD_s, "bgnice", cstrerror(eno)); | |
436 | kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_ONEMSG, eno, "bgnice"); | |
439 | 437 | #else |
440 | 438 | (void)nice(ness); |
441 | 439 | #endif |
453 | 451 | static Proc *last_proc; |
454 | 452 | |
455 | 453 | int rv = 0, forksleep, jwflags = JW_NONE; |
454 | int eno = /* stupid GCC */ 0; | |
456 | 455 | #ifndef MKSH_NOPROSPECTOFWORK |
457 | 456 | sigset_t omask; |
458 | 457 | #endif |
487 | 486 | if (flags & XPIPEI) { |
488 | 487 | /* continuing with a pipe */ |
489 | 488 | if (!last_job) |
490 | internal_errorf("exchild: XPIPEI and no last_job - pid %d", | |
491 | (int)procpid); | |
489 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
490 | "exchild: XPIPEI and no last_job - pid %ld", | |
491 | (long)procpid); | |
492 | 492 | j = last_job; |
493 | 493 | if (last_proc) |
494 | 494 | last_proc->next = p; |
519 | 519 | |
520 | 520 | /* create child process */ |
521 | 521 | forksleep = 1; |
522 | while ((cldpid = fork()) < 0 && errno == EAGAIN && forksleep < 32) { | |
522 | while ((cldpid = fork()) < 0 && (eno = errno) == EAGAIN && | |
523 | forksleep < 32) { | |
523 | 524 | if (intrsig) |
524 | 525 | /* allow user to ^C out... */ |
525 | 526 | break; |
535 | 536 | #ifndef MKSH_NOPROSPECTOFWORK |
536 | 537 | sigprocmask(SIG_SETMASK, &omask, NULL); |
537 | 538 | #endif |
538 | errorf("can't fork - try again"); | |
539 | kerrf(KWF_VERRNO | KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
540 | KWF_ONEMSG, eno, "can't fork - try again"); | |
539 | 541 | } |
540 | 542 | p->pid = cldpid ? cldpid : (procpid = getpid()); |
541 | 543 | |
620 | 622 | #ifndef MKSH_SMALL |
621 | 623 | if (t->type == TPIPE) |
622 | 624 | unwind(LLEAVE); |
623 | internal_warningf("%s: execute() returned", "exchild"); | |
625 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_TWOMSG, | |
626 | "exchild", "execute() returned"); | |
624 | 627 | fptreef(shl_out, 8, "%s: tried to execute {\n\t%T\n}\n", |
625 | 628 | "exchild", t); |
626 | 629 | shf_flush(shl_out); |
697 | 700 | j = last_job; |
698 | 701 | if (!j || !(j->flags & JF_STARTED)) { |
699 | 702 | if (!j) |
700 | warningf(true, Tf_sD_s, "waitlast", "no last job"); | |
703 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
704 | KWF_NOERRNO, "waitlast", "no last job"); | |
701 | 705 | else |
702 | internal_warningf(Tf_sD_s, "waitlast", Tnot_started); | |
706 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_TWOMSG | KWF_NOERRNO, | |
707 | "waitlast", Tnot_started); | |
703 | 708 | #ifndef MKSH_NOPROSPECTOFWORK |
704 | 709 | sigprocmask(SIG_SETMASK, &omask, NULL); |
705 | 710 | #endif |
883 | 888 | if (j->flags & JF_SAVEDTTY) |
884 | 889 | mksh_tcset(tty_fd, &tty_state); |
885 | 890 | sigprocmask(SIG_SETMASK, &omask, NULL); |
886 | bi_errorf(Tf_ldfailed, | |
887 | "fg: 1st", "tcsetpgrp", tty_fd, | |
891 | kwarnf1(KWF_VERRNO | KWF_BIERR, rv, | |
892 | Tf_ldfailed, Tfirst, tty_fd, | |
888 | 893 | (long)((j->flags & JF_SAVEDTTYPGRP) ? |
889 | j->saved_ttypgrp : j->pgrp), | |
890 | cstrerror(rv)); | |
894 | j->saved_ttypgrp : j->pgrp)); | |
891 | 895 | return (1); |
892 | 896 | } |
893 | 897 | } |
905 | 909 | if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) |
906 | 910 | mksh_tcset(tty_fd, &tty_state); |
907 | 911 | if (ttypgrp_ok && tcsetpgrp(tty_fd, kshpgrp) < 0) |
908 | warningf(true, Tf_ldfailed, | |
909 | "fg: 2nd", "tcsetpgrp", tty_fd, | |
910 | (long)kshpgrp, cstrerror(errno)); | |
912 | kwarnf0(KWF_PREFIX | KWF_FILELINE, | |
913 | Tf_ldfailed, "second", tty_fd, | |
914 | (long)kshpgrp); | |
911 | 915 | } |
912 | 916 | sigprocmask(SIG_SETMASK, &omask, NULL); |
913 | 917 | bi_errorf(Tf_s_sD_s, "can't continue job", |
1078 | 1082 | if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE) |
1079 | 1083 | remove_job(async_job, "async"); |
1080 | 1084 | if (!(j->flags & JF_STARTED)) { |
1081 | internal_warningf(Tf_sD_s, "j_async", Tjob_not_started); | |
1085 | kwarnf(KWF_INTERNAL | KWF_WARNING | KWF_TWOMSG | KWF_NOERRNO, | |
1086 | "j_async", Tjob_not_started); | |
1082 | 1087 | return; |
1083 | 1088 | } |
1084 | 1089 | async_job = j; |
1092 | 1097 | if (!oldest) { |
1093 | 1098 | /* XXX debugging */ |
1094 | 1099 | if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) { |
1095 | internal_warningf("%s: bad nzombie (%d)", | |
1096 | "j_async", nzombie); | |
1100 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1101 | "%s: bad nzombie (%d)", "j_async", nzombie); | |
1097 | 1102 | nzombie = 0; |
1098 | 1103 | } |
1099 | 1104 | break; |
1206 | 1211 | (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0) |
1207 | 1212 | j->flags |= JF_SAVEDTTYPGRP; |
1208 | 1213 | if (tcsetpgrp(tty_fd, kshpgrp) < 0) |
1209 | warningf(true, Tf_ldfailed, | |
1210 | "j_waitj:", "tcsetpgrp", tty_fd, | |
1211 | (long)kshpgrp, cstrerror(errno)); | |
1214 | kwarnf0(KWF_PREFIX | KWF_FILELINE, | |
1215 | Tf_ldfailed, "wait", tty_fd, | |
1216 | (long)kshpgrp); | |
1212 | 1217 | if (j->state == PSTOPPED) { |
1213 | 1218 | j->flags |= JF_SAVEDTTY; |
1214 | 1219 | mksh_tcget(tty_fd, &j->ttystat); |
1272 | 1277 | if (!(p = j->proc_list)) { |
1273 | 1278 | ; /* nothing */ |
1274 | 1279 | } else if (flags & JW_PIPEST) { |
1275 | uint32_t num = 0; | |
1280 | k32 num = 0; | |
1276 | 1281 | struct tbl *vp; |
1277 | 1282 | kby *vt; |
1278 | 1283 | |
1290 | 1295 | vp->u.array = (void *)vt; |
1291 | 1296 | vp = (void *)vt; |
1292 | 1297 | vp->areap = vp_pipest->areap; |
1293 | vp->ua.index = ++num; | |
1298 | vp->ua.index = num = K32(num + 1); | |
1294 | 1299 | vp->flag = DEFINED | ISSET | INTEGER | RDONLY | |
1295 | 1300 | ARRAY | INT_U | AINDEX; |
1296 | 1301 | got_array: |
1363 | 1368 | #endif |
1364 | 1369 | |
1365 | 1370 | if (ksh_getrusage(RUSAGE_CHILDREN, &ru0)) |
1366 | warningf(true, "getrusage1: %s", cstrerror(errno)); | |
1371 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, Tgetrusage); | |
1367 | 1372 | do { |
1368 | 1373 | #ifndef MKSH_NOPROSPECTOFWORK |
1369 | 1374 | pid = waitpid(-1, &status, (WNOHANG | |
1383 | 1388 | goto j_sigchld_out; |
1384 | 1389 | |
1385 | 1390 | if (ksh_getrusage(RUSAGE_CHILDREN, &ru1)) |
1386 | warningf(true, "getrusage2: %s", cstrerror(errno)); | |
1391 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, | |
1392 | Tgetrusage); | |
1387 | 1393 | |
1388 | 1394 | /* find job and process structures for this pid */ |
1389 | 1395 | for (j = job_list; j != NULL; j = j->next) |
1393 | 1399 | found: |
1394 | 1400 | if (j == NULL) { |
1395 | 1401 | /* Can occur if process has kids, then execs shell |
1396 | warningf(true, "bad process waited for (pid = %d)", | |
1397 | pid); | |
1402 | kwarnf0(KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, | |
1403 | "bad process waited for (pid = %d)", pid); | |
1398 | 1404 | */ |
1399 | 1405 | ru0 = ru1; |
1400 | 1406 | continue; |
1455 | 1461 | |
1456 | 1462 | /* XXX debugging (nasty - interrupt routine using shl_out) */ |
1457 | 1463 | if (!(j->flags & JF_STARTED)) { |
1458 | internal_warningf("check_job: job started (flags 0x%X)", | |
1464 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1465 | "check_job: job started (flags 0x%X)", | |
1459 | 1466 | (unsigned int)j->flags); |
1460 | 1467 | return; |
1461 | 1468 | } |
1606 | 1613 | msg = "Done"; |
1607 | 1614 | else { |
1608 | 1615 | shf_snprintf(msgbuf, sizeof(msgbuf), |
1609 | "Done (%d)", status); | |
1616 | TDone, status); | |
1610 | 1617 | msg = msgbuf; |
1611 | 1618 | } |
1612 | 1619 | break; |
1862 | 1869 | curr = *prev; |
1863 | 1870 | } |
1864 | 1871 | if (curr != j) { |
1865 | internal_warningf("remove_job: job %s (%s)", Tnot_found, where); | |
1872 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1873 | "remove_job: job %s (%s)", Tnot_found, where); | |
1866 | 1874 | return; |
1867 | 1875 | } |
1868 | 1876 | *prev = curr->next; |
1951 | 1959 | break; |
1952 | 1960 | case 1: |
1953 | 1961 | #ifndef MKSH_DISABLE_TTY_WARNING |
1954 | warningf(false, "can't find controlling tty: %s", | |
1955 | cstrerror(errno)); | |
1962 | kwarnf(KWF_PREFIX | KWF_ONEMSG, "can't find controlling tty"); | |
1956 | 1963 | #endif |
1957 | 1964 | break; |
1958 | 1965 | case 2: |
1959 | 1966 | #ifndef MKSH_DISABLE_TTY_WARNING |
1960 | warningf(false, "can't find tty fd: %s", | |
1961 | cstrerror(errno)); | |
1967 | kwarnf(KWF_PREFIX | KWF_ONEMSG, "can't find tty fd"); | |
1962 | 1968 | #endif |
1963 | 1969 | break; |
1964 | 1970 | case 3: |
1965 | warningf(false, Tf_ssfaileds, "j_ttyinit", | |
1966 | "dup of tty fd", cstrerror(errno)); | |
1971 | kwarnf0(KWF_PREFIX, Tf_ssfailed, | |
1972 | "j_ttyinit", "dup of tty fd"); | |
1967 | 1973 | break; |
1968 | 1974 | case 4: |
1969 | warningf(false, Tf_sD_sD_s, "j_ttyinit", | |
1970 | "can't set close-on-exec flag", cstrerror(errno)); | |
1975 | kwarnf(KWF_PREFIX | KWF_TWOMSG, "j_ttyinit", | |
1976 | "can't set close-on-exec flag"); | |
1971 | 1977 | break; |
1972 | 1978 | } |
1973 | 1979 | } |
0 | 0 | /*- |
1 | * Copyright (c) 2009, 2010, 2011, 2013, 2014, 2016 | |
1 | * Copyright (c) 2009, 2010, 2011, 2013, 2014, 2016, 2021 | |
2 | 2 | * mirabilos <m@mirbsd.org> |
3 | 3 | * |
4 | 4 | * Provided that these terms and disclaimer and all copyright notices |
22 | 22 | #include <err.h> |
23 | 23 | #endif |
24 | 24 | |
25 | __RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.28 2021/10/10 20:41:17 tg Exp $"); | |
25 | __RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.31 2021/11/13 21:22:36 tg Exp $"); | |
26 | 26 | |
27 | 27 | /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */ |
28 | 28 | #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0) |
54 | 54 | { |
55 | 55 | struct lalloc_item *lp, *lold = ptr; |
56 | 56 | |
57 | size = (size + 4095) & ~(size_t)4095; | |
57 | size = (size + 4095U) & (size_t)~(size_t)4095; | |
58 | 58 | |
59 | 59 | if (lold && lold->len >= size) |
60 | 60 | return (ptr); |
79 | 79 | } |
80 | 80 | #endif |
81 | 81 | |
82 | /* pre-initio() */ | |
82 | 83 | void |
83 | 84 | ainit(Area *ap) |
84 | 85 | { |
116 | 117 | fail: |
117 | 118 | #endif |
118 | 119 | #ifdef DEBUG |
119 | internal_warningf("rogue pointer %zX in ap %zX", | |
120 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
121 | "rogue pointer %zX in ap %zX", | |
120 | 122 | (size_t)ptr, (size_t)ap); |
121 | 123 | /* try to get a coredump */ |
122 | 124 | abort(); |
123 | 125 | #else |
124 | internal_errorf("rogue pointer %zX", (size_t)ptr); | |
126 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
127 | "rogue pointer %zX", (size_t)ptr); | |
125 | 128 | #endif |
126 | 129 | } |
127 | 130 | return (ap); |
128 | 131 | } |
129 | 132 | |
133 | /* pre-initio() */ | |
130 | 134 | void * |
131 | 135 | aresize2(void *ptr, size_t fac1, size_t fac2, Area *ap) |
132 | 136 | { |
133 | 137 | if (notoktomul(fac1, fac2)) |
134 | internal_errorf(Tintovfl, fac1, '*', fac2); | |
138 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
139 | Tintovfl, fac1, '*', fac2); | |
135 | 140 | return (aresize(ptr, fac1 * fac2, ap)); |
136 | 141 | } |
137 | 142 | |
143 | /* pre-initio() ptr=NULL */ | |
138 | 144 | void * |
139 | 145 | aresize(void *ptr, size_t numb, Area *ap) |
140 | 146 | { |
148 | 154 | pp->next = lp->next; |
149 | 155 | } |
150 | 156 | |
151 | if (notoktoadd(numb, sizeof(ALLOC_ITEM)) || | |
152 | (lp = remalloc(lp, numb + sizeof(ALLOC_ITEM))) == NULL | |
157 | if (notoktoadd(numb, sizeof(ALLOC_ITEM))) { | |
158 | errno = E2BIG; | |
159 | alloc_fail: | |
160 | if (!initio_done) { | |
161 | SHIKATANAI write(2, SC("mksh: out of memory early\n")); | |
162 | exit(255); | |
163 | } | |
164 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF), | |
165 | "can't allocate %zu data bytes", numb); | |
166 | } | |
167 | if ((lp = remalloc(lp, numb + sizeof(ALLOC_ITEM))) == NULL) | |
168 | goto alloc_fail; | |
153 | 169 | #ifndef MKSH_SMALL |
154 | || ALLOC_ISUNALIGNED(lp) | |
155 | #endif | |
156 | ) | |
157 | internal_errorf(Toomem, numb); | |
170 | if (ALLOC_ISUNALIGNED(lp)) { | |
171 | #ifdef EPROTO | |
172 | errno = EPROTO; | |
173 | #endif | |
174 | goto alloc_fail; | |
175 | } | |
176 | #endif | |
177 | ||
158 | 178 | /* area pointer and items share struct lalloc_common */ |
159 | 179 | /*XXX C99 §6.5(6) and footnote 72 may dislike this? */ |
160 | 180 | lp->next = ap->next; |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | 4 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
5 | * 2021 | |
5 | * 2021, 2022 | |
6 | 6 | * mirabilos <m@mirbsd.org> |
7 | 7 | * |
8 | 8 | * Provided that these terms and disclaimer and all copyright notices |
23 | 23 | |
24 | 24 | #include "sh.h" |
25 | 25 | |
26 | __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.261 2021/10/10 21:36:53 tg Exp $"); | |
26 | __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.263 2022/01/06 22:34:58 tg Exp $"); | |
27 | 27 | |
28 | 28 | /* |
29 | 29 | * states while lexing word |
1041 | 1041 | |
1042 | 1042 | if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) { |
1043 | 1043 | struct tbl *p; |
1044 | uint32_t h = hash(ident); | |
1044 | k32 h = hash(ident); | |
1045 | 1045 | |
1046 | 1046 | if ((cf & KEYWORD) && (p = ktsearch(&keywords, ident, h)) && |
1047 | 1047 | (!(cf & ESACONLY) || p->val.i == ESAC || |
1098 | 1098 | } else if (*ident == '\0') { |
1099 | 1099 | /* retain typeset et al. even when quoted */ |
1100 | 1100 | struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0))); |
1101 | uint32_t flag = tt ? tt->flag : 0; | |
1101 | kui flag = tt ? tt->flag : 0U; | |
1102 | 1102 | |
1103 | 1103 | if (flag & (DECL_UTIL | DECL_FWDR)) |
1104 | 1104 | strlcpy(ident, dp, sizeof(ident)); |
1207 | 1207 | |
1208 | 1208 | if (!(iop->ioflag & IOEVAL)) |
1209 | 1209 | ignore_backslash_newline--; |
1210 | } | |
1211 | ||
1212 | void | |
1213 | yyerror(const char *fmt, ...) | |
1214 | { | |
1215 | va_list va; | |
1216 | ||
1217 | /* pop aliases and re-reads */ | |
1218 | while (source->type == SALIAS || source->type == SREREAD) | |
1219 | source = source->next; | |
1220 | /* zap pending input */ | |
1221 | source->str = null; | |
1222 | ||
1223 | error_prefix(true); | |
1224 | va_start(va, fmt); | |
1225 | shf_vfprintf(shl_out, fmt, va); | |
1226 | shf_putc('\n', shl_out); | |
1227 | va_end(va); | |
1228 | errorfz(); | |
1229 | 1210 | } |
1230 | 1211 | |
1231 | 1212 | /* |
1429 | 1410 | alarm(0); |
1430 | 1411 | } |
1431 | 1412 | cp = Xstring(s->xs, xp); |
1432 | rndpush(cp); | |
1433 | 1413 | s->start = s->str = cp; |
1434 | 1414 | strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp)); |
1435 | 1415 | /* Note: if input is all nulls, this is not eof */ |
0 | .\" $MirOS: src/bin/mksh/lksh.1,v 1.28 2021/06/15 13:20:05 tg Exp $ | |
0 | .\" $MirOS: src/bin/mksh/lksh.1,v 1.30 2022/01/28 10:28:19 tg Exp $ | |
1 | 1 | .\"- |
2 | .\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2018 | |
2 | .\" Copyright © 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, | |
3 | .\" 2018 | |
3 | 4 | .\" mirabilos <m@mirbsd.org> |
4 | 5 | .\" |
5 | 6 | .\" Provided that these terms and disclaimer and all copyright notices |
60 | 61 | . ds en \(em |
61 | 62 | .\} |
62 | 63 | .ie n \{\ |
63 | . ds EM \ \*(en\ \& | |
64 | . ds EM \ \(em\ \& | |
64 | 65 | .\} |
65 | 66 | .el \{\ |
66 | 67 | . ds EM \f(TR\^\(em\^\fP |
80 | 81 | .\" with -mandoc, it might implement .Mx itself, but we want to |
81 | 82 | .\" use our own definition. And .Dd must come *first*, always. |
82 | 83 | .\" |
83 | .Dd $Mdocdate: June 15 2021 $ | |
84 | .Dd $Mdocdate: January 28 2022 $ | |
84 | 85 | .\" |
85 | 86 | .\" Check which macro package we use, and do other -mdoc setup. |
86 | 87 | .\" |
5 | 5 | /*- |
6 | 6 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
7 | 7 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
8 | * 2019, 2020, 2021 | |
8 | * 2019, 2020, 2021, 2022 | |
9 | 9 | * mirabilos <m@mirbsd.org> |
10 | 10 | * |
11 | 11 | * Provided that these terms and disclaimer and all copyright notices |
27 | 27 | #define EXTERN |
28 | 28 | #include "sh.h" |
29 | 29 | |
30 | #if HAVE_LANGINFO_CODESET | |
30 | #if HAVE_POSIX_UTF8_LOCALE | |
31 | #include <locale.h> | |
31 | 32 | #include <langinfo.h> |
32 | 33 | #endif |
33 | #if HAVE_SETLOCALE_CTYPE | |
34 | #include <locale.h> | |
35 | #endif | |
36 | ||
37 | __RCSID("$MirOS: src/bin/mksh/main.c,v 1.398 2021/10/12 23:18:13 tg Exp $"); | |
34 | ||
35 | __RCSID("$MirOS: src/bin/mksh/main.c,v 1.411 2022/01/27 13:45:05 tg Exp $"); | |
36 | __IDSTRING(mbsdint_h_rcsid, SYSKERN_MBSDINT_H); | |
37 | __IDSTRING(sh_h_rcsid, MKSH_SH_H_ID); | |
38 | 38 | |
39 | 39 | #ifndef MKSHRC_PATH |
40 | 40 | #define MKSHRC_PATH "~/.mkshrc" |
44 | 44 | #define MKSH_DEFAULT_TMPDIR MKSH_UNIXROOT "/tmp" |
45 | 45 | #endif |
46 | 46 | |
47 | #if !HAVE_SETLOCALE_CTYPE | |
47 | #if !HAVE_POSIX_UTF8_LOCALE | |
48 | 48 | /* this is the “implementation-defined default locale” */ |
49 | 49 | #ifdef MKSH_DEFAULT_UTFLOC |
50 | 50 | #define MKSH_DEFAULT_LOCALE "UTF-8" |
53 | 53 | #endif |
54 | 54 | #endif |
55 | 55 | |
56 | static kby isuc(const char *); | |
57 | 56 | static int main_init(int, const char *[], Source **, struct block **); |
58 | 57 | void chvt_reinit(void); |
59 | 58 | static void reclaim(void); |
103 | 102 | |
104 | 103 | extern const char Tpipest[]; |
105 | 104 | |
106 | static bool initio_done; | |
107 | ||
108 | 105 | /* top-level parsing and execution environment */ |
109 | 106 | static struct env env; |
110 | 107 | struct env *e = &env; |
111 | 108 | |
112 | /* compile-time assertions */ | |
113 | ||
114 | /* this one should be defined by the standard */ | |
115 | cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) && | |
116 | (sizeof(unsigned char) == 1)); | |
117 | cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) && | |
118 | ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF)); | |
109 | /* many compile-time assertions */ | |
110 | mbiCTAS(main_c) { | |
111 | ||
112 | /* require char to be 8 bit long */ | |
113 | mbiCTA(char_8bit, (CHAR_BIT) == 8 && | |
114 | (((unsigned int)(unsigned char)255U) == 255U) && | |
115 | (((unsigned int)(unsigned char)256U) == 0U) && | |
116 | mbiTYPE_UBITS(unsigned char) == 8U && | |
117 | mbiMASK_BITS(SCHAR_MAX) == 7U); | |
118 | ||
119 | /* POSIX guarantees a 32-bit int */ | |
120 | mbiCTA(int_32bit, mbiTYPE_UBITS(unsigned int) >= 32U && | |
121 | mbiMASK_BITS(INT_MAX) >= 31U); | |
122 | /* which implies unsigned long has at least 32 bit width, too */ | |
123 | ||
119 | 124 | /* the next assertion is probably not really needed */ |
120 | cta(short_is_2_char, sizeof(short) == 2); | |
121 | cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short)); | |
125 | mbiCTA(short_is_2_char, sizeof(short) == 2); | |
122 | 126 | /* the next assertion is probably not really needed */ |
123 | cta(int_is_4_char, sizeof(int) == 4); | |
124 | cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int)); | |
125 | ||
126 | cta(long_ge_int, sizeof(long) >= sizeof(int)); | |
127 | cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long)); | |
127 | mbiCTA(int_is_4_char, sizeof(int) == 4); | |
128 | 128 | |
129 | 129 | #ifndef MKSH_LEGACY_MODE |
130 | mbiCTA(basic_int32_ari, | |
131 | mbiTYPE_UMAX(mksh_uari_t) == (UINT32_MAX) && | |
132 | sizeof(mksh_ari_t) <= (279 / CHAR_BIT) && | |
133 | sizeof(mksh_uari_t) <= (279 / CHAR_BIT) && | |
134 | mbiMASK_CHK(INT32_MAX) && mbiMASK_CHK(UINT32_MAX) && | |
135 | /* require two’s complement */ | |
136 | ((INT32_MIN) == -(INT32_MAX)-1)); | |
130 | 137 | /* the next assertion is probably not really needed */ |
131 | cta(ari_is_4_char, sizeof(mksh_ari_t) == 4); | |
138 | mbiCTA(ari_is_4_char, sizeof(mksh_ari_t) == 4); | |
132 | 139 | /* but this is */ |
133 | cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1)); | |
140 | mbiCTA(ari_has_31_bit, mbiMASK_BITS(INT32_MAX) == 31); | |
134 | 141 | /* the next assertion is probably not really needed */ |
135 | cta(uari_is_4_char, sizeof(mksh_uari_t) == 4); | |
136 | /* but the next three are; we REQUIRE unsigned integer wraparound */ | |
137 | cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1)); | |
138 | cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3)); | |
139 | cta(uari_wrap_32_bit, | |
140 | (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) > | |
141 | (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4)); | |
142 | mbiCTA(uari_is_4_char, sizeof(mksh_uari_t) == 4); | |
143 | mbiCTA(uari_is_32_bit, mbiTYPE_UBITS(mksh_uari_t) == 32); | |
144 | #else | |
145 | mbiCTA(long_complement, (LONG_MIN) == -(LONG_MAX)-1); | |
142 | 146 | #endif |
143 | 147 | /* these are always required */ |
144 | cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0); | |
145 | cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0); | |
148 | mbiCTA(ari_is_signed, !mbiTYPE_ISU(mksh_ari_t)); | |
149 | mbiCTA(uari_is_unsigned, mbiTYPE_ISU(mksh_uari_t)); | |
146 | 150 | /* we require these to have the precisely same size and assume 2s complement */ |
147 | cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t)); | |
148 | ||
149 | cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t)); | |
150 | cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *)); | |
151 | cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void))); | |
151 | mbiCTA(ari_size_no_matter_of_signedness, | |
152 | sizeof(mksh_ari_t) == sizeof(mksh_uari_t)); | |
153 | ||
152 | 154 | /* our formatting routines assume this */ |
153 | cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long)); | |
154 | cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long)); | |
155 | mbiCTA(ptr_fits_in_long, sizeof(size_t) <= sizeof(long)); | |
156 | mbiCTA(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long)); | |
157 | ||
158 | }; | |
159 | /* end of compile-time asserts */ | |
155 | 160 | |
156 | 161 | static mksh_uari_t |
157 | 162 | rndsetup(void) |
158 | 163 | { |
159 | register uint32_t h; | |
164 | register k32 h; | |
160 | 165 | struct { |
161 | 166 | ALLOC_ITEM alloc_INT; |
162 | void *dataptr, *stkptr, *mallocptr; | |
167 | void *bssptr, *dataptr, *stkptr, *mallocptr; | |
163 | 168 | #if defined(__GLIBC__) && (__GLIBC__ >= 2) |
164 | 169 | sigjmp_buf jbuf; |
165 | 170 | #endif |
173 | 178 | /* undo what alloc() did to the malloc result address */ |
174 | 179 | bufptr = (void *)(cp - sizeof(ALLOC_ITEM)); |
175 | 180 | /* PIE or something similar provides us with deltas here */ |
176 | bufptr->dataptr = &rndsetupstate; | |
181 | bufptr->bssptr = &rndsetupstate; | |
182 | bufptr->dataptr = &e; | |
177 | 183 | /* ASLR in at least Windows, Linux, some BSDs */ |
178 | 184 | bufptr->stkptr = &bufptr; |
179 | 185 | /* randomised malloc in BSD (and possibly others) */ |
182 | 188 | /* glibc pointer guard */ |
183 | 189 | sigsetjmp(bufptr->jbuf, 1); |
184 | 190 | #endif |
185 | /* introduce variation (and yes, second arg MBZ for portability) */ | |
191 | /* introduce variation (cannot use gettimeofday *tzp portably) */ | |
186 | 192 | mksh_TIME(bufptr->tv); |
187 | 193 | |
188 | 194 | #ifdef MKSH_ALLOC_CATCH_UNDERRUNS |
194 | 200 | return ((mksh_uari_t)h); |
195 | 201 | } |
196 | 202 | |
203 | /* pre-initio() */ | |
197 | 204 | void |
198 | 205 | chvt_reinit(void) |
199 | 206 | { |
207 | 214 | Tmksh, NULL |
208 | 215 | }; |
209 | 216 | |
217 | #ifndef MKSH_EARLY_LOCALE_TRACKING | |
210 | 218 | static kby |
211 | 219 | isuc(const char *cx) { |
212 | char *cp, *x; | |
213 | kby rv = 0; | |
220 | const char *cp; | |
214 | 221 | |
215 | 222 | if (!cx || !*cx) |
216 | 223 | return (0); |
217 | 224 | |
218 | /* uppercase a string duplicate */ | |
219 | strdupx(x, cx, ATEMP); | |
220 | cp = x; | |
221 | while ((*cp = ksh_toupper(*cp))) | |
225 | if ((cp = cstrchr(cx, '.'))) | |
222 | 226 | ++cp; |
223 | ||
224 | /* check for UTF-8 */ | |
225 | if (vstrstr(x, "UTF-8") || vstrstr(x, "UTF8")) | |
226 | rv = 1; | |
227 | ||
228 | /* free copy and out */ | |
229 | afree(x, ATEMP); | |
227 | else | |
228 | cp = cx; | |
229 | if (!isCh(cp[0], 'U', 'u') || | |
230 | !isCh(cp[1], 'T', 't') || | |
231 | !isCh(cp[2], 'F', 'f')) | |
232 | return (0); | |
233 | cp += isch(cp[3], '-') ? 4 : 3; | |
234 | return (isch(*cp, '8') && (isch(cp[1], '@') || !cp[1])); | |
235 | } | |
236 | #endif | |
237 | ||
238 | kby | |
239 | kshname_islogin(const char **kshbasenamep) | |
240 | { | |
241 | const char *cp; | |
242 | size_t o; | |
243 | kby rv; | |
244 | ||
245 | /* determine the basename (without '-' or path) of the executable */ | |
246 | cp = kshname; | |
247 | o = 0; | |
248 | while ((rv = cp[o++])) { | |
249 | if (mksh_cdirsep(rv)) { | |
250 | cp += o; | |
251 | o = 0; | |
252 | } | |
253 | } | |
254 | rv = isch(*cp, '-') || isch(*kshname, '-'); | |
255 | if (isch(*cp, '-')) | |
256 | ++cp; | |
257 | if (!*cp) | |
258 | cp = empty_argv[0]; | |
259 | *kshbasenamep = cp; | |
230 | 260 | return (rv); |
231 | 261 | } |
232 | 262 | |
263 | /* pre-initio() */ | |
233 | 264 | static int |
234 | 265 | main_init(int argc, const char *argv[], Source **sp, struct block **lp) |
235 | 266 | { |
236 | int argi, i; | |
267 | int argi = 0, i; | |
237 | 268 | Source *s = NULL; |
238 | 269 | struct block *l; |
239 | 270 | unsigned char restricted_shell = 0, errexit, utf_flag; |
271 | 302 | /* initialise permanent Area */ |
272 | 303 | ainit(&aperm); |
273 | 304 | /* max. name length: -2147483648 = 11 (+ NUL) */ |
274 | vtemp = alloc(offsetof(struct tbl, name[0]) + 12, APERM); | |
305 | vtemp = alloc(offsetof(struct tbl, name[0]) + 12U, APERM); | |
275 | 306 | |
276 | 307 | /* set up base environment */ |
277 | 308 | env.type = E_NONE; |
279 | 310 | /* set up global l->vars and l->funs */ |
280 | 311 | newblock(); |
281 | 312 | |
282 | /* Do this first so output routines (eg, errorf, shellf) can work */ | |
313 | /* Do this first so output routines (eg. kwarnf, shellf) can work */ | |
283 | 314 | initio(); |
284 | 315 | |
285 | /* determine the basename (without '-' or path) of the executable */ | |
286 | ccp = kshname; | |
287 | goto begin_parsing_kshname; | |
288 | while ((i = ccp[argi++])) { | |
289 | if (mksh_cdirsep(i)) { | |
290 | ccp += argi; | |
291 | begin_parsing_kshname: | |
292 | argi = 0; | |
293 | } | |
294 | } | |
295 | Flag(FLOGIN) = (ord(*ccp) == ORD('-')) || (ord(*kshname) == ORD('-')); | |
296 | if (ord(*ccp) == ORD('-')) | |
297 | ++ccp; | |
298 | if (!*ccp) | |
299 | ccp = empty_argv[0]; | |
316 | /* check kshname: leading dash, determine basename */ | |
317 | Flag(FLOGIN) = kshname_islogin(&ccp); | |
300 | 318 | |
301 | 319 | /* |
302 | 320 | * Turn on nohup by default. (AT&T ksh does not have a nohup |
337 | 355 | if (argi < 0) |
338 | 356 | return (1); |
339 | 357 | /* called as rsh, rmksh, -rsh, RKSH.EXE, etc.? */ |
340 | if (ksh_eq(*ccp, 'R', 'r')) { | |
358 | if (isCh(*ccp, 'R', 'r')) { | |
341 | 359 | ++ccp; |
342 | 360 | ++restricted_shell; |
343 | 361 | } |
344 | 362 | #if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED) |
345 | 363 | /* are we called as -rsh or /bin/sh or SH.EXE or so? */ |
346 | if (ksh_eq(ccp[0], 'S', 's') && | |
347 | ksh_eq(ccp[1], 'H', 'h')) { | |
364 | if (isCh(ccp[0], 'S', 's') && | |
365 | isCh(ccp[1], 'H', 'h')) { | |
348 | 366 | /* either also turns off braceexpand */ |
349 | 367 | #ifdef MKSH_BINSHPOSIX |
350 | 368 | /* enable better POSIX conformance */ |
417 | 435 | * by the environment or the user. Also, we want tab completion |
418 | 436 | * on in vi by default. |
419 | 437 | */ |
420 | change_flag(FEMACS, OF_SPECIAL, true); | |
438 | change_flag(FEMACS, OF_INTERNAL, true); | |
421 | 439 | #if !MKSH_S_NOVI |
422 | 440 | Flag(FVITABCOMPLETE) = 1; |
423 | 441 | #endif |
511 | 529 | } else if (Flag(FCOMMAND)) { |
512 | 530 | s = pushs(SSTRINGCMDLINE, ATEMP); |
513 | 531 | if (!(s->start = s->str = argv[argi++])) |
514 | errorf(Tf_optdcs, 'c', Treq_arg); | |
532 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
533 | KWF_TWOMSG | KWF_NOERRNO, Tdc, Treq_arg); | |
515 | 534 | while (*s->str) { |
516 | 535 | if (ctype(*s->str, C_QUOTE)) |
517 | 536 | break; |
548 | 567 | SHF_MAPHI | SHF_CLEXEC); |
549 | 568 | if (s->u.shf == NULL) { |
550 | 569 | shl_stdout_ok = false; |
551 | warningf(true, Tf_sD_s, s->file, cstrerror(errno)); | |
570 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, s->file); | |
552 | 571 | /* mandated by SUSv4 */ |
553 | 572 | exstat = 127; |
554 | 573 | unwind(LERROR); |
571 | 590 | |
572 | 591 | /* this bizarreness is mandated by POSIX */ |
573 | 592 | if (Flag(FTALKING) && fstat(0, &s_stdin) >= 0 && |
574 | S_ISCHR(s_stdin.st_mode)) | |
593 | (S_ISCHR(s_stdin.st_mode) || S_ISFIFO(s_stdin.st_mode))) | |
575 | 594 | reset_nonblock(0); |
576 | 595 | |
577 | 596 | /* initialise job control */ |
634 | 653 | /* auto-detect from locale or environment */ |
635 | 654 | case 4: |
636 | 655 | #ifndef MKSH_EARLY_LOCALE_TRACKING |
637 | #if HAVE_SETLOCALE_CTYPE | |
656 | #if HAVE_POSIX_UTF8_LOCALE | |
638 | 657 | ccp = setlocale(LC_CTYPE, ""); |
639 | #if HAVE_LANGINFO_CODESET | |
640 | 658 | if (!isuc(ccp)) |
641 | 659 | ccp = nl_langinfo(CODESET); |
642 | #endif | |
643 | 660 | if (!isuc(ccp)) |
644 | 661 | ccp = null; |
645 | 662 | #endif |
704 | 721 | * user will know why things broke. |
705 | 722 | */ |
706 | 723 | if (!current_wd[0] && Flag(FTALKING)) |
707 | warningf(false, "can't determine current directory"); | |
724 | kwarnf(KWF_PREFIX | KWF_ONEMSG | KWF_NOERRNO, | |
725 | "can't determine current directory"); | |
708 | 726 | |
709 | 727 | if (Flag(FLOGIN)) |
710 | 728 | include(MKSH_SYSTEM_PROFILE, 0, NULL, true); |
824 | 842 | unwind(i); |
825 | 843 | /* NOTREACHED */ |
826 | 844 | default: |
827 | internal_errorf(Tunexpected_type, Tunwind, Tsource, i); | |
845 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
846 | Tunexpected_type, Tunwind, Tsource, i); | |
828 | 847 | /* NOTREACHED */ |
829 | 848 | } |
830 | 849 | } |
891 | 910 | unwind(i); |
892 | 911 | /* NOTREACHED */ |
893 | 912 | } |
894 | internal_errorf(Tf_cant_s, Tshell, | |
895 | i == LBREAK ? Tbreak : Tcontinue); | |
913 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
914 | Tf_cant_s, Tshell, i == LBREAK ? Tbreak : Tcontinue); | |
896 | 915 | /* NOTREACHED */ |
897 | 916 | case LINTR: |
898 | 917 | /* we get here if SIGINT not caught or ignored */ |
936 | 955 | default: |
937 | 956 | source = old_source; |
938 | 957 | quitenv(NULL); |
939 | internal_errorf(Tunexpected_type, Tunwind, Tshell, i); | |
958 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
959 | Tunexpected_type, Tunwind, Tshell, i); | |
940 | 960 | /* NOTREACHED */ |
941 | 961 | } |
942 | 962 | while (/* CONSTCOND */ 1) { |
1250 | 1270 | goto got_fd; |
1251 | 1271 | } |
1252 | 1272 | #endif |
1253 | if ((fd = open(T_devtty, O_RDWR, 0)) >= 0) { | |
1273 | if ((fd = open("/dev/tty", O_RDWR, 0)) >= 0) { | |
1254 | 1274 | do_close = true; |
1255 | 1275 | goto got_fd; |
1256 | 1276 | } |
1292 | 1312 | return (rv); |
1293 | 1313 | } |
1294 | 1314 | |
1295 | /* A shell error occurred (eg, syntax error, etc.) */ | |
1296 | ||
1297 | #define VWARNINGF_ERRORPREFIX 1 | |
1298 | #define VWARNINGF_FILELINE 2 | |
1299 | #define VWARNINGF_BUILTIN 4 | |
1300 | #define VWARNINGF_INTERNAL 8 | |
1301 | ||
1302 | static void vwarningf(unsigned int, const char *, va_list) | |
1303 | MKSH_A_FORMAT(__printf__, 2, 0); | |
1304 | ||
1305 | static void | |
1306 | vwarningf(unsigned int flags, const char *fmt, va_list ap) | |
1307 | { | |
1308 | if (fmt) { | |
1309 | if (flags & VWARNINGF_INTERNAL) | |
1310 | shf_fprintf(shl_out, Tf_sD_, "internal error"); | |
1311 | if (flags & VWARNINGF_ERRORPREFIX) | |
1312 | error_prefix(tobool(flags & VWARNINGF_FILELINE)); | |
1313 | if ((flags & VWARNINGF_BUILTIN) && | |
1314 | /* not set when main() calls parse_args() */ | |
1315 | builtin_argv0 && builtin_argv0 != kshname) | |
1316 | shf_fprintf(shl_out, Tf_sD_, builtin_argv0); | |
1317 | shf_vfprintf(shl_out, fmt, ap); | |
1318 | shf_putc('\n', shl_out); | |
1319 | } | |
1320 | shf_flush(shl_out); | |
1321 | } | |
1322 | ||
1323 | void | |
1324 | errorfx(int rc, const char *fmt, ...) | |
1325 | { | |
1326 | va_list va; | |
1327 | ||
1328 | exstat = rc; | |
1329 | ||
1330 | /* debugging: note that stdout not valid */ | |
1331 | shl_stdout_ok = false; | |
1332 | ||
1333 | va_start(va, fmt); | |
1334 | vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va); | |
1335 | va_end(va); | |
1336 | unwind(LERROR); | |
1337 | } | |
1338 | ||
1339 | void | |
1340 | errorf(const char *fmt, ...) | |
1341 | { | |
1342 | va_list va; | |
1343 | ||
1344 | exstat = 1; | |
1345 | ||
1346 | /* debugging: note that stdout not valid */ | |
1347 | shl_stdout_ok = false; | |
1348 | ||
1349 | va_start(va, fmt); | |
1350 | vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va); | |
1351 | va_end(va); | |
1352 | unwind(LERROR); | |
1353 | } | |
1354 | ||
1355 | /* like errorf(), but no unwind is done */ | |
1356 | void | |
1357 | warningf(bool fileline, const char *fmt, ...) | |
1358 | { | |
1359 | va_list va; | |
1360 | ||
1361 | va_start(va, fmt); | |
1362 | vwarningf(VWARNINGF_ERRORPREFIX | (fileline ? VWARNINGF_FILELINE : 0), | |
1363 | fmt, va); | |
1364 | va_end(va); | |
1365 | } | |
1366 | ||
1367 | /* | |
1368 | * Used by built-in utilities to prefix shell and utility name to message | |
1369 | * (also unwinds environments for special builtins). | |
1370 | */ | |
1371 | void | |
1372 | bi_errorf(const char *fmt, ...) | |
1373 | { | |
1374 | va_list va; | |
1375 | ||
1376 | /* debugging: note that stdout not valid */ | |
1377 | shl_stdout_ok = false; | |
1378 | ||
1379 | exstat = 1; | |
1380 | ||
1381 | va_start(va, fmt); | |
1382 | vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE | | |
1383 | VWARNINGF_BUILTIN, fmt, va); | |
1384 | va_end(va); | |
1385 | ||
1386 | /* POSIX special builtins cause non-interactive shells to exit */ | |
1387 | if (builtin_spec) { | |
1388 | builtin_argv0 = NULL; | |
1389 | /* may not want to use LERROR here */ | |
1390 | unwind(LERROR); | |
1391 | } | |
1392 | } | |
1393 | ||
1394 | /* | |
1395 | * Used by functions called by builtins and not: | |
1396 | * identical to errorfx if first argument is nil, | |
1397 | * like bi_errorf storing the errorlevel into it otherwise | |
1398 | */ | |
1399 | void | |
1400 | maybe_errorf(int *ep, int rc, const char *fmt, ...) | |
1401 | { | |
1402 | va_list va; | |
1403 | ||
1404 | /* debugging: note that stdout not valid */ | |
1405 | shl_stdout_ok = false; | |
1406 | ||
1407 | exstat = rc; | |
1408 | ||
1409 | va_start(va, fmt); | |
1410 | vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE | | |
1411 | (ep ? VWARNINGF_BUILTIN : 0), fmt, va); | |
1412 | va_end(va); | |
1413 | ||
1414 | if (!ep) | |
1415 | goto and_out; | |
1416 | *ep = rc; | |
1417 | ||
1418 | /* POSIX special builtins cause non-interactive shells to exit */ | |
1419 | if (builtin_spec) { | |
1420 | builtin_argv0 = NULL; | |
1421 | /* may not want to use LERROR here */ | |
1422 | and_out: | |
1423 | unwind(LERROR); | |
1424 | } | |
1425 | } | |
1426 | ||
1427 | /* Called when something that shouldn't happen does */ | |
1428 | void | |
1429 | internal_errorf(const char *fmt, ...) | |
1430 | { | |
1431 | va_list va; | |
1432 | ||
1433 | exstat = 0xFF; | |
1434 | if (trap_exstat != -1) | |
1435 | trap_exstat = exstat; | |
1436 | ||
1437 | va_start(va, fmt); | |
1438 | vwarningf(VWARNINGF_INTERNAL, fmt, va); | |
1439 | va_end(va); | |
1440 | unwind(LERROR); | |
1441 | } | |
1442 | ||
1443 | void | |
1444 | internal_warningf(const char *fmt, ...) | |
1445 | { | |
1446 | va_list va; | |
1447 | ||
1448 | va_start(va, fmt); | |
1449 | vwarningf(VWARNINGF_INTERNAL, fmt, va); | |
1450 | va_end(va); | |
1451 | } | |
1452 | ||
1453 | /* used by error reporting functions to print "ksh: .kshrc[25]: " */ | |
1454 | void | |
1455 | error_prefix(bool fileline) | |
1456 | { | |
1457 | /* Avoid foo: foo[2]: ... */ | |
1458 | if (!fileline || !source || !source->file || | |
1459 | strcmp(source->file, kshname) != 0) | |
1460 | shf_fprintf(shl_out, Tf_sD_, kshname + | |
1461 | (*kshname == '-' ? 1 : 0)); | |
1462 | if (fileline && source && source->file != NULL) { | |
1463 | shf_fprintf(shl_out, "%s[%lu]: ", source->file, | |
1464 | (unsigned long)(source->errline ? | |
1465 | source->errline : source->line)); | |
1466 | source->errline = 0; | |
1467 | } | |
1468 | } | |
1469 | ||
1470 | 1315 | /* printf to shl_out (stderr) with flush */ |
1471 | 1316 | void |
1472 | 1317 | shellf(const char *fmt, ...) |
1473 | 1318 | { |
1474 | 1319 | va_list va; |
1475 | 1320 | |
1476 | if (!initio_done) | |
1477 | /* shl_out may not be set up yet... */ | |
1478 | return; | |
1479 | 1321 | va_start(va, fmt); |
1480 | 1322 | shf_vfprintf(shl_out, fmt, va); |
1481 | 1323 | va_end(va); |
1489 | 1331 | va_list va; |
1490 | 1332 | |
1491 | 1333 | if (!shl_stdout_ok) |
1492 | internal_errorf("shl_stdout not valid"); | |
1334 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
1335 | "shl_stdout not valid"); | |
1493 | 1336 | va_start(va, fmt); |
1494 | 1337 | shf_vfprintf(shl_stdout, fmt, va); |
1495 | 1338 | va_end(va); |
1513 | 1356 | #endif |
1514 | 1357 | struct shf shf_iob[NSHF_IOB]; |
1515 | 1358 | |
1359 | /* pre-initio() */ | |
1516 | 1360 | void |
1517 | 1361 | initio(void) |
1518 | 1362 | { |
1524 | 1368 | shf_fdopen(1, SHF_WR, shl_stdout); |
1525 | 1369 | shf_fdopen(2, SHF_WR, shl_out); |
1526 | 1370 | shf_fdopen(2, SHF_WR, shl_xtrace); |
1371 | initio_done = true; | |
1527 | 1372 | #ifdef DF |
1528 | 1373 | if ((lfp = getenv("SDMKSH_PATH")) == NULL) { |
1529 | 1374 | if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp)) |
1530 | errorf("can't get home directory"); | |
1375 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | | |
1376 | KWF_NOERRNO, "can't get home directory"); | |
1531 | 1377 | strpathx(lfp, lfp, "mksh-dbg.txt", 1); |
1532 | 1378 | } |
1533 | 1379 | |
1534 | 1380 | if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0) |
1535 | errorf("can't open debug output file %s", lfp); | |
1381 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG, | |
1382 | lfp, "can't open debug output file"); | |
1536 | 1383 | if (shl_dbg_fd < FDBASE) { |
1537 | 1384 | int nfd; |
1538 | 1385 | |
1539 | nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE); | |
1386 | if ((nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE)) == -1) | |
1387 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG, | |
1388 | "can't dup debug output file"); | |
1540 | 1389 | close(shl_dbg_fd); |
1541 | if ((shl_dbg_fd = nfd) == -1) | |
1542 | errorf("can't dup debug output file"); | |
1390 | shl_dbg_fd = nfd; | |
1543 | 1391 | } |
1544 | 1392 | fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC); |
1545 | 1393 | shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg); |
1546 | 1394 | DF("=== open ==="); |
1547 | #endif | |
1548 | initio_done = true; | |
1395 | initio_done = 2; | |
1396 | #endif | |
1549 | 1397 | } |
1550 | 1398 | |
1551 | 1399 | /* A dup2() with error checking */ |
1555 | 1403 | int rv; |
1556 | 1404 | |
1557 | 1405 | if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF)) |
1558 | errorf(Ttoo_many_files, ofd, nfd, cstrerror(errno)); | |
1406 | kerrf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE, | |
1407 | Ttoo_many_files, ofd, nfd); | |
1559 | 1408 | |
1560 | 1409 | #ifdef __ultrix |
1561 | 1410 | /*XXX imake style */ |
1580 | 1429 | (errno == EBADF || errno == EPERM)) |
1581 | 1430 | return (-1); |
1582 | 1431 | if (nfd < FDBASE || nfd > (int)(kui)FDMAXNUM) |
1583 | errorf(Ttoo_many_files, fd, nfd, cstrerror(errno)); | |
1432 | kerrf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE, | |
1433 | Ttoo_many_files, fd, nfd); | |
1584 | 1434 | if (fcntl(nfd, F_SETFD, FD_CLOEXEC) == -1) |
1585 | internal_warningf(Tcloexec_failed, "set", nfd, | |
1586 | cstrerror(errno)); | |
1435 | kwarnf0(KWF_INTERNAL | KWF_WARNING, Tcloexec_failed, | |
1436 | "set", nfd); | |
1587 | 1437 | return (nfd); |
1588 | 1438 | } |
1589 | 1439 | |
1608 | 1458 | int lpv[2]; |
1609 | 1459 | |
1610 | 1460 | if (pipe(lpv) < 0) |
1611 | errorf("can't create pipe - try again"); | |
1461 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, | |
1462 | "pipe"); | |
1612 | 1463 | pv[0] = savefd(lpv[0]); |
1613 | 1464 | if (pv[0] != lpv[0]) |
1614 | 1465 | close(lpv[0]); |
1645 | 1496 | illegal_fd_name: |
1646 | 1497 | if (emsgp) |
1647 | 1498 | *emsgp = "illegal file descriptor name"; |
1499 | errno = EINVAL; | |
1648 | 1500 | return (-1); |
1649 | 1501 | } |
1650 | 1502 | |
1666 | 1518 | *emsgp = (fl == O_WRONLY) ? |
1667 | 1519 | "fd not open for reading" : |
1668 | 1520 | "fd not open for writing"; |
1521 | #ifdef ENXIO | |
1522 | errno = ENXIO; | |
1523 | #else | |
1524 | errno = EBADF; | |
1525 | #endif | |
1669 | 1526 | return (-1); |
1670 | 1527 | } |
1671 | 1528 | return (fd); |
1730 | 1587 | return (fd); |
1731 | 1588 | if (emsgp) |
1732 | 1589 | *emsgp = "no coprocess"; |
1590 | errno = EBADF; | |
1733 | 1591 | return (-1); |
1734 | 1592 | } |
1735 | 1593 | |
1770 | 1628 | dir = tmpdir ? tmpdir : MKSH_DEFAULT_TMPDIR; |
1771 | 1629 | /* add "/shXXXXXX.tmp" plus NUL */ |
1772 | 1630 | len = strlen(dir); |
1773 | checkoktoadd(len, offsetof(struct temp, tffn[0]) + 14); | |
1774 | tp = alloc(offsetof(struct temp, tffn[0]) + 14 + len, ap); | |
1775 | ||
1631 | checkoktoadd(len, offsetof(struct temp, tffn[0]) + 14U); | |
1632 | cp = alloc(offsetof(struct temp, tffn[0]) + 14U + len, ap); | |
1633 | ||
1634 | tp = (void *)cp; | |
1776 | 1635 | tp->shf = NULL; |
1777 | 1636 | tp->pid = procpid; |
1778 | 1637 | tp->type = type; |
1779 | 1638 | |
1780 | if (stat(dir, &sb) || !S_ISDIR(sb.st_mode)) { | |
1781 | tp->tffn[0] = '\0'; | |
1782 | goto maketemp_out; | |
1783 | } | |
1784 | ||
1785 | cp = (void *)tp; | |
1786 | 1639 | cp += offsetof(struct temp, tffn[0]); |
1787 | 1640 | memcpy(cp, dir, len); |
1788 | 1641 | cp += len; |
1789 | 1642 | memstr(cp, "/shXXXXXX.tmp"); |
1643 | ||
1644 | if (stat(dir, &sb) || !S_ISDIR(sb.st_mode)) | |
1645 | goto maketemp_out; | |
1646 | ||
1790 | 1647 | /* point to the first of six Xes */ |
1791 | 1648 | cp += 3; |
1792 | 1649 | |
1836 | 1693 | static void tgrow(struct table *); |
1837 | 1694 | static int tnamecmp(const void *, const void *); |
1838 | 1695 | |
1696 | /* pre-initio() tp->tbls=NULL tp->tshift=INIT_TBLSHIFT-1 */ | |
1839 | 1697 | static void |
1840 | 1698 | tgrow(struct table *tp) |
1841 | 1699 | { |
1844 | 1702 | struct tbl **ntblp, **otblp = tp->tbls; |
1845 | 1703 | |
1846 | 1704 | if (tp->tshift > 29) |
1847 | internal_errorf("hash table size limit reached"); | |
1705 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
1706 | "hash table size limit reached"); | |
1848 | 1707 | |
1849 | 1708 | /* calculate old size, new shift and new size */ |
1850 | 1709 | osize = (size_t)1 << (tp->tshift++); |
1886 | 1745 | afree(otblp, tp->areap); |
1887 | 1746 | } |
1888 | 1747 | |
1748 | /* pre-initio() initshift=0 */ | |
1889 | 1749 | void |
1890 | 1750 | ktinit(Area *ap, struct table *tp, kby initshift) |
1891 | 1751 | { |
1898 | 1758 | |
1899 | 1759 | /* table, name (key) to search for, hash(name), rv pointer to tbl ptr */ |
1900 | 1760 | struct tbl * |
1901 | ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp) | |
1761 | ktscan(struct table *tp, const char *name, k32 h, struct tbl ***ppp) | |
1902 | 1762 | { |
1903 | 1763 | size_t j, perturb, mask; |
1904 | 1764 | struct tbl **pp, *p; |
1923 | 1783 | |
1924 | 1784 | /* table, name (key) to enter, hash(n) */ |
1925 | 1785 | struct tbl * |
1926 | ktenter(struct table *tp, const char *n, uint32_t h) | |
1786 | ktenter(struct table *tp, const char *n, k32 h) | |
1927 | 1787 | { |
1928 | 1788 | struct tbl **pp, *p; |
1929 | 1789 | size_t len; |
1940 | 1800 | |
1941 | 1801 | /* create new tbl entry */ |
1942 | 1802 | len = strlen(n); |
1943 | checkoktoadd(len, offsetof(struct tbl, name[0]) + 1); | |
1803 | checkoktoadd(len, offsetof(struct tbl, name[0]) + 1U); | |
1944 | 1804 | p = alloc(offsetof(struct tbl, name[0]) + ++len, tp->areap); |
1945 | 1805 | p->flag = 0; |
1946 | 1806 | p->type = 0; |
2075 | 1935 | } |
2076 | 1936 | |
2077 | 1937 | #ifdef MKSH_ENVDIR |
2078 | #if HAVE_SETLOCALE_CTYPE | |
1938 | #if HAVE_POSIX_UTF8_LOCALE | |
2079 | 1939 | # error MKSH_ENVDIR has not been adapted to work with POSIX locale! |
2080 | 1940 | #else |
2081 | 1941 | static void |
2089 | 1949 | struct dirent *dent; |
2090 | 1950 | |
2091 | 1951 | if ((dirp = opendir(MKSH_ENVDIR)) == NULL) { |
2092 | warningf(false, "cannot read environment from %s: %s", | |
2093 | MKSH_ENVDIR, cstrerror(errno)); | |
1952 | kwarnf(KWF_PREFIX | KWF_TWOMSG, MKSH_ENVDIR, | |
1953 | "can't read environment"); | |
2094 | 1954 | return; |
2095 | 1955 | } |
2096 | 1956 | XinitN(xs, 256, ATEMP); |
2100 | 1960 | if (skip_varname(dent->d_name, true)[0] == '\0') { |
2101 | 1961 | strpathx(xp, MKSH_ENVDIR, dent->d_name, 1); |
2102 | 1962 | if (!(shf = shf_open(xp, O_RDONLY, 0, 0))) { |
2103 | warningf(false, | |
2104 | "cannot read environment %s from %s: %s", | |
2105 | dent->d_name, MKSH_ENVDIR, | |
2106 | cstrerror(errno)); | |
1963 | kwarnf(KWF_PREFIX | KWF_THREEMSG, MKSH_ENVDIR, | |
1964 | dent->d_name, "can't read environment"); | |
2107 | 1965 | goto read_envfile; |
2108 | 1966 | } |
2109 | 1967 | afree(xp, ATEMP); |
2119 | 1977 | XcheckN(xs, xp, 128); |
2120 | 1978 | } |
2121 | 1979 | if (n < 0) { |
2122 | warningf(false, | |
2123 | "cannot read environment %s from %s: %s", | |
2124 | dent->d_name, MKSH_ENVDIR, | |
2125 | cstrerror(shf_errno(shf))); | |
1980 | kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_THREEMSG, | |
1981 | shf_errno(shf), MKSH_ENVDIR, | |
1982 | dent->d_name, "can't read environment"); | |
2126 | 1983 | } else { |
2127 | 1984 | *xp = '\0'; |
1985 | rndpush(Xstring(xs, xp), Xlength(xs, xp)); | |
2128 | 1986 | xp = Xstring(xs, xp); |
2129 | rndpush(xp); | |
2130 | 1987 | typeset(xp, IMPORT | EXPORT, 0, 0, 0); |
2131 | 1988 | } |
2132 | 1989 | shf_close(shf); |
2133 | 1990 | } |
2134 | 1991 | goto read_envfile; |
2135 | 1992 | } else if (errno) |
2136 | warningf(false, "cannot read environment from %s: %s", | |
2137 | MKSH_ENVDIR, cstrerror(errno)); | |
1993 | kwarnf(KWF_PREFIX | KWF_TWOMSG, MKSH_ENVDIR, | |
1994 | "can't read environment"); | |
2138 | 1995 | closedir(dirp); |
2139 | 1996 | Xfree(xs, xp); |
2140 | 1997 | } |
2152 | 2009 | |
2153 | 2010 | wp = (const char **)environ; |
2154 | 2011 | while (*wp != NULL) { |
2155 | rndpush(*wp); | |
2012 | rndpush(*wp, strlen(*wp)); | |
2156 | 2013 | typeset(*wp, IMPORT | EXPORT, 0, 0, 0); |
2157 | 2014 | #ifdef MKSH_EARLY_LOCALE_TRACKING |
2158 | if (ord((*wp)[0]) == ORD('L') && ( | |
2159 | (ord((*wp)[1]) == ORD('C') && ord((*wp)[2]) == ORD('_')) || | |
2015 | if (isch((*wp)[0], 'L') && ( | |
2016 | (isch((*wp)[1], 'C') && isch((*wp)[2], '_')) || | |
2160 | 2017 | !strcmp(*wp, "LANG"))) { |
2161 | 2018 | const char **P; |
2162 | 2019 | |
2180 | 2037 | recheck_ctype(void) |
2181 | 2038 | { |
2182 | 2039 | const char *ccp; |
2183 | ||
2184 | /*XXX OSX has LC_CTYPE=UTF-8 */ | |
2040 | #if !HAVE_POSIX_UTF8_LOCALE | |
2041 | const char *cdp; | |
2042 | #endif | |
2043 | ||
2044 | /* determine active LC_CTYPE value */ | |
2185 | 2045 | ccp = str_val(global("LC_ALL")); |
2186 | if (ccp == null) | |
2046 | if (!*ccp) | |
2187 | 2047 | ccp = str_val(global("LC_CTYPE")); |
2188 | if (ccp == null) | |
2048 | if (!*ccp) | |
2189 | 2049 | ccp = str_val(global("LANG")); |
2190 | #if !HAVE_SETLOCALE_CTYPE | |
2191 | /*XXX == null? this :- or - ? */ | |
2192 | if (ccp == null) | |
2050 | #if !HAVE_POSIX_UTF8_LOCALE | |
2051 | if (!*ccp) | |
2193 | 2052 | ccp = MKSH_DEFAULT_LOCALE; |
2194 | 2053 | #endif |
2195 | /*XXX check either the parameters directly or setlocale, not both */ | |
2196 | UTFMODE = isuc(ccp); | |
2197 | #if HAVE_SETLOCALE_CTYPE | |
2198 | ccp = setlocale(LC_CTYPE, ccp); | |
2199 | #if HAVE_LANGINFO_CODESET | |
2200 | /*XXX setlocale without nl_langinfo(CODESET) makes no sense for us */ | |
2201 | if (!isuc(ccp)) | |
2202 | ccp = nl_langinfo(CODESET); | |
2203 | #endif | |
2204 | if (isuc(ccp)) | |
2205 | UTFMODE = 1; | |
2206 | #endif | |
2054 | ||
2055 | /* determine codeset used */ | |
2056 | #if HAVE_POSIX_UTF8_LOCALE | |
2057 | errno = EINVAL; | |
2058 | if (!setlocale(LC_CTYPE, ccp)) { | |
2059 | kwarnf(KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG, "setlocale"); | |
2060 | return; | |
2061 | } | |
2062 | ccp = nl_langinfo(CODESET); | |
2063 | #else | |
2064 | /* tacked on to a locale name or just a codeset? */ | |
2065 | if ((cdp = cstrchr(ccp, '.'))) | |
2066 | ccp = cdp + 1; | |
2067 | #endif | |
2068 | ||
2069 | /* see whether it’s UTF-8 */ | |
2070 | UTFMODE = 0; | |
2071 | if (!isCh(ccp[0], 'U', 'u') || | |
2072 | !isCh(ccp[1], 'T', 't') || | |
2073 | !isCh(ccp[2], 'F', 'f')) | |
2074 | return; | |
2075 | ccp += isch(ccp[3], '-') ? 4 : 3; | |
2076 | if (!isch(*ccp, '8')) | |
2077 | return; | |
2078 | ++ccp; | |
2079 | /* verify nothing untoward trails the string */ | |
2080 | #if !HAVE_POSIX_UTF8_LOCALE | |
2081 | if (cdp) { | |
2082 | /* tacked onto a locale name */ | |
2083 | if (*ccp && !isch(*ccp, '@')) | |
2084 | return; | |
2085 | } else | |
2086 | /* OSX has a "UTF-8" locale… */ | |
2087 | #endif | |
2088 | /* just a codeset so require EOS */ | |
2089 | if (*ccp != '\0') | |
2090 | return; | |
2091 | /* positively identified as UTF-8 */ | |
2092 | UTFMODE = 1; | |
2207 | 2093 | } |
2208 | 2094 | #endif |
2209 | 2095 |
0 | /*- | |
1 | * MirBSD sanitisation attempt for C integer madness | |
2 | * | |
3 | * Published under Ⓕ CC0 | |
4 | */ | |
5 | ||
6 | #ifndef SYSKERN_MBSDINT_H | |
7 | #define SYSKERN_MBSDINT_H "$MirOS: src/bin/mksh/mbsdint.h,v 1.2 2022/01/28 03:49:12 tg Exp $" | |
8 | ||
9 | /* if you have <sys/types.h> and/or <stdint.h>, include them before this */ | |
10 | ||
11 | #if !defined(_KERNEL) && !defined(_STANDALONE) | |
12 | #include <limits.h> | |
13 | #include <stddef.h> | |
14 | #else | |
15 | #include <sys/cdefs.h> | |
16 | #include <sys/limits.h> | |
17 | #include <sys/stddef.h> | |
18 | #endif | |
19 | ||
20 | /* should be in <sys/cdefs.h> via <limits.h> */ | |
21 | #ifndef __predict_true | |
22 | #if defined(__GNUC__) && (__GNUC__ >= 3) /* 2.96, but keep it simple here */ | |
23 | #define __predict_true(exp) __builtin_expect(!!(exp), 1) | |
24 | #define __predict_false(exp) __builtin_expect(!!(exp), 0) | |
25 | #else | |
26 | #define __predict_true(exp) (!!(exp)) | |
27 | #define __predict_false(exp) (!!(exp)) | |
28 | #endif /* !GCC 3.x */ | |
29 | #endif /* ndef(__predict_true) */ | |
30 | ||
31 | #if !defined(SIZE_MAX) && defined(SIZE_T_MAX) | |
32 | #define SIZE_MAX SIZE_T_MAX | |
33 | #endif | |
34 | ||
35 | /* compile-time assertions: mbiCTAS(srcf_c) { … }; */ | |
36 | #define mbiCTAS(name) struct ctassert_ ## name | |
37 | #define mbiCTA(name,cond) char cta_ ## name [(cond) ? 1 : -1] | |
38 | /* special CTAs */ | |
39 | #define mbiCTA_TYPE_NOTF(type) char ctati_ ## type [((type)0.5 == 0) ? 1 : -1] | |
40 | ||
41 | /* largest integer */ | |
42 | #if defined(INTMAX_MIN) | |
43 | #define mbiHUGE_S intmax_t | |
44 | #define mbiHUGE_MIN INTMAX_MIN | |
45 | #define mbiHUGE_MAX INTMAX_MAX | |
46 | #define mbiHUGE_U uintmax_t | |
47 | #define mbiHUGE_UMAX UINTMAX_MAX | |
48 | #elif defined(LLONG_MIN) | |
49 | #define mbiHUGE_S long long | |
50 | #define mbiHUGE_MIN LLONG_MIN | |
51 | #define mbiHUGE_MAX LLONG_MAX | |
52 | #define mbiHUGE_U unsigned long long | |
53 | #define mbiHUGE_UMAX ULLONG_MAX | |
54 | #else | |
55 | #define mbiHUGE_S long | |
56 | #define mbiHUGE_MIN LONG_MIN | |
57 | #define mbiHUGE_MAX LONG_MAX | |
58 | #define mbiHUGE_U unsigned long | |
59 | #define mbiHUGE_UMAX ULONG_MAX | |
60 | #endif | |
61 | ||
62 | /* kinds of types */ | |
63 | /* runtime only, but see mbiCTA_TYPE_NOTF */ | |
64 | #define mbiTYPE_ISF(type) ((double)0.5 == (double)(type)0.5) | |
65 | /* compile-time and runtime */ | |
66 | #define mbiTYPE_ISU(type) ((type)-1 > 0) | |
67 | /* limits of types */ | |
68 | #define mbiTYPE_UMAX(type) ((type)~(type)0) | |
69 | #define mbiTYPE_UBITS(type) mbiMASK_BITS(mbiTYPE_UMAX(type)) | |
70 | /* calculation by Hallvard B Furuseth (from comp.lang.c), up to 2039 bits */ | |
71 | #define mbiMASK_BITS(maxv) ((unsigned int)((maxv) / ((maxv) % 255 + 1) / \ | |
72 | 255 % 255 * 8 + 7 - 86 / ((maxv) % 255 + 12))) | |
73 | ||
74 | /* ensure v is a positive (2ⁿ-1) number (n>0), up to 279 bits */ | |
75 | #define mbiMASK_CHK(v) ((v) > 0 ? mbi_maskchk31_1((v)) : 0) | |
76 | #define mbi_maskchks(v,m,o,n) (v <= m ? o : ((v & m) == m) && n) | |
77 | #define mbi_maskchk31s(v,n) mbi_maskchks(v, 0x7FFFFFFFUL, \ | |
78 | mbi_maskchk16(v), n) | |
79 | #define mbi_maskchk31_1(v) mbi_maskchk31s(v, mbi_maskchk31_2(v >> 31)) | |
80 | #define mbi_maskchk31_2(v) mbi_maskchk31s(v, mbi_maskchk31_3(v >> 31)) | |
81 | #define mbi_maskchk31_3(v) mbi_maskchk31s(v, mbi_maskchk31_4(v >> 31)) | |
82 | #define mbi_maskchk31_4(v) mbi_maskchk31s(v, mbi_maskchk31_5(v >> 31)) | |
83 | #define mbi_maskchk31_5(v) mbi_maskchk31s(v, mbi_maskchk31_6(v >> 31)) | |
84 | #define mbi_maskchk31_6(v) mbi_maskchk31s(v, mbi_maskchk31_7(v >> 31)) | |
85 | #define mbi_maskchk31_7(v) mbi_maskchk31s(v, mbi_maskchk31_8(v >> 31)) | |
86 | #define mbi_maskchk31_8(v) mbi_maskchk31s(v, mbi_maskchk31_9(v >> 31)) | |
87 | #define mbi_maskchk31_9(v) (v <= 0x7FFFFFFFUL && mbi_maskchk16(v)) | |
88 | #define mbi_maskchk16(v) mbi_maskchks(v, 0xFFFFU, \ | |
89 | mbi_maskchk8(v), mbi_maskchk8(v >> 16)) | |
90 | #define mbi_maskchk8(v) mbi_maskchks(v, 0xFFU, \ | |
91 | mbi_maskchk4(v), mbi_maskchk4(v >> 8)) | |
92 | #define mbi_maskchk4(v) mbi_maskchks(v, 0xFU, \ | |
93 | mbi_maskchkF(v), mbi_maskchkF(v >> 4)) | |
94 | #define mbi_maskchkF(v) (v == 0xF || v == 7 || v == 3 || v == 1 || !v) | |
95 | ||
96 | /* compile-time assertions for mbsdint.h */ | |
97 | mbiCTAS(mbsdint_h) { | |
98 | /* compiler (in)sanity, from autoconf */ | |
99 | #define mbiCTf(x) 'x' | |
100 | mbiCTA(xlc6, mbiCTf(a) == 'x'); | |
101 | #undef mbiCTf | |
102 | mbiCTA(osf4, '\x00' == 0); | |
103 | /* C types */ | |
104 | mbiCTA(basic_char, | |
105 | sizeof(char) == 1 && (CHAR_BIT) >= 7 && (CHAR_BIT) < 2040 && | |
106 | mbiTYPE_UMAX(unsigned char) == (UCHAR_MAX) && | |
107 | sizeof(signed char) == 1 && | |
108 | sizeof(unsigned char) == 1 && | |
109 | mbiMASK_CHK(SCHAR_MAX) && mbiMASK_CHK(UCHAR_MAX) && | |
110 | ((SCHAR_MIN) == -(SCHAR_MAX) || (SCHAR_MIN) == -(SCHAR_MAX)-1) && | |
111 | mbiTYPE_UBITS(unsigned char) == (unsigned int)(CHAR_BIT)); | |
112 | mbiCTA(basic_short, | |
113 | mbiTYPE_UMAX(unsigned short) == (USHRT_MAX) && | |
114 | sizeof(short) <= (279 / CHAR_BIT) && | |
115 | sizeof(unsigned short) <= (279 / CHAR_BIT) && | |
116 | mbiMASK_CHK(SHRT_MAX) && mbiMASK_CHK(USHRT_MAX) && | |
117 | ((SHRT_MIN) == -(SHRT_MAX) || (SHRT_MIN) == -(SHRT_MAX)-1) && | |
118 | sizeof(short) >= sizeof(signed char) && | |
119 | sizeof(unsigned short) >= sizeof(unsigned char) && | |
120 | sizeof(short) == sizeof(unsigned short)); | |
121 | mbiCTA(basic_int, | |
122 | mbiTYPE_UMAX(unsigned int) == (UINT_MAX) && | |
123 | sizeof(int) <= (279 / CHAR_BIT) && | |
124 | sizeof(unsigned int) <= (279 / CHAR_BIT) && | |
125 | mbiMASK_CHK(INT_MAX) && mbiMASK_CHK(UINT_MAX) && | |
126 | ((INT_MIN) == -(INT_MAX) || (INT_MIN) == -(INT_MAX)-1) && | |
127 | sizeof(int) >= sizeof(short) && | |
128 | sizeof(unsigned int) >= sizeof(unsigned short) && | |
129 | sizeof(int) == sizeof(unsigned int)); | |
130 | mbiCTA(basic_long, | |
131 | mbiTYPE_UMAX(unsigned long) == (ULONG_MAX) && | |
132 | sizeof(long) <= (279 / CHAR_BIT) && | |
133 | sizeof(unsigned long) <= (279 / CHAR_BIT) && | |
134 | mbiMASK_CHK(LONG_MAX) && mbiMASK_CHK(ULONG_MAX) && | |
135 | ((LONG_MIN) == -(LONG_MAX) || (LONG_MIN) == -(LONG_MAX)-1) && | |
136 | sizeof(long) >= sizeof(int) && | |
137 | sizeof(unsigned long) >= sizeof(unsigned int) && | |
138 | sizeof(long) == sizeof(unsigned long)); | |
139 | #ifdef LLONG_MIN | |
140 | mbiCTA(basic_quad, | |
141 | mbiTYPE_UMAX(unsigned long long) == (ULLONG_MAX) && | |
142 | sizeof(long long) <= (279 / CHAR_BIT) && | |
143 | sizeof(unsigned long long) <= (279 / CHAR_BIT) && | |
144 | mbiMASK_CHK(LLONG_MAX) && mbiMASK_CHK(ULLONG_MAX) && | |
145 | ((LLONG_MIN) == -(LLONG_MAX) || (LLONG_MIN) == -(LLONG_MAX)-1) && | |
146 | sizeof(long long) >= sizeof(long) && | |
147 | sizeof(unsigned long long) >= sizeof(unsigned long) && | |
148 | sizeof(long long) == sizeof(unsigned long long)); | |
149 | #endif | |
150 | #ifdef INTMAX_MIN | |
151 | mbiCTA(basic_imax, | |
152 | mbiTYPE_UMAX(uintmax_t) == (UINTMAX_MAX) && | |
153 | sizeof(intmax_t) <= (279 / CHAR_BIT) && | |
154 | sizeof(uintmax_t) <= (279 / CHAR_BIT) && | |
155 | mbiMASK_CHK(INTMAX_MAX) && mbiMASK_CHK(UINTMAX_MAX) && | |
156 | ((INTMAX_MIN) == -(INTMAX_MAX) || (INTMAX_MIN) == -(INTMAX_MAX)-1) && | |
157 | #ifdef LLONG_MIN | |
158 | sizeof(intmax_t) >= sizeof(long long) && | |
159 | sizeof(uintmax_t) >= sizeof(unsigned long long) && | |
160 | #else | |
161 | sizeof(intmax_t) >= sizeof(long) && | |
162 | sizeof(uintmax_t) >= sizeof(unsigned long) && | |
163 | #endif | |
164 | sizeof(intmax_t) == sizeof(uintmax_t)); | |
165 | #endif | |
166 | /* size_t is C but ssize_t is POSIX */ | |
167 | mbiCTA_TYPE_NOTF(size_t); | |
168 | mbiCTA(basic_sizet, | |
169 | sizeof(size_t) >= sizeof(unsigned int) && | |
170 | sizeof(size_t) <= sizeof(mbiHUGE_U) && | |
171 | mbiTYPE_ISU(size_t) && | |
172 | #ifdef SIZE_MAX | |
173 | mbiMASK_CHK(SIZE_MAX) && | |
174 | mbiMASK_BITS(SIZE_MAX) <= mbiTYPE_UBITS(size_t) && | |
175 | ((SIZE_MAX) == (mbiHUGE_U)(size_t)(SIZE_MAX)) && | |
176 | #endif | |
177 | mbiTYPE_UBITS(size_t) <= mbiMASK_BITS(mbiHUGE_UMAX)); | |
178 | mbiCTA_TYPE_NOTF(ptrdiff_t); | |
179 | mbiCTA(basic_ptrdifft, | |
180 | sizeof(ptrdiff_t) >= sizeof(int) && | |
181 | sizeof(ptrdiff_t) <= sizeof(mbiHUGE_S) && | |
182 | !mbiTYPE_ISU(ptrdiff_t) && | |
183 | #ifdef PTRDIFF_MAX | |
184 | mbiMASK_CHK(PTRDIFF_MAX) && | |
185 | ((PTRDIFF_MAX) == (mbiHUGE_S)(ptrdiff_t)(PTRDIFF_MAX)) && | |
186 | #endif | |
187 | 1); | |
188 | /* UGH! off_t is POSIX, with no _MIN/_MAX constants… WTF‽ */ | |
189 | #ifdef SSIZE_MAX | |
190 | mbiCTA_TYPE_NOTF(ssize_t); | |
191 | mbiCTA(basic_ssizet, | |
192 | sizeof(ssize_t) == sizeof(size_t) && | |
193 | !mbiTYPE_ISU(ssize_t) && | |
194 | mbiMASK_CHK(SSIZE_MAX) && | |
195 | ((SSIZE_MAX) == (mbiHUGE_S)(ssize_t)(SSIZE_MAX)) && | |
196 | #ifdef SIZE_MAX | |
197 | mbiMASK_BITS(SSIZE_MAX) <= mbiMASK_BITS(SIZE_MAX) && | |
198 | #endif | |
199 | mbiMASK_BITS(SSIZE_MAX) < mbiTYPE_UBITS(size_t)); | |
200 | #endif | |
201 | /* C99 §6.2.6.2(1, 2, 6) permits M ≤ N, but M < N is normally desired */ | |
202 | /* here require signed/unsigned types to have same width (M=N-1) */ | |
203 | mbiCTA(vbits_char, mbiMASK_BITS(UCHAR_MAX) == mbiMASK_BITS(SCHAR_MAX) + 1U); | |
204 | mbiCTA(vbits_short, mbiMASK_BITS(USHRT_MAX) == mbiMASK_BITS(SHRT_MAX) + 1U); | |
205 | mbiCTA(vbits_int, mbiMASK_BITS(UINT_MAX) == mbiMASK_BITS(INT_MAX) + 1U); | |
206 | mbiCTA(vbits_long, mbiMASK_BITS(ULONG_MAX) == mbiMASK_BITS(LONG_MAX) + 1U); | |
207 | #ifdef LLONG_MIN | |
208 | mbiCTA(vbits_quad, mbiMASK_BITS(ULLONG_MAX) == mbiMASK_BITS(LLONG_MAX) + 1U); | |
209 | #endif | |
210 | #ifdef INTMAX_MIN | |
211 | mbiCTA(vbits_imax, mbiMASK_BITS(UINTMAX_MAX) == mbiMASK_BITS(INTMAX_MAX) + 1U); | |
212 | #endif | |
213 | /* require pointers and size_t to take up the same amount of space */ | |
214 | mbiCTA(sizet_voidptr, sizeof(size_t) == sizeof(void *)); | |
215 | mbiCTA(sizet_funcptr, sizeof(size_t) == sizeof(void (*)(void))); | |
216 | #if 0 /* breaks on LLP64 (e.g. Windows/amd64) */ | |
217 | mbiCTA(sizet_inulong, sizeof(size_t) <= sizeof(long)); | |
218 | #endif | |
219 | /* assume ptrdiff_t and (s)size_t will fit each other */ | |
220 | mbiCTA(sizet_ptrdiff, sizeof(size_t) == sizeof(ptrdiff_t)); | |
221 | }; | |
222 | ||
223 | /* | |
224 | * calculations where the unsigned type is used as backing store, | |
225 | * doing the two’s complement conversion manually (to avoid UB/IB); | |
226 | * (M=N-1), see above, is required for these to work (symmetrically) | |
227 | * | |
228 | * ut = unsigned type (e.g. unsigned long); st = signed type (e.g. long) | |
229 | * SM = signed max (e.g. LONG_MAX); v = value | |
230 | * m = magnitude (≥ 0 value); vz = signbit (0:value; 1:-value) | |
231 | * HM = half mask (e.g. (ut)0x7FFFUL); FM = full mask (e.g. (ut)0xFFFFUL) | |
232 | */ | |
233 | ||
234 | /* 1. casting between unsigned(two’s complement) and signed(native) */ | |
235 | #define mbiA_U2S(ut,st,SM,v) (((v) > (ut)(SM)) ? \ | |
236 | (st)(-(st)(~(v)) - (st)1) : \ | |
237 | (st)(v)) | |
238 | #define mbiA_S2U(ut,st,v) (((v) < 0) ? \ | |
239 | (ut)(~(ut)(-((v) + (st)1))) : \ | |
240 | (ut)(v)) | |
241 | ||
242 | /* 2. converting between signed(native) and signbit(vz) plus magnitude */ | |
243 | #define mbiA_VZM2S(ut,st,vz,m) (((vz) && (m) > 0) ? \ | |
244 | (st)(-(st)((m) - (ut)1) - (st)1) : \ | |
245 | (st)(m)) | |
246 | #define mbiA_S2VZ(v) ((v) < 0) | |
247 | #define mbiA_S2M(ut,st,v) (((v) < 0) ? \ | |
248 | (ut)((ut)(-((v) + (st)1)) + (ut)1) : \ | |
249 | (ut)(v)) | |
250 | ||
251 | /* 3. masking arithmetics in possibly-longer type */ | |
252 | #define mbiMA_U2S(ut,st,FM,HM,v) \ | |
253 | (((ut)((v) & FM) > HM) ? \ | |
254 | (st)(-(st)(~(v) & HM) - (st)1) : \ | |
255 | (st)((v) & HM)) | |
256 | #define mbiMA_S2U(ut,st,FM,v) ((ut)(mbiA_S2U(ut, st, v) & FM)) | |
257 | #define mbiMA_VZM2S(ut,st,FM,HM,vz,m) \ | |
258 | (((vz) && (ut)((m) & FM) > 0) ? \ | |
259 | (st)(-(st)(((m) - (ut)1) & HM) - (st)1) : \ | |
260 | (st)((m) & HM)) | |
261 | #define mbiMA_S2VZ(v) ((v) < 0) | |
262 | #define mbiMA_S2M(ut,st,HM,v) (((v) < 0) ? \ | |
263 | (ut)((ut)((-((v) + (st)1)) & HM) + (ut)1) : \ | |
264 | (ut)((ut)(v) & HM)) | |
265 | ||
266 | /* | |
267 | * UB-safe overflow/underflow-checking integer arithmetics | |
268 | * | |
269 | * Before using, #define mbiCfail to the action that should be | |
270 | * taken on check (e.g. "goto fail" or "return (0)"); make sure | |
271 | * to #undef mbiCfail before the end of the function body though! | |
272 | * | |
273 | * There is IB on some signed operations, but that is only either | |
274 | * the result (which is checked) is implementation-defined, thus | |
275 | * safe, or an implementation-defined signal is raised, which is | |
276 | * the caller’s problem ☻ | |
277 | */ | |
278 | ||
279 | /* 1. for unsigned types checking afterwards is OK */ | |
280 | #define mbiCAUinc(vl) mbiCAUadd(vl, 1) | |
281 | #define mbiCAUdec(vl) mbiCAUsub(vl, 1) | |
282 | #define mbiCAUadd(vl,vr) do { \ | |
283 | (vl) += (vr); \ | |
284 | if (__predict_false((vl) < (vr))) \ | |
285 | mbiCfail; \ | |
286 | } while (/* CONSTCOND */ 0) | |
287 | #define mbiCAUsub(vl,vr) do { \ | |
288 | if (__predict_false((vl) < (vr))) \ | |
289 | mbiCfail; \ | |
290 | (vl) -= (vr); \ | |
291 | } while (/* CONSTCOND */ 0) | |
292 | #define mbiCAUmul(vl,vr) do { \ | |
293 | if (__predict_false((((vl) * (vr)) / (vr)) < (vl))) \ | |
294 | mbiCfail; \ | |
295 | (vl) *= (vr); \ | |
296 | } while (/* CONSTCOND */ 0) | |
297 | ||
298 | /* 2. for signed types; lim is a prefix (e.g. SHRT) */ | |
299 | #define mbiCASinc(lim,vl) do { \ | |
300 | if (__predict_false((vl) == lim ## _MAX)) \ | |
301 | mbiCfail; \ | |
302 | ++(vl); \ | |
303 | } while (/* CONSTCOND */ 0) | |
304 | #define mbiCASdec(lim,vl) do { \ | |
305 | if (__predict_false((vl) == lim ## _MIN)) \ | |
306 | mbiCfail; \ | |
307 | --(vl); \ | |
308 | } while (/* CONSTCOND */ 0) | |
309 | #define mbiCASadd(lim,vl,vr) do { \ | |
310 | if (__predict_false((vl) > (lim ## _MAX - (vr)))) \ | |
311 | mbiCfail; \ | |
312 | (vl) += (vr); \ | |
313 | } while (/* CONSTCOND */ 0) | |
314 | #define mbiCASsub(lim,vl,vr) do { \ | |
315 | if (__predict_false((vl) < (lim ## _MIN + (vr)))) \ | |
316 | mbiCfail; \ | |
317 | (vl) -= (vr); \ | |
318 | } while (/* CONSTCOND */ 0) | |
319 | #define mbiCASmul(lim,vl,vr) do { \ | |
320 | if (__predict_false((lim ## _MAX / (vr)) < (vl) || \ | |
321 | (lim ## _MIN / (vr)) > (vl))) \ | |
322 | mbiCfail; \ | |
323 | (vl) *= (vr); \ | |
324 | } while (/* CONSTCOND */ 0) | |
325 | ||
326 | /* 3. signed narrowing assign; this is IB */ | |
327 | #define mbiCASlet(dsttype,vl,srctype,vr) do { \ | |
328 | (vl) = (dsttype)(vr); \ | |
329 | if (__predict_false((srctype)(vl) != (vr))) \ | |
330 | mbiCfail; \ | |
331 | } while (/* CONSTCOND */ 0) | |
332 | ||
333 | /* | |
334 | * calculations on manual two’s complement | |
335 | * | |
336 | * addition, subtraction and multiplication, bitwise and boolean | |
337 | * operations, as well as equality comparisons can be done on the | |
338 | * unsigned value; other comparisons must be done on the signed | |
339 | * value and the other operations follow | |
340 | */ | |
341 | ||
342 | /* rotate and shift: pass *unsigned* values; shr shifts in vz bits */ | |
343 | #define mbiVAU_shift(ut,dst,vl,vr,rv) do { \ | |
344 | (dst) = (vr) & (mbiTYPE_UBITS(ut) - 1); \ | |
345 | (dst) = (dst) ? (rv) : (vl); \ | |
346 | } while (/* CONSTCOND */ 0) | |
347 | #define mbiVAUrol(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \ | |
348 | ((vl) << (dst)) | ((vl) >> (mbiTYPE_UBITS(ut) - (dst)))) | |
349 | #define mbiVAUror(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \ | |
350 | ((vl) >> (dst)) | ((vl) << (mbiTYPE_UBITS(ut) - (dst)))) | |
351 | #define mbiVAUshl(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \ | |
352 | (vl) << (dst)) | |
353 | #define mbiVAUshr(ut,dst,vz,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \ | |
354 | (vz) ? (ut)~((ut)~(vl) >> (dst)) : (vl) >> (dst)) | |
355 | #define mbiM_do(dst,FM,act) do { act; (dst) &= FM; } while (/* CONSTCOND */ 0) | |
356 | #define mbiMVAUrol(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUrol(ut,dst,vl,vr)) | |
357 | #define mbiMVAUror(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUror(ut,dst,vl,vr)) | |
358 | #define mbiMVAUshl(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUshl(ut,dst,vl,vr)) | |
359 | #define mbiMVAUshr(ut,FM,dst,vz,vl,vr) \ | |
360 | mbiM_do(dst, FM, mbiVAUshr(ut,dst,vz,vl,vr)) | |
361 | ||
362 | /* division and remainder; pass *signed* values and unsigned result vars */ | |
363 | #define mbiVASdivrem(ut,st,udiv,urem,vl,vr) do { \ | |
364 | (udiv) = mbiA_S2M(ut, st, (vl)) / mbiA_S2M(ut, st, (vr)); \ | |
365 | if (mbiA_S2VZ(vl) ^ mbiA_S2VZ(vr)) \ | |
366 | (udiv) = -(udiv); \ | |
367 | (urem) = mbiA_S2U(ut, st, (vl)) - \ | |
368 | ((udiv) * mbiA_S2U(ut, st, (vr))); \ | |
369 | } while (/* CONSTCOND */ 0) | |
370 | #define mbiMVASdivrem(ut,st,FM,HM,udiv,urem,vl,vr) do { \ | |
371 | (udiv) = mbiMA_S2M(ut, st, HM, (vl)) / \ | |
372 | mbiMA_S2M(ut, st, HM, (vr)); \ | |
373 | if (mbiMA_S2VZ(vl) ^ mbiMA_S2VZ(vr)) \ | |
374 | (udiv) = -(udiv); \ | |
375 | (urem) = mbiA_S2U(ut, st, (vl)) - \ | |
376 | ((udiv) * mbiA_S2U(ut, st, (vr))); \ | |
377 | (udiv) &= FM; \ | |
378 | (urem) &= FM; \ | |
379 | } while (/* CONSTCOND */ 0) | |
380 | ||
381 | #endif /* !SYSKERN_MBSDINT_H */ |
0 | 0 | /*- |
1 | * Copyright © 2011, 2014, 2015, 2021 | |
1 | * Copyright © 2011, 2014, 2015, 2021, 2022 | |
2 | 2 | * mirabilos <m@mirbsd.org> |
3 | 3 | * |
4 | 4 | * Provided that these terms and disclaimer and all copyright notices |
16 | 16 | * damage or existence of a defect, except proven that it results out |
17 | 17 | * of said person’s immediate fault when using the work as intended. |
18 | 18 | *- |
19 | * This file provides BAFH (Better Avalanche for the Jenkins Hash) as | |
20 | * inline macro bodies that operate on “register uint32_t” variables, | |
21 | * with variants that use their local intermediate registers. | |
22 | * | |
23 | * Usage note for BAFH with entropy distribution: input up to 4 bytes | |
24 | * is best combined into a 32-bit unsigned integer, which is then run | |
25 | * through BAFHFinish_reg for mixing and then used as context instead | |
26 | * of 0. Longer input should be handled the same: take the first four | |
27 | * bytes as IV after mixing then add subsequent bytes the same way. | |
28 | * This needs counting input bytes and is endian-dependent, thus not, | |
29 | * for speed reasons, specified for the regular stable hash, but very | |
30 | * much recommended if the actual output value may differ across runs | |
31 | * (so is using a random value instead of 0 for the IV). | |
19 | * This file provides BAFH1-0 (Better Avalanche for the Jenkins Hash) | |
20 | * as macro bodies operating on “register k32” variables (from sh.h). | |
32 | 21 | *- |
33 | 22 | * Little quote gem: |
34 | 23 | * We are looking into it. Changing the core |
37 | 26 | * -- Rasmus Lerdorf |
38 | 27 | */ |
39 | 28 | |
40 | #ifndef SYSKERN_MIRHASH_H | |
41 | #define SYSKERN_MIRHASH_H 1 | |
42 | #define SYSKERN_MIRHASH_BAFH | |
29 | #ifndef MKSH_MIRHASH_H | |
30 | #define MKSH_MIRHASH_H | |
43 | 31 | |
44 | 32 | #include <sys/types.h> |
45 | 33 | |
46 | __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.9 2021/07/31 19:56:33 tg Exp $"); | |
34 | __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.14 2022/01/27 14:15:41 tg Exp $"); | |
47 | 35 | |
48 | 36 | /*- |
49 | * BAFH itself is defined by the following primitives: | |
37 | * BAFH1-0 is defined by the following primitives: | |
50 | 38 | * |
51 | 39 | * • BAFHInit(ctx) initialises the hash context, which consists of a |
52 | * sole 32-bit unsigned integer (ideally in a register), to 0. | |
53 | * It is possible to use any initial value out of [0; 2³²[ – which | |
40 | * sole 32-bit unsigned integer (ideally in a register), to 0^H1. | |
41 | * It is possible to use any initial value out of [0; 2³²[ — which | |
54 | 42 | * is, in fact, recommended if using BAFH for entropy distribution |
55 | * – but for a regular stable hash, the IV 0 is needed. | |
43 | * — but for a regular stable hash, the IV 0^H1 is needed. | |
56 | 44 | * |
57 | 45 | * • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity |
58 | * into the hash context. The algorithm used is Jenkins’ one-at-a- | |
59 | * time, except that an additional constant 1 is added so that, if | |
60 | * the context is (still) zero, adding a NUL byte is not ignored. | |
46 | * into the hash context using Jenkins’ one-at-a-time algorithm. | |
61 | 47 | * |
62 | 48 | * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”, |
63 | 49 | * rotated right by “cl” ∈ [1; 31] (no casting, be careful!) where |
64 | * “eax” must be uint32_t and “cl” an in-range integer. | |
50 | * “eax” is K32()d and “cl” must be within range. | |
65 | 51 | * |
66 | 52 | * • BAFHFinish(ctx) avalanches the context around so every sub-byte |
67 | 53 | * depends on all input octets; afterwards, the context variable’s |
68 | 54 | * value is the hash output. BAFH does not use any padding, nor is |
69 | 55 | * the input length added; this is due to the common use case (for |
70 | 56 | * quick entropy distribution and use with a hashtable). |
71 | * Warning: BAFHFinish uses the MixColumn algorithm of AES – which | |
57 | * Warning: BAFHFinish uses the MixColumn algorithm of AES — which | |
72 | 58 | * is reversible (to avoid introducing funnels and reducing entro‐ |
73 | 59 | * py), so blinding may need to be employed for some uses, e.g. in |
74 | 60 | * mksh, after a fork. |
75 | 61 | * |
76 | * The BAFHUpdateOctet and BAFHFinish are available in two flavours: | |
77 | * suffixed with _reg (assumes the context is in a register) or _mem | |
78 | * (which doesn’t). | |
79 | * | |
80 | * The following high-level macros (with _reg and _mem variants) are | |
81 | * available: | |
62 | * The following high-level macros are available: | |
82 | 63 | * |
83 | 64 | * • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context. |
84 | 65 | * • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf). |
85 | 66 | * |
86 | 67 | * All macros may use ctx multiple times in their expansion, but all |
87 | 68 | * other arguments are always evaluated at most once except BAFHror. |
88 | * | |
89 | * To stay portable, encode numbers using ULEB128, or better and for | |
90 | * sortability, VLQ (same unsigned but big endian), normal or Git’s. | |
91 | 69 | */ |
92 | 70 | |
93 | 71 | #define BAFHInit(h) do { \ |
94 | (h) = 0; \ | |
72 | (h) = 1U; \ | |
95 | 73 | } while (/* CONSTCOND */ 0) |
96 | 74 | |
97 | #define BAFHUpdateOctet_reg(h,b) do { \ | |
98 | (h) += (unsigned char)(b); \ | |
99 | ++(h); \ | |
100 | (h) += (h) << 10; \ | |
101 | (h) ^= (h) >> 6; \ | |
75 | #define BAFHUpdateOctet(h,b) do { \ | |
76 | (h) = K32(K32(h) + KBI(b)); \ | |
77 | (h) = K32((h) + K32((h) << 10)); \ | |
78 | (h) = K32((h) ^ K32((h) >> 6)); \ | |
102 | 79 | } while (/* CONSTCOND */ 0) |
103 | 80 | |
104 | #define BAFHUpdateOctet_mem(m,b) do { \ | |
105 | register uint32_t BAFH_h = (m); \ | |
81 | #define BAFHror(eax,cl) K32(K32(K32(eax) >> (cl)) | K32(K32(eax) << (32 - (cl)))) | |
82 | ||
83 | #define BAFHFinish__impl(h,v,d) \ | |
84 | v = K32(K32(h) >> 7) & 0x01010101U; \ | |
85 | v = K32(v + K32(v << 1)); \ | |
86 | v = K32(v + K32(v << 3)); \ | |
87 | v = K32(v ^ (K32(K32(h) << 1) & 0xFEFEFEFEU)); \ | |
106 | 88 | \ |
107 | BAFHUpdateOctet_reg(BAFH_h, (b)); \ | |
108 | (m) = BAFH_h; \ | |
89 | v = K32(v ^ BAFHror(v, 8)); \ | |
90 | v = K32(v ^ (h = BAFHror(h, 8))); \ | |
91 | v = K32(v ^ (h = BAFHror(h, 8))); \ | |
92 | d = K32(v ^ BAFHror(h, 8)); | |
93 | ||
94 | #define BAFHFinish(h) do { \ | |
95 | register k32 BAFHFinish_v; \ | |
96 | \ | |
97 | BAFHFinish__impl((h), BAFHFinish_v, (h)) \ | |
109 | 98 | } while (/* CONSTCOND */ 0) |
110 | 99 | |
111 | #define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl)))) | |
112 | ||
113 | #define BAFHFinish_reg(h) do { \ | |
114 | register uint32_t BAFHFinish_v; \ | |
100 | #define BAFHUpdateMem(h,p,z) do { \ | |
101 | register const unsigned char *BAFHUpdate_p; \ | |
102 | register const unsigned char *BAFHUpdate_d; \ | |
115 | 103 | \ |
116 | BAFHFinish_v = ((h) >> 7) & 0x01010101U; \ | |
117 | BAFHFinish_v += BAFHFinish_v << 1; \ | |
118 | BAFHFinish_v += BAFHFinish_v << 3; \ | |
119 | BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU; \ | |
120 | \ | |
121 | BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \ | |
122 | BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \ | |
123 | BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \ | |
124 | (h) = BAFHror((h), 8) ^ BAFHFinish_v; \ | |
104 | BAFHUpdate_p = (const void *)(p); \ | |
105 | BAFHUpdate_d = BAFHUpdate_p + (z); \ | |
106 | while (BAFHUpdate_p < BAFHUpdate_d) \ | |
107 | BAFHUpdateOctet((h), *BAFHUpdate_p++); \ | |
125 | 108 | } while (/* CONSTCOND */ 0) |
126 | 109 | |
127 | #define BAFHFinish_mem(m) do { \ | |
128 | register uint32_t BAFHFinish_v, BAFH_h = (m); \ | |
129 | \ | |
130 | BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U; \ | |
131 | BAFHFinish_v += BAFHFinish_v << 1; \ | |
132 | BAFHFinish_v += BAFHFinish_v << 3; \ | |
133 | BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU; \ | |
134 | \ | |
135 | BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \ | |
136 | BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \ | |
137 | BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \ | |
138 | (m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v; \ | |
139 | } while (/* CONSTCOND */ 0) | |
140 | ||
141 | #define BAFHUpdateMem_reg(h,p,z) do { \ | |
142 | register const unsigned char *BAFHUpdate_p; \ | |
143 | register size_t BAFHUpdate_z = (z); \ | |
144 | \ | |
145 | BAFHUpdate_p = (const void *)(p); \ | |
146 | while (BAFHUpdate_z--) \ | |
147 | BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \ | |
148 | } while (/* CONSTCOND */ 0) | |
149 | ||
150 | /* meh should have named them _r/m but that’s not valid C */ | |
151 | #define BAFHUpdateMem_mem(m,p,z) do { \ | |
152 | register uint32_t BAFH_h = (m); \ | |
153 | \ | |
154 | BAFHUpdateMem_reg(BAFH_h, (p), (z)); \ | |
155 | (m) = BAFH_h; \ | |
156 | } while (/* CONSTCOND */ 0) | |
157 | ||
158 | #define BAFHUpdateStr_reg(h,s) do { \ | |
110 | #define BAFHUpdateStr(h,s) do { \ | |
159 | 111 | register const unsigned char *BAFHUpdate_s; \ |
160 | 112 | register unsigned char BAFHUpdate_c; \ |
161 | 113 | \ |
162 | 114 | BAFHUpdate_s = (const void *)(s); \ |
163 | 115 | while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \ |
164 | BAFHUpdateOctet_reg((h), BAFHUpdate_c); \ | |
165 | } while (/* CONSTCOND */ 0) | |
166 | ||
167 | #define BAFHUpdateStr_mem(m,s) do { \ | |
168 | register uint32_t BAFH_h = (m); \ | |
169 | \ | |
170 | BAFHUpdateStr_reg(BAFH_h, (s)); \ | |
171 | (m) = BAFH_h; \ | |
116 | BAFHUpdateOctet((h), BAFHUpdate_c); \ | |
172 | 117 | } while (/* CONSTCOND */ 0) |
173 | 118 | |
174 | 119 | #endif |
3 | 3 | /*- |
4 | 4 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
5 | 5 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, |
6 | * 2020, 2021 | |
6 | * 2020, 2021, 2022 | |
7 | 7 | * mirabilos <m@mirbsd.org> |
8 | 8 | * Copyright (c) 2015 |
9 | 9 | * Daniel Richard G. <skunk@iSKUNK.ORG> |
32 | 32 | #include <grp.h> |
33 | 33 | #endif |
34 | 34 | |
35 | __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.330 2021/10/10 20:41:17 tg Exp $"); | |
36 | ||
37 | #define KSH_CHVT_FLAG | |
38 | #ifdef MKSH_SMALL | |
39 | #undef KSH_CHVT_FLAG | |
40 | #endif | |
41 | #ifdef TIOCSCTTY | |
42 | #define KSH_CHVT_CODE | |
43 | #define KSH_CHVT_FLAG | |
44 | #endif | |
35 | __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.341 2022/01/27 13:45:05 tg Exp $"); | |
45 | 36 | |
46 | 37 | static const unsigned char *pat_scan(const unsigned char *, |
47 | 38 | const unsigned char *, bool) MKSH_A_PURE; |
50 | 41 | const unsigned char *) MKSH_A_PURE; |
51 | 42 | static const unsigned char *gmatch_cclass(const unsigned char *, unsigned char) |
52 | 43 | MKSH_A_PURE; |
53 | #ifdef KSH_CHVT_CODE | |
54 | 44 | static void chvt(const Getopt *); |
55 | #endif | |
56 | 45 | static unsigned int dollarqU(struct shf *, const unsigned char *); |
57 | 46 | #ifndef MKSH_SMALL |
58 | 47 | static void dollarq8(struct shf *, const unsigned char *); |
67 | 56 | /* we don't need to check for other codes, EPERM won't happen */ |
68 | 57 | #define DO_SETUID(func,argvec) do { \ |
69 | 58 | if ((func argvec) && errno == EAGAIN) \ |
70 | errorf("%s failed with EAGAIN, probably due to a" \ | |
71 | " too low process limit; aborting", #func); \ | |
59 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | \ | |
60 | KWF_TWOMSG, #func, "failed, probably due to a" \ | |
61 | " too low process limit; aborting"); \ | |
72 | 62 | } while (/* CONSTCOND */ 0) |
73 | 63 | #else |
74 | 64 | #define DO_SETUID(func,argvec) func argvec |
90 | 80 | } |
91 | 81 | |
92 | 82 | #define SHFLAGS_DEFNS |
93 | #define FN(sname,cname,flags,ochar) \ | |
94 | static const struct { \ | |
95 | /* character flag (if any) */ \ | |
96 | char c; \ | |
97 | /* OF_* */ \ | |
98 | unsigned char optflags; \ | |
99 | /* long name of option */ \ | |
100 | char name[sizeof(sname)]; \ | |
101 | } shoptione_ ## cname = { \ | |
102 | ochar, flags, sname \ | |
83 | #define FN(sname,cname,flags,ochar) \ | |
84 | static const struct shoptionS_ ## cname { \ | |
85 | /* character flag (if any) */ \ | |
86 | char c; \ | |
87 | /* OF_* */ \ | |
88 | unsigned char optflags; \ | |
89 | /* long name of option */ \ | |
90 | char name[sizeof(sname)]; \ | |
91 | } shoptione_ ## cname = { \ | |
92 | ochar, flags, sname \ | |
103 | 93 | }; |
104 | 94 | #include "sh_flags.gen" |
95 | ||
96 | mbiCTAS(sh_flags_gen) { | |
97 | #define FN(sname,cname,flags,ochar) mbiCTA(cta_ ## cname, \ | |
98 | offsetof(struct shoptionS_ ## cname, optflags) == 1 && \ | |
99 | offsetof(struct shoptionS_ ## cname, name[0]) == 2); | |
100 | #include "sh_flags.gen" | |
101 | }; | |
105 | 102 | |
106 | 103 | #define OFC(i) (options[i][-2]) |
107 | 104 | #define OFF(i) (((const unsigned char *)options[i])[-1]) |
242 | 239 | |
243 | 240 | /* change a Flag(*) value; takes care of special actions */ |
244 | 241 | void |
245 | change_flag(enum sh_flag f, int what, bool newset) | |
242 | change_flag(enum sh_flag f, | |
243 | /* OF_INTERNAL, OF_FIRSTTIME, OF_CMDLINE, or OF_SET */ | |
244 | unsigned int what, | |
245 | bool newset) | |
246 | 246 | { |
247 | 247 | unsigned char oldval = Flag(f); |
248 | 248 | unsigned char newval = (newset ? 1 : 0); |
312 | 312 | |
313 | 313 | if (f == FTALKING) { |
314 | 314 | /* Changing interactive flag? */ |
315 | if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid) | |
315 | if (what == OF_CMDLINE && procpid == kshpid) | |
316 | 316 | Flag(FTALKING_I) = newval; |
317 | 317 | #ifndef MKSH_UNEMPLOYED |
318 | 318 | } else if (f == FMONITOR) { |
357 | 357 | if ((Flag(FXTRACE) = newval) == 2) { |
358 | 358 | in_xtrace = true; |
359 | 359 | Flag(FXTRACE) = 0; |
360 | shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace); | |
360 | shf_putsv(substitute(str_val(global("PS4")), 0), shl_xtrace); | |
361 | 361 | Flag(FXTRACE) = 2; |
362 | 362 | in_xtrace = false; |
363 | 363 | } |
370 | 370 | int |
371 | 371 | parse_args(const char **argv, |
372 | 372 | /* OF_FIRSTTIME, OF_CMDLINE, or OF_SET */ |
373 | int what, | |
373 | unsigned int what, | |
374 | 374 | bool *setargsp) |
375 | 375 | { |
376 | 376 | static const char cmd_opts[] = |
386 | 386 | #undef SHFLAGS_NOT_CMD |
387 | 387 | ; |
388 | 388 | bool set; |
389 | const char *opts = what == OF_CMDLINE || what == OF_FIRSTTIME ? | |
390 | cmd_opts : set_opts; | |
389 | const char * const opts = what == OF_SET ? set_opts : cmd_opts; | |
391 | 390 | const char *array = NULL; |
392 | 391 | Getopt go; |
393 | 392 | size_t i; |
414 | 413 | * lone -o: print options |
415 | 414 | * |
416 | 415 | * Note that on the command line, -o requires |
417 | * an option (ie, can't get here if what is | |
418 | * OF_CMDLINE). | |
416 | * an option (i.e. can't get here if what is | |
417 | * not OF_SET). | |
419 | 418 | */ |
420 | 419 | #if !defined(MKSH_SMALL) || defined(DEBUG) |
421 | 420 | if (!set && !baseline_flags[(int)FNFLAGS]) { |
471 | 470 | } |
472 | 471 | break; |
473 | 472 | |
474 | #ifdef KSH_CHVT_FLAG | |
475 | 473 | case 'T': |
476 | 474 | if (what != OF_FIRSTTIME) |
477 | 475 | break; |
478 | #ifndef KSH_CHVT_CODE | |
479 | errorf("no TIOCSCTTY ioctl"); | |
480 | #else | |
481 | change_flag(FTALKING, OF_CMDLINE, true); | |
482 | 476 | chvt(&go); |
483 | 477 | break; |
484 | #endif | |
485 | #endif | |
486 | 478 | |
487 | 479 | case '?': |
488 | 480 | return (-1); |
490 | 482 | default: |
491 | 483 | if (what == OF_FIRSTTIME) |
492 | 484 | break; |
493 | /* -s: sort positional params (AT&T ksh stupidity) */ | |
494 | if (what == OF_SET && optc == 's') { | |
485 | /* -s: sort positional params (via AT&T ksh) */ | |
486 | if (what == OF_SET && isch(optc, 's')) { | |
495 | 487 | sortargs = true; |
496 | 488 | break; |
497 | 489 | } |
502 | 494 | break; |
503 | 495 | } |
504 | 496 | if (i == NELEM(options)) |
505 | internal_errorf("parse_args: '%c'", optc); | |
506 | } | |
507 | } | |
508 | if (!(go.info & GI_MINUSMINUS) && argv[go.optind] && | |
497 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
498 | "parse_args: '%c'", optc); | |
499 | } | |
500 | } | |
501 | /* lone ‘-’ (or ‘+’)? */ | |
502 | if (argv[go.optind] && argv[go.optind][1] == '\0' && | |
509 | 503 | ctype(argv[go.optind][0], C_MINUS | C_PLUS) && |
510 | argv[go.optind][1] == '\0') { | |
511 | /* lone - clears -v and -x flags */ | |
512 | if (argv[go.optind][0] == '-') { | |
504 | !(go.info & GI_MINUSMINUS)) { | |
505 | /* POSIX: lone hyphen-minus sh first arg ignored */ | |
506 | if (what == OF_SET && isch(argv[go.optind][0], '-')) { | |
507 | /* set; lone dash clears -v and -x flags (obsolete) */ | |
513 | 508 | Flag(FVERBOSE) = 0; |
514 | 509 | change_xtrace(0, false); |
515 | 510 | } |
516 | /* set skips lone - or + option */ | |
511 | /* either way, skip it (POSIX only dash but… meh) */ | |
517 | 512 | go.optind++; |
518 | 513 | } |
519 | 514 | if (setargsp) |
548 | 543 | int |
549 | 544 | getn(const char *s, int *ai) |
550 | 545 | { |
551 | return (getpn(&s, ai) && !*s); | |
546 | if (!getpn(&s, ai)) | |
547 | return (0); | |
548 | if (!*s) | |
549 | return (1); | |
550 | errno = EINVAL; | |
551 | return (0); | |
552 | 552 | } |
553 | 553 | |
554 | 554 | /* |
582 | 582 | } |
583 | 583 | |
584 | 584 | while (ctype(c, C_DIGIT)) { |
585 | if (num > 214748364U) | |
585 | if (num > 214748364U) { | |
586 | 586 | /* overflow on multiplication */ |
587 | 587 | state = 2; |
588 | errno = EOVERFLOW; | |
589 | } | |
588 | 590 | if (state < 2) { |
589 | 591 | state = 1; |
590 | 592 | num = num * 10U + (unsigned int)ksh_numdig(c); |
594 | 596 | } |
595 | 597 | --s; |
596 | 598 | |
597 | if (num > (neg ? 2147483648U : 2147483647U)) | |
599 | if (num > (neg ? 2147483648U : 2147483647U)) { | |
598 | 600 | /* overflow for signed 32-bit int */ |
599 | 601 | state = 2; |
602 | errno = EOVERFLOW; | |
603 | } | |
600 | 604 | |
601 | 605 | if (state) |
602 | 606 | *sp = s; |
607 | else | |
608 | errno = EINVAL; | |
603 | 609 | if (state != 1) { |
604 | 610 | *ai = 0; |
605 | 611 | return (0); |
993 | 999 | /*XXX this is a prime example for bsearch or a const hashtable */ |
994 | 1000 | static const struct cclass { |
995 | 1001 | const char *name; |
996 | uint32_t value; | |
1002 | kui value; | |
997 | 1003 | } cclasses[] = { |
998 | 1004 | /* POSIX */ |
999 | 1005 | { "alnum", C_ALNUM }, |
1286 | 1292 | * |
1287 | 1293 | * Non-standard features: |
1288 | 1294 | * - ';' is like ':' in options, except the argument is optional |
1289 | * (if it isn't present, optarg is set to 0). | |
1295 | * (if it isn't present, optarg is set to NULL). | |
1290 | 1296 | * Used for 'set -o'. |
1291 | 1297 | * - ',' is like ':' in options, except the argument always immediately |
1292 | 1298 | * follows the option character (optarg is set to the null string if |
1336 | 1342 | go->buf[0] = c; |
1337 | 1343 | go->optarg = go->buf; |
1338 | 1344 | } else { |
1339 | warningf(true, Tf_optfoo, | |
1340 | (go->flags & GF_NONAME) ? "" : argv[0], | |
1341 | (go->flags & GF_NONAME) ? "" : Tcolsp, | |
1342 | c, Tunknown_option); | |
1345 | ksh_getopt_opterr(c, | |
1346 | (go->flags & GF_NONAME) ? null : argv[0], | |
1347 | Tunknown_option); | |
1343 | 1348 | if (go->flags & GF_ERROR) |
1344 | bi_errorfz(); | |
1349 | bi_unwind(1); | |
1345 | 1350 | } |
1346 | 1351 | return (ORD('?')); |
1347 | 1352 | } |
1364 | 1369 | go->optarg = go->buf; |
1365 | 1370 | return (ORD(':')); |
1366 | 1371 | } |
1367 | warningf(true, Tf_optfoo, | |
1368 | (go->flags & GF_NONAME) ? "" : argv[0], | |
1369 | (go->flags & GF_NONAME) ? "" : Tcolsp, | |
1370 | c, Treq_arg); | |
1372 | ksh_getopt_opterr(c, | |
1373 | (go->flags & GF_NONAME) ? null : argv[0], | |
1374 | Treq_arg); | |
1371 | 1375 | if (go->flags & GF_ERROR) |
1372 | bi_errorfz(); | |
1376 | bi_unwind(1); | |
1373 | 1377 | return (ORD('?')); |
1374 | 1378 | } |
1375 | 1379 | go->p = 0; |
1399 | 1403 | } |
1400 | 1404 | } |
1401 | 1405 | return (ord(c)); |
1406 | } | |
1407 | ||
1408 | void | |
1409 | ksh_getopt_opterr(int ch, const char *name, const char *msg) | |
1410 | { | |
1411 | static char buf[3] = { '-', KSH_BEL, '\0' }; | |
1412 | ||
1413 | buf[1] = ch; | |
1414 | if (name == null || name == kshname) | |
1415 | kwarnf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
1416 | KWF_TWOMSG | KWF_NOERRNO, buf, msg); | |
1417 | else | |
1418 | kwarnf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
1419 | KWF_THREEMSG | KWF_NOERRNO, name, buf, msg); | |
1402 | 1420 | } |
1403 | 1421 | |
1404 | 1422 | /* |
1682 | 1700 | |
1683 | 1701 | if (max_colz > 2147483646) { |
1684 | 1702 | #ifndef MKSH_SMALL |
1685 | internal_warningf("print_columns called with %s=%zu >= INT_MAX", | |
1703 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1704 | "print_columns called with %s=%zu >= INT_MAX", | |
1686 | 1705 | "max_col", max_colz); |
1687 | 1706 | #endif |
1688 | 1707 | return; |
1691 | 1710 | |
1692 | 1711 | if (max_oct > 2147483646) { |
1693 | 1712 | #ifndef MKSH_SMALL |
1694 | internal_warningf("print_columns called with %s=%zu >= INT_MAX", | |
1713 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
1714 | "print_columns called with %s=%zu >= INT_MAX", | |
1695 | 1715 | "max_oct", max_oct); |
1696 | 1716 | #endif |
1697 | 1717 | return; |
1757 | 1777 | { |
1758 | 1778 | char *cp, *dp, *ep; |
1759 | 1779 | |
1780 | rndpush(buf, len); | |
1760 | 1781 | if (!len || !(dp = memchr(buf, '\0', len))) |
1761 | 1782 | return; |
1762 | 1783 | |
1967 | 1988 | if (pathcnd) { |
1968 | 1989 | #ifdef MKSH__NO_PATH_MAX |
1969 | 1990 | /* same as notoktoadd(pathlen, 1) but adapted */ |
1970 | if ((uintmax_t)sb.st_size >= (uintmax_t)SIZE_MAX) { | |
1991 | if ((uintmax_t)sb.st_size >= (uintmax_t)mksh_MAXSZ) { | |
1971 | 1992 | errno = ENAMETOOLONG; |
1972 | 1993 | goto notfound; |
1973 | 1994 | } |
1974 | ldestlen = sb.st_size + 1; /* <= SIZE_MAX */ | |
1995 | ldestlen = sb.st_size + 1; /* <= mksh_MAXSZ */ | |
1975 | 1996 | #endif |
1976 | 1997 | /* ldestsz == pathlen + 1 */ |
1977 | 1998 | ldest = aresize(ldest, ldestsz, ATEMP); |
2466 | 2487 | * setting in AT&T ksh) |
2467 | 2488 | */ |
2468 | 2489 | if (current_wd[0]) |
2469 | /* Ignore failure (happens if readonly or integer) */ | |
2490 | /* Ignore failure (happens if read-only or integer) */ | |
2470 | 2491 | setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); |
2471 | 2492 | |
2472 | 2493 | if (!mksh_abspath(Xstring(xs, xp))) { |
2485 | 2506 | char *ptmp = pwd; |
2486 | 2507 | |
2487 | 2508 | set_current_wd(ptmp); |
2488 | /* Ignore failure (happens if readonly or integer) */ | |
2509 | /* Ignore failure (happens if read-only or integer) */ | |
2489 | 2510 | setstr(pwd_s, ptmp, KSH_RETURN_ERROR); |
2490 | 2511 | } else { |
2491 | 2512 | set_current_wd(null); |
2502 | 2523 | return (rv); |
2503 | 2524 | } |
2504 | 2525 | |
2505 | #ifdef KSH_CHVT_CODE | |
2506 | 2526 | extern void chvt_reinit(void); |
2507 | 2527 | |
2508 | 2528 | static void |
2509 | 2529 | chvt(const Getopt *go) |
2510 | 2530 | { |
2531 | char buf[99], ch; | |
2511 | 2532 | const char *dv = go->optarg; |
2512 | char *cp = NULL; | |
2513 | int fd; | |
2514 | ||
2515 | switch (*dv) { | |
2516 | case '-': | |
2533 | int fd, pfd[2]; | |
2534 | pid_t cpid; | |
2535 | bool isdaemon = false, dowait = false; | |
2536 | #ifndef MKSH_DISABLE_REVOKE_WARNING | |
2537 | int revwarn = 0; | |
2538 | #if !HAVE_REVOKE | |
2539 | #define ifrevwarn | |
2540 | #else | |
2541 | #define ifrevwarn if (revwarn) | |
2542 | #endif | |
2543 | #endif | |
2544 | ||
2545 | switch (ord(*dv)) { | |
2546 | case ORD('-'): | |
2547 | isdaemon = true; | |
2517 | 2548 | dv = "/dev/null"; |
2518 | 2549 | break; |
2519 | case '!': | |
2550 | case ORD('!'): | |
2551 | dowait = true; | |
2520 | 2552 | ++dv; |
2521 | 2553 | /* FALLTHROUGH */ |
2522 | 2554 | default: { |
2523 | 2555 | struct stat sb; |
2524 | 2556 | |
2525 | 2557 | if (stat(dv, &sb)) { |
2526 | cp = shf_smprintf("/dev/ttyC%s", dv); | |
2527 | dv = cp; | |
2528 | if (stat(dv, &sb)) { | |
2529 | memmove(cp + 1, cp, /* /dev/tty */ 8); | |
2530 | dv = cp + 1; | |
2531 | if (stat(dv, &sb)) { | |
2532 | errorf(Tchvt2, | |
2533 | "can't find tty", go->optarg); | |
2558 | int E = errno; | |
2559 | ||
2560 | memcpy(buf, "/dev/ttyC", 9U); | |
2561 | strlcpy(buf + 9U, dv, sizeof(buf) - 9U); | |
2562 | if (stat(buf, &sb)) { | |
2563 | strlcpy(buf + 8U, dv, sizeof(buf) - 8U); | |
2564 | if (stat(buf, &sb)) | |
2565 | kerrf(KWF_VERRNO | KWF_ERR(1) | | |
2566 | KWF_PREFIX | KWF_TWOMSG, E, | |
2567 | "chvt", dv); | |
2568 | } | |
2569 | dv = buf; | |
2570 | } | |
2571 | if (!S_ISCHR(sb.st_mode)) | |
2572 | kerrf(KWF_VERRNO | KWF_ERR(1) | KWF_PREFIX | | |
2573 | KWF_TWOMSG, (int)(ENOTTY), "chvt", dv); | |
2574 | #ifndef MKSH_DISABLE_REVOKE_WARNING | |
2575 | #if !HAVE_REVOKE | |
2576 | #ifdef ENOSYS | |
2577 | revwarn = ENOSYS; | |
2578 | #else | |
2579 | revwarn = EINVAL; | |
2580 | #endif | |
2581 | #else | |
2582 | revwarn = revoke(dv) ? errno : 0; | |
2583 | #endif | |
2584 | ifrevwarn kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_THREEMSG, | |
2585 | revwarn, "chvt", dv, | |
2586 | "can't revoke; new shell is potentially insecure"); | |
2587 | #endif | |
2588 | } | |
2589 | } | |
2590 | if (pipe(pfd)) | |
2591 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, "chvt", "pipe"); | |
2592 | switch ((cpid = fork())) { | |
2593 | case -1: | |
2594 | close(pfd[0]); | |
2595 | close(pfd[1]); | |
2596 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, "chvt", "fork"); | |
2597 | case 0: | |
2598 | close(pfd[0]); | |
2599 | break; | |
2600 | default: | |
2601 | close(pfd[1]); | |
2602 | if (read(pfd[0], &ch, 1) != 1 || !isch(ch, '.')) | |
2603 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_THREEMSG | | |
2604 | KWF_NOERRNO, "chvt", dv, | |
2605 | "child process initialisation failure"); | |
2606 | close(pfd[0]); | |
2607 | if (dowait) { | |
2608 | pid_t corpse; | |
2609 | int status; | |
2610 | ||
2611 | while (/* CONSTCOND */ 1) { | |
2612 | #ifndef MKSH_NOPROSPECTOFWORK | |
2613 | corpse = waitpid(cpid, &status, 0); | |
2614 | #else | |
2615 | corpse = wait(&status); | |
2616 | #endif | |
2617 | if (corpse == -1) { | |
2618 | status = errno; | |
2619 | if (status == ECHILD) | |
2620 | break; | |
2621 | if (status == EINTR) | |
2622 | continue; | |
2623 | kerrf(KWF_ERR(1) | KWF_PREFIX | | |
2624 | KWF_TWOMSG, "chvt", "wait"); | |
2534 | 2625 | } |
2535 | } | |
2536 | } | |
2537 | if (!S_ISCHR(sb.st_mode)) | |
2538 | errorf(Tchvt2, "not a char device", dv); | |
2539 | #ifndef MKSH_DISABLE_REVOKE_WARNING | |
2540 | #if HAVE_REVOKE | |
2541 | if (revoke(dv)) | |
2542 | #endif | |
2543 | warningf(false, Tchvt2, | |
2544 | "new shell is potentially insecure, can't revoke", | |
2545 | dv); | |
2546 | #endif | |
2547 | } | |
2548 | } | |
2626 | #ifdef MKSH_NOPROSPECTOFWORK | |
2627 | /* should not happen but… */ | |
2628 | if (corpse != cpid) | |
2629 | continue; | |
2630 | #endif | |
2631 | if (WIFSIGNALED(status)) { | |
2632 | status = WTERMSIG(status); | |
2633 | dv = status > 0 && status < ksh_NSIG ? | |
2634 | ksh_sigmess(status) : NULL; | |
2635 | if (ksh_sigmessf(dv)) | |
2636 | dv = "Signalled"; | |
2637 | kwarnf(KWF_PREFIX | KWF_TWOMSG | | |
2638 | KWF_NOERRNO, "chvt", dv); | |
2639 | } else if (WIFEXITED(status)) { | |
2640 | status = (WEXITSTATUS(status)) & 255; | |
2641 | if (!status) | |
2642 | break; | |
2643 | kwarnf0(KWF_PREFIX | KWF_NOERRNO, | |
2644 | TchvtDone, status); | |
2645 | } else | |
2646 | continue; | |
2647 | } | |
2648 | } | |
2649 | exit(0); | |
2650 | } | |
2651 | if (setsid() == -1) | |
2652 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, "chvt", "setsid"); | |
2549 | 2653 | if ((fd = binopen2(dv, O_RDWR)) < 0) { |
2550 | 2654 | sleep(1); |
2551 | if ((fd = binopen2(dv, O_RDWR)) < 0) { | |
2552 | errorf(Tchvt2, Topen, dv); | |
2553 | } | |
2554 | } | |
2555 | afree(cp, ATEMP); | |
2556 | if (go->optarg[0] != '!') { | |
2557 | switch (fork()) { | |
2558 | case -1: | |
2559 | errorf(Tchvt_failed, "fork"); | |
2560 | case 0: | |
2561 | break; | |
2562 | default: | |
2563 | exit(0); | |
2564 | } | |
2565 | } | |
2566 | if (setsid() == -1) | |
2567 | errorf(Tchvt_failed, "setsid"); | |
2568 | if (go->optarg[0] != '-') { | |
2655 | if ((fd = binopen2(dv, O_RDWR)) < 0) | |
2656 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_THREEMSG, | |
2657 | "chvt", dv, Topen); | |
2658 | } | |
2659 | if (!isdaemon) { | |
2660 | #ifdef TIOCSCTTY | |
2569 | 2661 | if (ioctl(fd, TIOCSCTTY, NULL) == -1) |
2570 | errorf(Tchvt_failed, "TIOCSCTTY"); | |
2662 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, | |
2663 | "chvt", "TIOCSCTTY"); | |
2664 | #endif | |
2665 | #if HAVE_TERMIOS_H | |
2571 | 2666 | if (tcflush(fd, TCIOFLUSH)) |
2572 | errorf(Tchvt_failed, "TCIOFLUSH"); | |
2667 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, | |
2668 | "chvt", "TCIOFLUSH"); | |
2669 | #else | |
2670 | if (ioctl(fd, TCFLSH, 2) == -1) | |
2671 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_TWOMSG, | |
2672 | "chvt", "TCFLSH"); | |
2673 | #endif | |
2573 | 2674 | } |
2574 | 2675 | ksh_dup2(fd, 0, false); |
2575 | 2676 | ksh_dup2(fd, 1, false); |
2576 | 2677 | ksh_dup2(fd, 2, false); |
2678 | #ifndef MKSH_DISABLE_REVOKE_WARNING | |
2679 | if (!isdaemon) { | |
2680 | ifrevwarn kwarnf(KWF_VERRNO | KWF_PREFIX | KWF_THREEMSG, | |
2681 | revwarn, "chvt", dv, | |
2682 | "can't revoke; new shell is potentially insecure"); | |
2683 | } | |
2684 | #endif | |
2577 | 2685 | if (fd > 2) |
2578 | 2686 | close(fd); |
2579 | 2687 | rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt))); |
2580 | 2688 | chvt_reinit(); |
2581 | } | |
2582 | #endif | |
2689 | /* signal parent the all OK */ | |
2690 | if (write(pfd[1], Tdot, 1) != 1) | |
2691 | kwarnf(KWF_PREFIX | KWF_TWOMSG, "chvt", "write"); | |
2692 | close(pfd[1]); | |
2693 | } | |
2583 | 2694 | |
2584 | 2695 | #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) |
2585 | 2696 | char * |
2640 | 2751 | errno = EINVAL; |
2641 | 2752 | #endif |
2642 | 2753 | if ((CLK_TCK = sysconf(_SC_CLK_TCK)) == -1L) |
2643 | internal_errorf("sysconf(_SC_CLK_TCK): %s", cstrerror(errno)); | |
2754 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG, | |
2755 | "sysconf(_SC_CLK_TCK)"); | |
2644 | 2756 | #endif |
2645 | 2757 | INVTCK(ru->ru_utime, u); |
2646 | 2758 | INVTCK(ru->ru_stime, s); |
2781 | 2893 | |
2782 | 2894 | #ifdef DEBUG |
2783 | 2895 | #undef strchr |
2896 | /* pre-initio() */ | |
2784 | 2897 | char * |
2785 | 2898 | ucstrchr(char *s, int c) |
2786 | 2899 | { |
0 | .\" $MirOS: src/bin/mksh/mksh.1,v 1.525+locale-tracking 2021/10/10 21:33:55 tg Exp $ | |
0 | .\" $MirOS: src/bin/mksh/mksh.1,v 1.532+locale-tracking 2022/01/28 10:28:19 tg Exp $ | |
1 | 1 | .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ |
2 | 2 | .\"- |
3 | 3 | .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
4 | 4 | .\" 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, |
5 | .\" 2018, 2019, 2020, 2021 | |
5 | .\" 2018, 2019, 2020, 2021, 2022 | |
6 | 6 | .\" mirabilos <m@mirbsd.org> |
7 | 7 | .\" |
8 | 8 | .\" Provided that these terms and disclaimer and all copyright notices |
63 | 63 | . ds en \(em |
64 | 64 | .\} |
65 | 65 | .ie n \{\ |
66 | . ds EM \ \*(en\ \& | |
66 | . ds EM \ \(em\ \& | |
67 | 67 | .\} |
68 | 68 | .el \{\ |
69 | 69 | . ds EM \f(TR\^\(em\^\fP |
83 | 83 | .\" with -mandoc, it might implement .Mx itself, but we want to |
84 | 84 | .\" use our own definition. And .Dd must come *first*, always. |
85 | 85 | .\" |
86 | .Dd $Mdocdate: October 10 2021 $ | |
86 | .Dd $Mdocdate: January 28 2022 $ | |
87 | 87 | .\" |
88 | 88 | .\" Check which macro package we use, and do other -mdoc setup. |
89 | 89 | .\" |
197 | 197 | .Nd MirBSD Korn shell |
198 | 198 | .Sh SYNOPSIS |
199 | 199 | .Nm |
200 | .Bk -words | |
201 | 200 | .Op Fl +abCefhiklmnprUuvXx |
202 | .Oo | |
203 | .Fl T Oo Ar \&! Oc Ns Ar tty | |
204 | \*(Ba | |
205 | .Ar \&\- | |
201 | .Op Fl +o Ar option | |
202 | .Oo Fl T Oo Ar !\& | |
203 | .Oc Ns Ar tty Ns \*(Ba Ns Ar \-\& | |
206 | 204 | .Oc |
205 | .Op Ar file Op Ar arg1 ... | |
206 | .Nm | |
207 | .Op Fl +abCefhiklmnprUuvXx | |
207 | 208 | .Op Fl +o Ar option |
208 | .Oo | |
209 | .Fl c Ar string \*(Ba | |
210 | .Fl s \*(Ba | |
211 | .Ar file | |
212 | .Op Ar argument ... | |
209 | .Oo Fl T Oo Ar !\& | |
210 | .Oc Ns Ar tty Ns \*(Ba Ns Ar \-\& | |
213 | 211 | .Oc |
214 | .Ek | |
212 | .Fl c | |
213 | .Ar cmd | |
214 | .Op Ar arg0 ... | |
215 | .Nm | |
216 | .Op Fl +abCefhiklmnprUuvXx | |
217 | .Op Fl +o Ar option | |
218 | .Oo Fl T Oo Ar !\& | |
219 | .Oc Ns Ar tty Ns \*(Ba Ns Ar \-\& | |
220 | .Oc | |
221 | .Fl s | |
222 | .Op Ar arg1 ... | |
215 | 223 | .Nm builtin-name |
216 | 224 | .Op Ar argument ... |
217 | 225 | .Sh DESCRIPTION |
218 | 226 | .Nm |
219 | 227 | is a command interpreter intended for both interactive and shell |
220 | 228 | script use. |
221 | Its command language is a superset of the | |
229 | Its command language is a superset of both | |
222 | 230 | .Xr sh C |
231 | and | |
232 | .Tn POSIX | |
223 | 233 | shell language and largely compatible to the original Korn shell. |
224 | 234 | At times, this manual page may give scripting advice; while it |
225 | 235 | sometimes does take portable shell scripting or various standards |
230 | 240 | Please refer to: |
231 | 241 | .Pa http://www.mirbsd.org/mksh\-faq.htm#sowhatismksh |
232 | 242 | .Ss Invocation |
233 | Most builtins can be called directly, for example if a link points from its | |
234 | name to the shell; not all make sense, have been tested or work at all though. | |
243 | Most builtins can be called directly, for example if a link or | |
244 | .Xr symlink 7 | |
245 | points to | |
246 | .Nm , | |
247 | or if | |
248 | .Va argv[0] | |
249 | is set correspondingly; | |
250 | this does not make sense for, or works properly with, all built-in utilities though. | |
235 | 251 | .Pp |
236 | 252 | The options are as follows: |
237 | .Bl -tag -width XcXstring | |
238 | .It Fl c Ar string | |
253 | .Bl -tag -width 2n | |
254 | .It Fl c | |
239 | 255 | .Nm |
240 | 256 | will execute the command(s) contained in |
241 | .Ar string . | |
257 | .Ar cmd , | |
258 | setting | |
259 | .Li $0 | |
260 | to | |
261 | .Ar arg0 | |
262 | .Pq if present , | |
263 | .Li $1 | |
264 | to the next argument, etc. | |
265 | If compiled with | |
266 | .Dv \-DMKSH_MIDNIGHTBSD01ASH_COMPAT | |
267 | and in | |
268 | .Fl o Ic sh | |
269 | mode, a | |
270 | .Dq Li \-\- | |
271 | argument directly following | |
272 | .Ar cmd | |
273 | is ignored for compatibility with the legacy | |
274 | .Fx | |
275 | .Nm sh ; | |
276 | this is deprecated and may go away in the future. | |
242 | 277 | .It Fl i |
243 | 278 | Interactive shell. |
244 | 279 | A shell that reads commands from standard input is |
269 | 304 | command below). |
270 | 305 | .It Fl l |
271 | 306 | Login shell. |
272 | If the name or basename the shell is called with (i.e. argv[0]) | |
273 | starts with | |
307 | If the name the shell is called as | |
308 | .Pq i.e.\& Va argv[0] | |
309 | or its basename begins with a dash | |
310 | .Pq hyphen-minus | |
274 | 311 | .Ql \- |
275 | or if this option is used, | |
276 | the shell is assumed to be a login shell; see | |
312 | or if this option is given, | |
313 | the shell is a | |
314 | .Dq login shell ; | |
315 | see | |
277 | 316 | .Sx Startup files |
278 | 317 | below. |
279 | 318 | .It Fl p |
280 | 319 | Privileged shell. |
281 | 320 | A shell is |
282 | 321 | .Dq privileged |
283 | if the real user ID or group ID does not match the | |
284 | effective user ID or group ID (see | |
322 | if the real user ID from | |
285 | 323 | .Xr getuid 2 |
286 | and | |
287 | .Xr getgid 2 ) . | |
324 | or group ID from | |
325 | .Xr getgid 2 | |
326 | does not match the effective user ID or group ID. | |
288 | 327 | Clearing the privileged option causes the shell to set |
289 | its effective user ID (group ID) to its initial real user ID (group ID). | |
328 | its effective user ID and group ID to its initial real user ID | |
329 | and group ID, respectively. | |
290 | 330 | For further implications, see |
331 | .Ic set Fl p | |
332 | and | |
291 | 333 | .Sx Startup files . |
292 | If the shell is privileged and this flag is not explicitly set, the | |
334 | If the shell is privileged and this flag is not set explicitly on invocation, | |
335 | nor during processing the startup files, the | |
293 | 336 | .Dq privileged |
294 | option is cleared automatically after processing the startup files. | |
337 | flag is cleared automatically afterwards. | |
295 | 338 | .It Fl r |
296 | 339 | Restricted shell. |
297 | 340 | A shell is |
298 | 341 | .Dq restricted |
299 | if the basename the shell is called with, after | |
300 | .Ql \- | |
301 | processing, starts with | |
342 | if the basename the shell is called with, after dash removal, begins with | |
302 | 343 | .Ql r |
303 | 344 | or if this option is used. |
304 | 345 | The following restrictions come into effect after the shell processes any |
308 | 349 | .Pp |
309 | 350 | .Bl -bullet -compact |
310 | 351 | .It |
311 | Command names cannot be specified with pathnames, absolute or relative, | |
312 | nor using the | |
352 | Command names cannot be specified with pathnames, either absolute or relative; | |
353 | the | |
313 | 354 | .Fl p |
314 | option of the | |
355 | flag of the | |
315 | 356 | .Ic command |
316 | built-in utility; the | |
357 | built-in utility is not usable. | |
358 | The | |
317 | 359 | .Ev ENV , |
318 | 360 | .Ev PATH |
319 | 361 | and |
322 | 364 | .It |
323 | 365 | The current location is fixed: the |
324 | 366 | .Ic cd |
325 | command and its alias | |
326 | .Ic chdir | |
327 | is disabled. | |
367 | builtin is disabled. | |
328 | 368 | .It |
329 | Redirections that create files can't be used (i.e.\& | |
369 | Redirections that create files, i.e.\& | |
330 | 370 | .Dq Li \*(Gt , |
331 | 371 | .Dq Li \*(Gt\*(Ba , |
332 | .Dq Li \*(Gt\*(Gt , | |
333 | .Dq Li \*(Lt\*(Gt ) , | |
334 | and the | |
372 | .Dq Li \*(Gt\*(Gt | |
373 | and | |
374 | .Dq Li \*(Lt\*(Gt , | |
375 | cannot be used, and the | |
335 | 376 | .Ev HISTFILE |
336 | 377 | parameter cannot be changed. |
337 | 378 | .El |
338 | 379 | .It Fl s |
339 | The shell reads commands from standard input; all non-option arguments | |
340 | are positional parameters. | |
341 | .It Fl T Ar name | |
380 | .Nm | |
381 | will read and execute commands from standard input; all non-option arguments | |
382 | are assigned to the positional parameters. | |
383 | .It Fl T Ar \- | |
384 | Detach from the controlling terminal, return immediately | |
385 | .Pq daemonise . | |
386 | .It Xo | |
387 | .Fl T Oo Ar !\& Oc Ns Ar name | |
388 | .Xc | |
342 | 389 | Spawn |
343 | 390 | .Nm |
344 | 391 | on the |
346 | 393 | device given. |
347 | 394 | The paths |
348 | 395 | .Ar name , |
349 | .Pa /dev/ttyC Ns Ar name | |
350 | and | |
351 | .Pa /dev/tty Ns Ar name | |
396 | .Li /dev/ttyC Ns Ar name | |
397 | and | |
398 | .Li /dev/tty Ns Ar name | |
352 | 399 | are attempted in order. |
353 | Unless | |
354 | .Ar name | |
355 | begins with an exclamation mark | |
356 | .Pq Ql \&! , | |
357 | this is done in a subshell and returns immediately. | |
358 | 400 | If |
359 | 401 | .Ar name |
360 | is a dash | |
361 | .Pq Ql \&\- , | |
362 | detach from controlling terminal (daemonise) instead. | |
402 | is prefixed with an exclamation mark | |
403 | .Pq Ql \&! , | |
404 | wait for the spawned shell to return, | |
405 | report its exit status or terminating signal visually. | |
406 | Exit 0 if spawned. | |
363 | 407 | .El |
364 | 408 | .Pp |
365 | In addition to the above, the options described in the | |
409 | In addition to the above, the flags | |
410 | .Op Fl +abCefhkmnUuvXx | |
411 | and | |
412 | .Op Fl +o Ar option , | |
413 | respectively for single-letter and long options, | |
414 | as described for the | |
366 | 415 | .Ic set |
367 | built-in command can also be used on the command line: | |
368 | both | |
369 | .Op Fl +abCefhkmnuvXx | |
370 | and | |
371 | .Op Fl +o Ar option | |
372 | can be used for single letter or long options, respectively. | |
416 | built-in utility, can be used on the command line. | |
373 | 417 | .Pp |
374 | 418 | If neither the |
375 | 419 | .Fl c |
376 | 420 | nor the |
377 | 421 | .Fl s |
378 | option is specified, the first non-option argument specifies the name | |
379 | of a file the shell reads commands from. | |
380 | If there are no non-option | |
381 | arguments, the shell reads commands from the standard input. | |
382 | The name of the shell (i.e. the contents of $0) | |
383 | is determined as follows: if the | |
384 | .Fl c | |
385 | option is used and there is a non-option argument, it is used as the name; | |
386 | if commands are being read from a file, the file is used as the name; | |
387 | otherwise, the name the shell was called with (i.e. argv[0]) is used. | |
388 | .Pp | |
389 | The exit status of the shell is 127 if the command file specified on the | |
390 | command line could not be opened, or non-zero if a fatal syntax error | |
391 | occurred during the execution of a script. | |
392 | In the absence of fatal errors, | |
393 | the exit status is that of the last command executed, or zero if no | |
394 | command is executed. | |
422 | options are specified, | |
423 | .Nm mksh | |
424 | will read and execute commands as if the | |
425 | .Fl s | |
426 | flag was passed iff the | |
427 | .Ar file | |
428 | argument is absent or | |
429 | .Dq Li \- ; | |
430 | otherwise, it sets $0 to | |
431 | .Ar file | |
432 | and reads commands from it. | |
433 | Further arguments | |
434 | .Ar arg1 ... | |
435 | are assigned to positional parameters. | |
436 | .Pp | |
437 | The exit status of the shell is 127 if the | |
438 | .Ar file | |
439 | specified on the command line could not be opened, | |
440 | or non-zero if a fatal error occurred during execution of the script. | |
441 | Otherwise, the errorlevel is that of the last command executed, | |
442 | 0 if no command was executed. | |
395 | 443 | .Ss Startup files |
396 | 444 | For the actual location of these files, see |
397 | 445 | .Sx FILES . |
1393 | 1441 | .Sx Arithmetic expressions |
1394 | 1442 | for a description of an expression. |
1395 | 1443 | .Ss Parameters |
1396 | Parameters are shell variables; they can be assigned values and their values | |
1444 | Parameters are shell variables; they can be assigned values, and their values | |
1397 | 1445 | can be accessed using a parameter substitution. |
1398 | 1446 | A parameter name is either one |
1399 | of the special single punctuation or digit character parameters described | |
1400 | below, or a letter followed by zero or more letters or digits | |
1401 | .Po | |
1402 | .Ql _ | |
1403 | counts as a letter | |
1404 | .Pc . | |
1405 | The latter form can be treated as arrays by appending an array index of the | |
1406 | form | |
1407 | .Op Ar expr | |
1408 | where | |
1447 | of the special single punctuation character or positional parameters described | |
1448 | below, or a letter followed by zero or more letters, digits or underscores. | |
1449 | The latter form can be accessed as array appending an index of the form | |
1450 | .Li [\& Ns Ar expr Ns Li ]\& | |
1451 | (in which | |
1409 | 1452 | .Ar expr |
1410 | is an arithmetic expression. | |
1411 | Array indices in | |
1412 | .Nm | |
1413 | are limited to the range 0 through 4294967295, inclusive. | |
1414 | That is, they are a 32-bit unsigned integer. | |
1453 | is an arithmetic expression). | |
1454 | Array indices range from 0 to 4294967295 | |
1455 | .Pq 2\*(ha32\-1 , | |
1456 | inclusive, in | |
1457 | .Nm . | |
1415 | 1458 | .Pp |
1416 | 1459 | Parameter substitutions take the form |
1417 | 1460 | .Pf $ Ns Ar name , |
1755 | 1798 | are evaluated as arithmetic expressions. |
1756 | 1799 | .Pp |
1757 | 1800 | .It Pf ${ Ns Ar name Ns @#} |
1758 | The hash (using the BAFH algorithm) of the expansion of | |
1801 | The hash (using the BAFH1-0 algorithm) of the expansion of | |
1759 | 1802 | .Ar name . |
1760 | 1803 | This is also used internally for the shell's hashtables. |
1761 | 1804 | .Pp |
1828 | 1871 | .It Ev 1 No .. Ev 9 |
1829 | 1872 | The first nine positional parameters that were supplied to the shell, function, |
1830 | 1873 | or script sourced using the |
1831 | .Dq Li \&. | |
1832 | built-in. | |
1874 | .Dq Li .\& | |
1875 | .Pq Dq dot | |
1876 | builtin. | |
1833 | 1877 | Further positional parameters may be accessed using |
1834 | 1878 | .Pf ${ Ar number Ns } . |
1835 | 1879 | .It Ev * |
3243 | 3287 | .It Ic Lbafh_add Op Ar string |
3244 | 3288 | .It Ic Lbafh_finish |
3245 | 3289 | .Pq Li dot.mkshrc No functions |
3246 | Implement the Better Avalance for the Jenkins Hash. | |
3290 | Implement the Better Avalance for Jenkins Hash | |
3291 | .Pq IV=1 . | |
3247 | 3292 | This is the same hash |
3248 | 3293 | .Nm |
3249 | 3294 | currently uses internally. |
4426 | 4471 | ROT13-encrypts/-decrypts stdin to stdout. |
4427 | 4472 | .Pp |
4428 | 4473 | .It Xo |
4429 | .Ic set Op Fl +abCefhiklmnprsUuvXx | |
4474 | .Ic set Op Fl +abCefhkmnpsUuvXx | |
4430 | 4475 | .Op Fl +o Ar option |
4431 | 4476 | .Op Fl +A Ar name |
4432 | 4477 | .Op Fl \- |
4433 | .Op Ar arg ... | |
4434 | .Xc | |
4478 | .Op Ar argument ... | |
4479 | .Xc | |
4480 | .It Xo | |
4481 | .Ic set Fl \- | |
4482 | .Op Ar argument ... | |
4483 | .Xc | |
4484 | .It Ic set Fl +o | |
4435 | 4485 | .Pq keeps assignments , special |
4436 | 4486 | The |
4437 | 4487 | .Ic set |
4451 | 4501 | .Fl + Ns Ar letter |
4452 | 4502 | syntax, where |
4453 | 4503 | .Ar letter |
4454 | is the option's single letter name (not all options have a single letter name). | |
4455 | The following table lists short (if extant) and long names | |
4504 | is the option's single letter name (not all options have both names). | |
4505 | The following table lists short and long names | |
4506 | .Pq if extant | |
4456 | 4507 | along with a description of what each option does: |
4457 | 4508 | .Bl -tag -width 3n |
4458 | 4509 | .It Fl A Ar name |
4459 | 4510 | Sets the elements of the array parameter |
4460 | 4511 | .Ar name |
4461 | 4512 | to |
4462 | .Ar arg ... | |
4513 | .Ar argument ... | |
4463 | 4514 | .Pp |
4464 | 4515 | If |
4465 | 4516 | .Fl A |
4492 | 4543 | Only used with job control |
4493 | 4544 | .Pq Fl m . |
4494 | 4545 | .It Fl C \*(Ba Fl o Ic noclobber |
4495 | Prevent \*(Gt redirection from overwriting existing files. | |
4496 | Instead, \*(Gt\*(Ba must be used to force an overwrite. | |
4546 | Prevent \*(Gt redirection from overwriting existing files; | |
4547 | .Ql \*(Gt\*(Ba | |
4548 | must be used to force overwriting instead. | |
4497 | 4549 | .Em Note: |
4498 | 4550 | This is not safe to use for creation of temporary files or |
4499 | 4551 | lockfiles due to a TOCTOU in a check allowing one to redirect output to |
4501 | 4553 | or other device files even in |
4502 | 4554 | .Ic noclobber |
4503 | 4555 | mode. |
4556 | .It Fl c | |
4557 | Commands are read from an argument string. | |
4558 | Can only be used when the shell is invoked. | |
4504 | 4559 | .It Fl e \*(Ba Fl o Ic errexit |
4505 | 4560 | Exit (after executing the |
4506 | 4561 | .Dv ERR |
4550 | 4605 | the effective UID (EUID) or GID (EGID), respectively. |
4551 | 4606 | See above for a description of what this means. |
4552 | 4607 | .Pp |
4553 | If the shell is privileged, setting this flag after startup files | |
4554 | have been processed let it go full setuid and/or setgid. | |
4555 | Clearing this flag makes the shell drop privileges. | |
4556 | Changing this flag resets the groups vector. | |
4608 | If the shell is privileged, setting this flag after startup file | |
4609 | processing let it go full setuid and/or setgid. | |
4610 | Clearing the flag makes the shell drop privileges. | |
4611 | Changing this flag resets the supplementary groups vector. | |
4557 | 4612 | .It Fl r \*(Ba Fl o Ic restricted |
4558 | 4613 | The shell is a restricted shell. |
4559 | 4614 | This option can only be used when the shell is invoked. |
4577 | 4632 | and internal string handling functions. |
4578 | 4633 | This flag is disabled by default, but can be enabled by setting it on the |
4579 | 4634 | shell command line; is enabled automatically for interactive shells if |
4580 | requested at compile time, your system supports | |
4581 | .Fn setlocale LC_CTYPE \&"" | |
4582 | and optionally | |
4583 | .Fn nl_langinfo CODESET , | |
4584 | or the | |
4635 | the POSIX locale uses the UTF-8 codeset or, lacking POSIX locales, the | |
4585 | 4636 | .Ev LC_ALL , |
4586 | 4637 | .Ev LC_CTYPE |
4587 | 4638 | or |
4588 | 4639 | .Ev LANG |
4589 | environment variables, | |
4590 | and at least one of these returns something that matches | |
4591 | .Dq UTF\-8 | |
4640 | environment variables either case-insensitively equal | |
4641 | .Dq Li UTF\-8 | |
4592 | 4642 | or |
4593 | .Dq utf8 | |
4594 | case-insensitively; for direct builtin calls depending on the | |
4595 | aforementioned environment variables. | |
4643 | .Dq Li utf8 | |
4644 | or have that as codeset modifier. | |
4596 | 4645 | .Pp |
4597 | 4646 | This build of the shell implements baroque locale tracking, that is, |
4598 | 4647 | .Ic set Fl +U |
4657 | 4706 | Do not kill running jobs with a |
4658 | 4707 | .Dv SIGHUP |
4659 | 4708 | signal when a login shell exits. |
4660 | Currently set by default, but this may | |
4661 | change in the future to be compatible with | |
4662 | .At | |
4663 | .Nm ksh , | |
4664 | which | |
4665 | doesn't have this option, but does send the | |
4666 | .Dv SIGHUP | |
4667 | signal. | |
4709 | Currently enabled by default. | |
4668 | 4710 | .It Fl o Ic nolog |
4669 | 4711 | No effect. |
4670 | 4712 | In the original Korn shell, this prevented function definitions from |
4765 | 4807 | .Pp |
4766 | 4808 | These options can also be used upon invocation of the shell. |
4767 | 4809 | The current set of |
4768 | options (with single letter names) can be found in the parameter | |
4810 | options with single letter names can be found in the parameter | |
4769 | 4811 | .Dq Li $\- . |
4770 | 4812 | .Ic set Fl o |
4771 | 4813 | with no option name will list all the options and whether each is on or off; |
4775 | 4817 | construct, which is an implementation detail; these commands are transient |
4776 | 4818 | .Pq only valid within the current shell session . |
4777 | 4819 | .Pp |
4778 | Remaining arguments, if any, are positional parameters and are assigned, in | |
4779 | order, to the positional parameters (i.e. $1, $2, etc.). | |
4820 | A lone | |
4821 | .Dq Li \- | |
4822 | clears both the | |
4823 | .Fl v | |
4824 | and | |
4825 | .Fl x | |
4826 | options (obsolete); it | |
4827 | .Pq or a lone Dq Li +\& | |
4828 | terminates option processing and is otherwise ignored. | |
4829 | .Pp | |
4830 | .No Remaining Ar argument Ns s , | |
4831 | if any, are assigned (in order, unless | |
4832 | .Fl s | |
4833 | is given) to | |
4834 | .Ar name | |
4835 | .Pq with Fl A | |
4836 | or the positional parameters | |
4837 | .Pq i.e.,\& $1, $2, etc . | |
4838 | .No Use Fl \- | |
4839 | if the first argument begins with plus or dash. | |
4780 | 4840 | If options end with |
4781 | 4841 | .Dq Li \-\- |
4782 | 4842 | and there are no remaining arguments, all positional parameters are cleared. |
4783 | For unknown historical reasons, a lone | |
4784 | .Dq Li \- | |
4785 | option is treated specially\*(EMit clears both the | |
4786 | .Fl v | |
4787 | and | |
4788 | .Fl x | |
4789 | options. | |
4790 | 4843 | If no options or arguments are given, the values of all parameters are printed |
4791 | 4844 | .Pq suitably quoted . |
4792 | 4845 | .Pp |
5942 | 5995 | builtin does not interpret backslashes and only supports the exact option |
5943 | 5996 | .Fl n , |
5944 | 5997 | unless built with |
5945 | .Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT . | |
5998 | .Dv \-DMKSH_MIDNIGHTBSD01ASH_COMPAT . | |
5946 | 5999 | .It |
5947 | 6000 | The substitution operations |
5948 | 6001 | .Sm off |
5981 | 6034 | eats a leading |
5982 | 6035 | .Fl \- |
5983 | 6036 | if built with |
5984 | .Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT . | |
6037 | .Dv \-DMKSH_MIDNIGHTBSD01ASH_COMPAT . | |
5985 | 6038 | .El |
5986 | 6039 | .Ss Interactive input line editing |
5987 | 6040 | The shell supports three modes of reading command lines from a |
7260 | 7313 | .Nm mksh |
7261 | 7314 | currently uses OPTU-16 internally, which is the same as UTF-8 and CESU-8 |
7262 | 7315 | with 0000..FFFD being valid codepoints; raw octets map to U+EF80..U+EFFF |
7263 | for releases before R60, U-00200080..U-002000FF for R60 onwards. | |
7316 | for releases before R60, U-10000080..U-100000FF for R60 onwards. | |
7264 | 7317 | .Em Future compatibility note : |
7265 | 7318 | there's work underway to use full 21-bit UTF-8 in mksh R60 or so. |
7266 | 7319 | .Sh BUGS |
0 | RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.28+locale-tracking 2021/10/03 23:38:13 tg Exp $ | |
0 | RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.32+locale-tracking 2022/01/25 06:07:32 tg Exp $ | |
1 | 1 | ToC: spelling |
2 | 2 | Title: How do you spell <tt>mksh</tt>? How do you pronounce it? |
3 | 3 | |
473 | 473 | the PUA; however, there is ambiguity if encountering those UTF-8-encoded, so |
474 | 474 | it changed for R60.) The <tt>Arithmetic expressions</tt> and <tt>CAVEATS</tt> |
475 | 475 | sections in mksh(1) contain more details about encoding and mapping.</p> |
476 | <p>As of R60, <tt>utf8-mode</tt> maps “raw octets” to U-00200080‥U-002000FF, | |
476 | <p>As of R60, <tt>utf8-mode</tt> maps “raw octets” to U-10000080‥U-100000FF, | |
477 | 477 | which is outside the UCS and therefore collision-free. There’s work underway |
478 | 478 | to make the shell support the full 21-bit UCS range for R60.</p> |
479 | 479 | <p class="boxhead">The following POSIX sh-compatible code toggles the |
483 | 483 | <div class="boxtext"> |
484 | 484 | <pre> |
485 | 485 | case ${KSH_VERSION:-} in |
486 | *MIRBSD KSH*|*LEGACY KSH*) | |
486 | *MIRBSD\ KSH*|*LEGACY\ KSH*) | |
487 | 487 | case ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} in |
488 | 488 | *[Uu][Tt][Ff]8*|*[Uu][Tt][Ff]-8*) set -U ;; |
489 | 489 | *) set +U ;; |
540 | 540 | … becomes…<br /> |
541 | 541 | <tt>[[ foo = *@(foo|bar)*baz* ]]</tt></p> |
542 | 542 | ---- |
543 | ToC: local-arrays | |
544 | Title: How can I do local arrays? | |
545 | ||
546 | <p class="boxhead">mksh supports function-local arrays with an “onion | |
547 | model” in which you can basically create (and unset) a local variable | |
548 | in a function, which may of course be array-typed:</p> | |
549 | <div class="boxtext"> | |
550 | <pre> | |
551 | function foo { | |
552 | a[1]=x # modifies the outer array | |
553 | echo ${a[*]} | |
554 | local a # makes a local variable… | |
555 | set -A a # … of type array… | |
556 | a[0]=yz # modifies the inner array | |
557 | echo ${a[*]} | |
558 | unset a # removes the local variable | |
559 | echo ${a[*]} | |
560 | a[2]=! # modifies the unveiled outer again | |
561 | echo ${a[*]} | |
562 | } | |
563 | set -A a -- 1 2 3 4 5 | |
564 | echo ${a[*]} # shows the outer array before… | |
565 | foo | |
566 | echo ${a[*]} # …and after the function ran | |
567 | </pre> | |
568 | </div><p class="boxfoot">This also works with <tt>a=(…)</tt> and | |
569 | in POSIX-style functions <tt>foo() { …; }</tt> (in mksh, although | |
570 | not in AT&T ksh which uses a different scope model) and with | |
571 | appending <tt>a+=(…)</tt> (and <tt>set -A a+ -- …</tt>), and even | |
572 | no-truncation array assignments <tt>set +A a -- …</tt> behave in | |
573 | a consistent manner.</p> | |
574 | ---- | |
543 | 575 | ToC: trim-vector |
544 | 576 | Title: ${@?}: bad substitution |
545 | 577 | |
552 | 584 | ToC: extensions-to-avoid |
553 | 585 | Title: Are there any extensions to avoid? |
554 | 586 | |
555 | <p>GNU <tt>bash</tt> supports “<tt>&></tt>” (and “|&”) to redirect | |
556 | both stdout and stderr in one go, but this breaks POSIX and Korn Shell syntax; | |
557 | use POSIX redirections instead:</p> | |
587 | <p>GNU <tt>bash</tt> supports “<tt>&></tt>” (and “<tt>|&</tt>”) | |
588 | to redirect both stdout and stderr in one go, but this breaks POSIX | |
589 | and Korn Shell syntax; use POSIX redirections instead:</p> | |
558 | 590 | <table border="1" cellpadding="3"> |
559 | 591 | <tr><td>GNU bash</td><td> |
560 | 592 | <tt>foo |& bar |& baz &>log</tt> |
26 | 26 | #include "sh.h" |
27 | 27 | |
28 | 28 | #include <klibc/startup.h> |
29 | #include <errno.h> | |
30 | #include <io.h> | |
31 | #include <unistd.h> | |
32 | 29 | #include <process.h> |
33 | 30 | |
34 | __RCSID("$MirOS: src/bin/mksh/os2.c,v 1.12 2021/07/30 02:58:07 tg Exp $"); | |
31 | __RCSID("$MirOS: src/bin/mksh/os2.c,v 1.16 2022/01/06 22:35:02 tg Exp $"); | |
35 | 32 | |
36 | 33 | struct a_s_arg { |
37 | 34 | union { |
67 | 64 | #define KLIBC_ARG_RESPONSE_EXCLUDE \ |
68 | 65 | (__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL) |
69 | 66 | |
67 | /* pre-initio() */ | |
70 | 68 | static void |
71 | 69 | response(int *argcp, const char ***argvp) |
72 | 70 | { |
105 | 103 | line = malloc(filesize + /* type */ 1 + /* NUL */ 1); |
106 | 104 | if (!line) { |
107 | 105 | exit_out_of_memory: |
108 | fputs("Out of memory while reading response file\n", stderr); | |
106 | SHIKATANAI write(2, | |
107 | SC("mksh: out of memory reading response file\n")); | |
109 | 108 | exit(255); |
110 | 109 | } |
111 | 110 | |
147 | 146 | free(line); |
148 | 147 | |
149 | 148 | if (ferror(f)) { |
150 | fputs("Cannot read response file\n", stderr); | |
149 | SHIKATANAI write(2, | |
150 | SC("mksh: can't read response file\n")); | |
151 | 151 | exit(255); |
152 | 152 | } |
153 | 153 | |
162 | 162 | *argvp = new_argv; |
163 | 163 | } |
164 | 164 | |
165 | /* pre-initio() */ | |
165 | 166 | static void |
166 | 167 | init_extlibpath(void) |
167 | 168 | { |
181 | 182 | } |
182 | 183 | } |
183 | 184 | |
185 | /* pre-initio() */ | |
184 | 186 | void |
185 | 187 | os2_init(int *argcp, const char ***argvp) |
186 | 188 | { |
513 | 515 | add_temp(const char *name) |
514 | 516 | { |
515 | 517 | struct temp *tp; |
516 | ||
517 | tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM); | |
518 | memcpy(tp->tffn, name, strlen(name) + 1); | |
518 | size_t len; | |
519 | ||
520 | len = strlen(name); | |
521 | tp = alloc(offsetof(struct temp, tffn[0]) + ++len, APERM); | |
522 | memcpy(tp->tffn, name, len); | |
519 | 523 | tp->next = templist; |
520 | 524 | templist = tp; |
521 | 525 | } |
10 | 10 | /*- |
11 | 11 | * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
12 | 12 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
13 | * 2019, 2020, 2021 | |
13 | * 2019, 2020, 2021, 2022 | |
14 | 14 | * mirabilos <m@mirbsd.org> |
15 | 15 | * |
16 | 16 | * Provided that these terms and disclaimer and all copyright notices |
29 | 29 | * of said person’s immediate fault when using the work as intended. |
30 | 30 | */ |
31 | 31 | |
32 | #define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.978 2022/01/28 10:28:20 tg Exp $" | |
33 | ||
32 | 34 | #ifdef MKSH_USE_AUTOCONF_H |
33 | 35 | /* things that “should” have been on the command line */ |
34 | 36 | #include "autoconf.h" |
35 | 37 | #undef MKSH_USE_AUTOCONF_H |
36 | #endif | |
37 | ||
38 | #ifdef __dietlibc__ | |
39 | /* XXX imake style */ | |
40 | #define _BSD_SOURCE /* live, BSD, live❣ */ | |
41 | 38 | #endif |
42 | 39 | |
43 | 40 | #if HAVE_SYS_PARAM_H |
125 | 122 | #ifdef MIRBSD_BOOTFLOPPY |
126 | 123 | #include <wchar.h> |
127 | 124 | #endif |
125 | #include "mbsdint.h" | |
128 | 126 | |
129 | 127 | /* monkey-patch known-bad offsetof versions to quell a warning */ |
130 | 128 | #if (defined(__KLIBC__) || defined(__dietlibc__)) && \ |
203 | 201 | #define __SCCSID(x) __IDSTRING(sccsid,x) |
204 | 202 | #endif |
205 | 203 | |
206 | #ifdef EXTERN | |
207 | __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.954 2021/10/11 22:35:23 tg Exp $"); | |
208 | #endif | |
209 | #define MKSH_VERSION "R59 2021/10/15" | |
210 | ||
211 | /* arithmetic types: C implementation */ | |
212 | #if !HAVE_CAN_INTTYPES | |
213 | #if !HAVE_CAN_UCBINTS | |
214 | typedef signed int int32_t; | |
215 | typedef unsigned int uint32_t; | |
216 | #else | |
217 | typedef u_int32_t uint32_t; | |
218 | #endif | |
219 | #endif | |
204 | #define MKSH_VERSION "R59 2022/01/27" | |
220 | 205 | |
221 | 206 | /* shell types */ |
222 | 207 | typedef unsigned char kby; /* byte */ |
223 | typedef unsigned int kui; /* wchar; kby or EOF; etc. */ | |
208 | typedef unsigned int kui; /* wchar; kby or EOF; ⊇k32; etc. */ | |
209 | /* main.c cta:int_32bit guaranteed */ | |
210 | typedef unsigned int k32; /* 32-bit arithmetic (hashes etc.) */ | |
211 | /* for use with/without 32-bit masking */ | |
224 | 212 | typedef unsigned long kul; /* long, arithmetic */ |
225 | 213 | typedef signed long ksl; /* signed long, arithmetic */ |
226 | 214 | |
227 | #define KBY(c) ((kby)(c)) /* byte, truncated if necessary */ | |
228 | #define KBI(c) ((kui)(kby)(c)) /* byte as u_int, truncated */ | |
215 | #define KBY(c) ((kby)(KUI(c) & 0xFFU)) /* byte, truncated if necessary */ | |
216 | #define KBI(c) ((kui)(KUI(c) & 0xFFU)) /* byte as u_int, truncated */ | |
229 | 217 | #define KUI(u) ((kui)(u)) /* int as u_int, not truncated */ |
218 | #define K32(u) ((k32)(KUI(u) & 0xFFFFFFFFU)) | |
230 | 219 | |
231 | 220 | /* arithmetic types: shell arithmetics */ |
221 | ||
222 | /* “cast” between unsigned / signed long */ | |
223 | #define KUL2SL(ul) mbiA_U2S(kul, ksl, LONG_MAX, ul) | |
224 | #define KSL2UL(sl) mbiA_S2U(kul, ksl, sl) | |
225 | ||
226 | /* convert between signed and sign variable plus magnitude */ | |
227 | #define KNEGUL2SL(n,ul) mbiA_VZM2S(kul, ksl, n, ul) | |
228 | /* n = sl < 0; //mbiA_S2VZ(sl); */ | |
229 | #define KSL2NEGUL(sl) mbiA_S2M(kul, ksl, sl) | |
230 | ||
231 | /* new arithmetics tbd, using mbiMA_* */ | |
232 | ||
233 | /* older arithmetics, to be replaced later */ | |
232 | 234 | #ifdef MKSH_LEGACY_MODE |
233 | 235 | /* |
234 | 236 | * POSIX demands these to be the C environment's long type |
241 | 243 | * integer wraparound, even across division and modulo, for |
242 | 244 | * any shell code using them, is guaranteed. |
243 | 245 | */ |
246 | #if HAVE_CAN_INTTYPES | |
244 | 247 | typedef int32_t mksh_ari_t; |
245 | 248 | typedef uint32_t mksh_uari_t; |
246 | #endif | |
249 | #else | |
250 | /* relies on compile-time asserts and CFLAGS to validate that */ | |
251 | typedef signed int mksh_ari_t; | |
252 | typedef unsigned int mksh_uari_t; | |
253 | #define INT32_MIN INT_MIN | |
254 | #define INT32_MAX INT_MAX | |
255 | #define UINT32_MAX UINT_MAX | |
256 | #endif | |
257 | #endif | |
258 | ||
259 | /* new arithmetics in preparation */ | |
247 | 260 | |
248 | 261 | /* boolean type (no <stdbool.h> deliberately) */ |
249 | 262 | typedef unsigned char mksh_bool; |
290 | 303 | #undef PRINT /* LynxOS defines that somewhere */ |
291 | 304 | #undef flock /* SCO UnixWare defines that to flock64 but ENOENT */ |
292 | 305 | |
306 | /* compiler shenanigans… */ | |
307 | #ifdef _FORTIFY_SOURCE | |
308 | /* workaround via https://stackoverflow.com/a/64407070/2171120 */ | |
309 | #define SHIKATANAI (void)! | |
310 | #else | |
311 | #define SHIKATANAI (void) | |
312 | #endif | |
313 | ||
293 | 314 | #ifndef MKSH_INCLUDES_ONLY |
294 | ||
295 | /* compile-time assertions */ | |
296 | #define cta(name,expr) struct cta_ ## name { char t[(expr) ? 1 : -1]; } | |
297 | ||
298 | /* counts the value bits when given inttype_MAX as argument */ | |
299 | #define IMAX_BITS(m) ((m) / ((m) % 255 + 1) / 255 % 255 * 8 + 7 - \ | |
300 | 86 / ((m) % 255 + 12)) | |
301 | /* taken from comp.lang.c by Hallvard B Furuseth */ | |
302 | 315 | |
303 | 316 | /* EBCDIC fun */ |
304 | 317 | |
310 | 323 | # endif |
311 | 324 | # if __CHARSET_LIB && defined(MKSH_EBCDIC) |
312 | 325 | # error "Please compile without -E argument to Build.sh for ASCII!" |
313 | # endif | |
314 | # if __CHARSET_LIB && !defined(_ENHANCED_ASCII_EXT) | |
315 | /* go all-out on ASCII */ | |
316 | # define _ENHANCED_ASCII_EXT 0xFFFFFFFF | |
317 | 326 | # endif |
318 | 327 | #endif |
319 | 328 | |
382 | 391 | #endif |
383 | 392 | |
384 | 393 | #ifndef SIZE_MAX |
385 | #ifdef SIZE_T_MAX | |
386 | #define SIZE_MAX SIZE_T_MAX | |
387 | #else | |
388 | 394 | #define SIZE_MAX ((size_t)-1) |
389 | 395 | #endif |
396 | ||
397 | #ifndef PTRDIFF_MAX | |
398 | #if (sizeof(size_t) == sizeof(ptrdiff_t)) && ((SIZE_MAX) == ((size_t)-1)) | |
399 | #define PTRDIFF_MAX ((ptrdiff_t)(SIZE_MAX >> 1)) | |
400 | #endif | |
401 | #endif | |
402 | ||
403 | /* limit maximum object size so we can express pointer differences w/o UB */ | |
404 | #if SIZE_MAX <= PTRDIFF_MAX | |
405 | #define mksh_MAXSZ SIZE_MAX | |
406 | #else | |
407 | #define mksh_MAXSZ ((size_t)PTRDIFF_MAX) | |
390 | 408 | #endif |
391 | 409 | |
392 | 410 | /* if this breaks, see sh.h,v 1.954 commit message and diff */ |
397 | 415 | #define KSH_ISVDIS(x,d) ((x) == _POSIX_VDISABLE ? (d) : KBI(x)) |
398 | 416 | #define KSH_DOVDIS(x) (x) = _POSIX_VDISABLE |
399 | 417 | |
418 | #ifndef S_ISFIFO | |
419 | #define S_ISFIFO(m) ((m & 0170000) == 0010000) | |
420 | #endif | |
400 | 421 | #ifndef S_ISCHR |
401 | 422 | #define S_ISCHR(m) ((m & 0170000) == 0020000) |
402 | 423 | #endif |
469 | 490 | #define ksh_sigrestore(s,svp) ksh_sigset((s), *(svp), NULL) |
470 | 491 | #endif |
471 | 492 | |
493 | #if HAVE_SIGDESCR_NP | |
494 | #define ksh_sigmess(nr) sigdescr_np(nr) | |
495 | #elif HAVE_SYS_SIGLIST | |
496 | #if !HAVE_SYS_SIGLIST_DECL | |
497 | extern const char * const sys_siglist[]; | |
498 | #endif | |
499 | #define ksh_sigmess(nr) sys_siglist[nr] | |
500 | #elif HAVE_STRSIGNAL | |
501 | #define ksh_sigmess(nr) strsignal(nr) | |
502 | #else | |
503 | #define ksh_sigmess(nr) NULL | |
504 | #endif | |
505 | #define ksh_sigmessf(mess) (!(mess) || !*(mess)) | |
506 | ||
472 | 507 | /* contract: masks the signal, may restart, not oneshot */ |
473 | 508 | void ksh_sigset(int, sig_t, ksh_sigsaved *); |
474 | 509 | |
521 | 556 | extern int revoke(const char *); |
522 | 557 | #endif |
523 | 558 | |
559 | #ifndef EOVERFLOW | |
560 | #define EOVERFLOW ERANGE | |
561 | #endif | |
562 | ||
524 | 563 | #if defined(DEBUG) || !HAVE_STRERROR |
525 | 564 | #undef strerror |
526 | 565 | #define strerror /* poisoned */ dontuse_strerror |
527 | #define cstrerror /* replaced */ cstrerror | |
528 | 566 | extern const char *cstrerror(int); |
529 | 567 | #else |
530 | 568 | #define cstrerror(errnum) ((const char *)strerror(errnum)) |
705 | 743 | |
706 | 744 | /* use this ipv strchr(s, 0) but no side effects in s! */ |
707 | 745 | #define strnul(s) ((s) + strlen((const void *)s)) |
746 | ||
747 | /* inspired by jupp, where they are in lowercase though */ | |
748 | #define SC(s) (s), (sizeof(s) / sizeof(s[0]) - 1U) | |
749 | #define SZ(s) (s), strlen(s) | |
708 | 750 | |
709 | 751 | #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) |
710 | 752 | #define strdupx(d,s,ap) do { \ |
957 | 999 | /* note that i MUST NOT be zero */ |
958 | 1000 | #define LRETURN 1 /* return statement */ |
959 | 1001 | #define LEXIT 2 /* exit statement */ |
960 | #define LERROR 3 /* errorf() called */ | |
1002 | #define LERROR 3 /* kerrf() called */ | |
961 | 1003 | #define LERREXT 4 /* set -e caused */ |
962 | 1004 | #define LINTR 5 /* ^C noticed */ |
963 | 1005 | #define LBREAK 6 /* break statement */ |
1000 | 1042 | #define kshppid rndsetupstate.kshppid_v |
1001 | 1043 | |
1002 | 1044 | /* option processing */ |
1003 | #define OF_CMDLINE 0x01 /* command line */ | |
1004 | #define OF_SET 0x02 /* set builtin */ | |
1005 | #define OF_SPECIAL 0x04 /* a special variable changing */ | |
1006 | #define OF_INTERNAL 0x08 /* set internally by shell */ | |
1007 | #define OF_FIRSTTIME 0x10 /* as early as possible, once */ | |
1008 | #define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL) | |
1045 | #define OF_CMDLINE 0x01U /* command line */ | |
1046 | #define OF_SET 0x02U /* set builtin */ | |
1047 | #define OF_INTERNAL 0x04U /* set internally by shell */ | |
1048 | #define OF_FIRSTTIME 0x08U /* as early as possible, once */ | |
1049 | #define OF_ANY (OF_CMDLINE | OF_SET | OF_INTERNAL) | |
1009 | 1050 | |
1010 | 1051 | /* null value for variable; comparison pointer for unset */ |
1011 | 1052 | EXTERN char null[] E_INIT(""); |
1030 | 1071 | |
1031 | 1072 | #ifndef HAVE_STRING_POOLING /* helpers for pooled strings */ |
1032 | 1073 | #define T1space (Treal_sp2 + 5) |
1033 | #define Tcolsp (Tf_sD_ + 2) | |
1034 | 1074 | #define TC_IFSWS (TinitIFS + 4) |
1035 | 1075 | EXTERN const char TinitIFS[] E_INIT("IFS= \t\n"); |
1036 | EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_"); | |
1076 | EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} \"$_\""); | |
1037 | 1077 | #define Tspdollaru (TFCEDIT_dollaru + 18) |
1038 | 1078 | EXTERN const char Tsgdot[] E_INIT("*=."); |
1039 | 1079 | EXTERN const char Taugo[] E_INIT("augo"); |
1045 | 1085 | EXTERN const char Tbg[] E_INIT("bg"); |
1046 | 1086 | EXTERN const char Tbad_buf[] E_INIT("%s: buf %zX len %zd"); |
1047 | 1087 | EXTERN const char Tbad_flags[] E_INIT("%s: flags 0x%08X"); |
1048 | EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'"); | |
1049 | #define Tbad_sig_s (Tbad_sig_ss + 4) | |
1088 | EXTERN const char Tbad_sig[] E_INIT("bad signal"); | |
1050 | 1089 | EXTERN const char Tsgbreak[] E_INIT("*=break"); |
1051 | 1090 | #define Tbreak (Tsgbreak + 2) |
1052 | 1091 | EXTERN const char T__builtin[] E_INIT("-\\builtin"); |
1053 | 1092 | #define T_builtin (T__builtin + 1) |
1054 | 1093 | #define Tbuiltin (T__builtin + 2) |
1055 | EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes"); | |
1056 | 1094 | EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd"); |
1057 | 1095 | EXTERN const char Tcant_filesub[] E_INIT("can't open $(<...) file"); |
1058 | 1096 | #define Tcd (Tcant_cd + 25) |
1059 | EXTERN const char Tchvt2[] E_INIT("chvt: %s: %s"); | |
1060 | EXTERN const char Tchvt_failed[] E_INIT("chvt: %s failed"); | |
1061 | EXTERN const char Tcloexec_failed[] E_INIT("failed to %s close-on-exec flag for fd#%d: %s"); | |
1097 | EXTERN const char Tcloexec_failed[] E_INIT("failed to %s close-on-exec flag for fd#%d"); | |
1062 | 1098 | #define T_command (T_funny_command + 9) |
1063 | 1099 | #define Tcommand (T_funny_command + 10) |
1064 | 1100 | EXTERN const char Tsgcontinue[] E_INIT("*=continue"); |
1065 | 1101 | #define Tcontinue (Tsgcontinue + 2) |
1066 | 1102 | EXTERN const char Tcreate[] E_INIT("create"); |
1103 | EXTERN const char TchvtDone[] E_INIT("chvt: Done (%d)"); | |
1104 | #define TDone (TchvtDone + 6) | |
1067 | 1105 | EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected"); |
1068 | 1106 | EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL"); |
1069 | 1107 | EXTERN const char TENV[] E_INIT("ENV"); |
1070 | 1108 | EXTERN const char Tdsgexport[] E_INIT("^*=export"); |
1071 | 1109 | #define Texport (Tdsgexport + 3) |
1072 | #ifdef __OS2__ | |
1073 | EXTERN const char Textproc[] E_INIT("extproc"); | |
1074 | #endif | |
1075 | 1110 | EXTERN const char Tfalse[] E_INIT("false"); |
1076 | 1111 | EXTERN const char Tfg[] E_INIT("fg"); |
1077 | 1112 | EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution"); |
1078 | 1113 | #define Tfile (Tcant_filesub + 19) |
1114 | EXTERN const char Tyankfirst[] E_INIT("\nyank something first"); | |
1115 | #define Tfirst (Tyankfirst + 16) | |
1079 | 1116 | EXTERN const char TFPATH[] E_INIT("FPATH"); |
1080 | 1117 | EXTERN const char T_function[] E_INIT(" function"); |
1081 | 1118 | #define Tfunction (T_function + 1) |
1082 | 1119 | EXTERN const char T_funny_command[] E_INIT("funny $()-command"); |
1083 | 1120 | EXTERN const char Tgetopts[] E_INIT("getopts"); |
1121 | #define Tgetrusage (Ttime_getrusage + 6) | |
1122 | EXTERN const char Ttime_getrusage[] E_INIT("time: getrusage"); | |
1084 | 1123 | #define Thistory (Tnot_in_history + 7) |
1085 | 1124 | EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented"); |
1086 | 1125 | EXTERN const char Tinvname[] E_INIT("%s: invalid %s name"); |
1088 | 1127 | EXTERN const char Tjob_not_started[] E_INIT("job not started"); |
1089 | 1128 | EXTERN const char Tmksh[] E_INIT("mksh"); |
1090 | 1129 | #define Tname (Tinvname + 15) |
1130 | EXTERN const char Tnil[] E_INIT("(null)"); | |
1091 | 1131 | EXTERN const char Tno_args[] E_INIT("missing argument"); |
1092 | 1132 | EXTERN const char Tno_OLDPWD[] E_INIT("no OLDPWD"); |
1093 | EXTERN const char Tnot_ident[] E_INIT("is not an identifier"); | |
1133 | EXTERN const char Tnot_ident[] E_INIT("not an identifier"); | |
1094 | 1134 | EXTERN const char Tnot_in_history[] E_INIT("not in history"); |
1095 | EXTERN const char Tnot_found_s[] E_INIT("%s not found"); | |
1096 | #define Tnot_found (Tnot_found_s + 3) | |
1135 | #define Tnot_found (Tinacc_not_found + 16) | |
1136 | #define Tsp_not_found (Tinacc_not_found + 15) | |
1137 | EXTERN const char Tinacc_not_found[] E_INIT("inaccessible or not found"); | |
1097 | 1138 | #define Tnot_started (Tjob_not_started + 4) |
1098 | 1139 | #define TOLDPWD (Tno_OLDPWD + 3) |
1099 | 1140 | EXTERN const char Topen[] E_INIT("open"); |
1108 | 1149 | #define Tread (Tshf_read + 4) |
1109 | 1150 | EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly"); |
1110 | 1151 | #define Treadonly (Tdsgreadonly + 3) |
1152 | EXTERN const char Tread_only[] E_INIT("read-only"); | |
1111 | 1153 | EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection"); |
1112 | 1154 | #define Tredirection (Tredirection_dup + 19) |
1113 | 1155 | #define Treal_sp1 (Treal_sp2 + 1) |
1115 | 1157 | EXTERN const char TREPLY[] E_INIT("REPLY"); |
1116 | 1158 | EXTERN const char Treq_arg[] E_INIT("requires an argument"); |
1117 | 1159 | EXTERN const char Tselect[] E_INIT("select"); |
1118 | #define Tset (Tf_parm + 18) | |
1160 | #define Tset (Tf_parm + 14) | |
1119 | 1161 | #define Tset_po (T_set_po + 1) |
1120 | 1162 | EXTERN const char T_set_po[] E_INIT(" set +o"); |
1121 | 1163 | EXTERN const char Tsghset[] E_INIT("*=#set"); |
1131 | 1173 | EXTERN const char Tsynerr[] E_INIT("syntax error"); |
1132 | 1174 | EXTERN const char Ttime[] E_INIT("time"); |
1133 | 1175 | EXTERN const char Ttoo_many_args[] E_INIT("too many arguments"); |
1134 | EXTERN const char Ttoo_many_files[] E_INIT("too many open files (%d -> %d): %s"); | |
1176 | EXTERN const char Ttoo_many_files[] E_INIT("too many open files (%d -> %d)"); | |
1135 | 1177 | EXTERN const char Ttrue[] E_INIT("true"); |
1136 | 1178 | EXTERN const char Tdgtypeset[] E_INIT("^=typeset"); |
1137 | 1179 | #define Ttypeset (Tdgtypeset + 2) |
1148 | 1190 | EXTERN const char Tf__S[] E_INIT(" %S"); |
1149 | 1191 | #define Tf__d (Tunexpected_type + 22) |
1150 | 1192 | #define Tf__sN (Tf_s_s_sN + 5) |
1193 | EXTERN const char Tf_s_T[] E_INIT("%s %T"); | |
1151 | 1194 | #define Tf_T (Tf_s_T + 3) |
1152 | 1195 | EXTERN const char Tf_dN[] E_INIT("%d\n"); |
1153 | 1196 | EXTERN const char Tf_s_[] E_INIT("%s "); |
1154 | EXTERN const char Tf_s_T[] E_INIT("%s %T"); | |
1155 | 1197 | EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n"); |
1156 | #define Tf_s_s (Tf_sD_s_s + 4) | |
1157 | 1198 | #define Tf__s_s (Tf_sD_s_s + 3) |
1158 | #define Tf_s_sD_s (Tf_cant_ss_s + 6) | |
1159 | #define Tf_optdcs (Tf_optfoo + 4) | |
1160 | EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s"); | |
1161 | EXTERN const char Tf_sD_[] E_INIT("%s: "); | |
1162 | EXTERN const char Tf_parm[] E_INIT("%s: parameter not set"); | |
1163 | EXTERN const char Tf_coproc[] E_INIT("-p: %s"); | |
1199 | EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s"); | |
1200 | EXTERN const char Tf_parm[] E_INIT("parameter not set"); | |
1164 | 1201 | EXTERN const char Tf_cant_s[] E_INIT("%s: can't %s"); |
1165 | EXTERN const char Tf_cant_ss_s[] E_INIT("can't %s %s: %s"); | |
1166 | 1202 | EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed"); |
1167 | #if HAVE_MKNOD | |
1168 | EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'"); | |
1169 | #endif | |
1170 | 1203 | EXTERN const char Tf_S_[] E_INIT("%S "); |
1171 | 1204 | #define Tf_S (Tf__S + 1) |
1172 | #define Tf_lu (Tf_toolarge + 17) | |
1173 | EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu"); | |
1174 | EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s"); | |
1205 | EXTERN const char Tf_sSQlu[] E_INIT("%s[%lu]"); | |
1206 | #define Tf_SQlu (Tf_sSQlu + 2) | |
1207 | #define Tf_lu (Tf_toolarge + 14) | |
1208 | EXTERN const char Tf_toolarge[] E_INIT("%s too large: %lu"); | |
1209 | EXTERN const char Tf_ldfailed[] E_INIT("%s tcsetpgrp(%d, %ld)"); | |
1175 | 1210 | EXTERN const char Tf_toomany[] E_INIT("too many %ss"); |
1176 | 1211 | EXTERN const char Tf_sd[] E_INIT("%s %d"); |
1177 | #define Tf_s (Tcloexec_failed + 43) | |
1212 | #define Tf_s (Tf_temp + 24) | |
1178 | 1213 | EXTERN const char Tft_end[] E_INIT("%;"); |
1179 | EXTERN const char Tft_R[] E_INIT("%R"); | |
1180 | #define Tf_d (Tunexpected_type + 23) | |
1214 | #define Tft_R (Tft_s_R + 3) | |
1215 | EXTERN const char Tft_s_R[] E_INIT("%s %R"); | |
1216 | #define Tf_d (Tcloexec_failed + 39) | |
1181 | 1217 | EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'"); |
1182 | EXTERN const char Tf_ro[] E_INIT("read-only: %s"); | |
1183 | EXTERN const char Tf_temp[] E_INIT("can't %s temporary file %s: %s"); | |
1184 | EXTERN const char Tf_ssfaileds[] E_INIT("%s: %s failed: %s"); | |
1185 | EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s"); | |
1218 | EXTERN const char Tf_temp[] E_INIT("can't %s temporary file %s"); | |
1219 | EXTERN const char Tf_ssfailed[] E_INIT("%s: %s failed"); | |
1186 | 1220 | EXTERN const char Tf__c_[] E_INIT("-%c "); |
1187 | 1221 | EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s"); |
1188 | 1222 | #define Tf_sN (Tf_s_s_sN + 6) |
1189 | #define Tf_sD_s (Tf_temp + 24) | |
1190 | EXTERN const char T_devtty[] E_INIT("/dev/tty"); | |
1223 | #define Tf_sD_s (Tf_s_sD_s + 3) | |
1191 | 1224 | #else /* helpers for string pooling */ |
1192 | 1225 | #define T1space " " |
1193 | #define Tcolsp ": " | |
1194 | 1226 | #define TC_IFSWS " \t\n" |
1195 | 1227 | #define TinitIFS "IFS= \t\n" |
1196 | #define TFCEDIT_dollaru "${FCEDIT:-/bin/ed} $_" | |
1197 | #define Tspdollaru " $_" | |
1228 | #define TFCEDIT_dollaru "${FCEDIT:-/bin/ed} \"$_\"" | |
1229 | #define Tspdollaru " \"$_\"" | |
1198 | 1230 | #define Tsgdot "*=." |
1199 | 1231 | #define Taugo "augo" |
1200 | 1232 | #define Tbracket "[" |
1205 | 1237 | #define Tbg "bg" |
1206 | 1238 | #define Tbad_buf "%s: buf %zX len %zd" |
1207 | 1239 | #define Tbad_flags "%s: flags 0x%08X" |
1208 | #define Tbad_sig_ss "%s: bad signal '%s'" | |
1209 | #define Tbad_sig_s "bad signal '%s'" | |
1240 | #define Tbad_sig "bad signal" | |
1210 | 1241 | #define Tsgbreak "*=break" |
1211 | 1242 | #define Tbreak "break" |
1212 | 1243 | #define T__builtin "-\\builtin" |
1213 | 1244 | #define T_builtin "\\builtin" |
1214 | 1245 | #define Tbuiltin "builtin" |
1215 | #define Toomem "can't allocate %zu data bytes" | |
1216 | 1246 | #define Tcant_cd "restricted shell - can't cd" |
1217 | 1247 | #define Tcant_filesub "can't open $(<...) file" |
1218 | 1248 | #define Tcd "cd" |
1219 | #define Tchvt2 "chvt: %s: %s" | |
1220 | #define Tchvt_failed "chvt: %s failed" | |
1221 | #define Tcloexec_failed "failed to %s close-on-exec flag for fd#%d: %s" | |
1249 | #define Tcloexec_failed "failed to %s close-on-exec flag for fd#%d" | |
1222 | 1250 | #define T_command "-command" |
1223 | 1251 | #define Tcommand "command" |
1224 | 1252 | #define Tsgcontinue "*=continue" |
1225 | 1253 | #define Tcontinue "continue" |
1226 | 1254 | #define Tcreate "create" |
1255 | #define TchvtDone "chvt: Done (%d)" | |
1256 | #define TDone "Done (%d)" | |
1227 | 1257 | #define TELIF_unexpected "TELIF unexpected" |
1228 | 1258 | #define TEXECSHELL "EXECSHELL" |
1229 | 1259 | #define TENV "ENV" |
1230 | 1260 | #define Tdsgexport "^*=export" |
1231 | 1261 | #define Texport "export" |
1232 | #ifdef __OS2__ | |
1233 | #define Textproc "extproc" | |
1234 | #endif | |
1235 | 1262 | #define Tfalse "false" |
1236 | 1263 | #define Tfg "fg" |
1237 | 1264 | #define Tfg_badsubst "fileglob: bad substitution" |
1238 | 1265 | #define Tfile "file" |
1266 | #define Tyankfirst "\nyank something first" | |
1267 | #define Tfirst "first" | |
1239 | 1268 | #define TFPATH "FPATH" |
1240 | 1269 | #define T_function " function" |
1241 | 1270 | #define Tfunction "function" |
1242 | 1271 | #define T_funny_command "funny $()-command" |
1243 | 1272 | #define Tgetopts "getopts" |
1273 | #define Tgetrusage "getrusage" | |
1274 | #define Ttime_getrusage "time: getrusage" | |
1244 | 1275 | #define Thistory "history" |
1245 | 1276 | #define Tintovfl "integer overflow %zu %c %zu prevented" |
1246 | 1277 | #define Tinvname "%s: invalid %s name" |
1248 | 1279 | #define Tjob_not_started "job not started" |
1249 | 1280 | #define Tmksh "mksh" |
1250 | 1281 | #define Tname "name" |
1282 | #define Tnil "(null)" | |
1251 | 1283 | #define Tno_args "missing argument" |
1252 | 1284 | #define Tno_OLDPWD "no OLDPWD" |
1253 | #define Tnot_ident "is not an identifier" | |
1285 | #define Tnot_ident "not an identifier" | |
1254 | 1286 | #define Tnot_in_history "not in history" |
1255 | #define Tnot_found_s "%s not found" | |
1256 | 1287 | #define Tnot_found "not found" |
1288 | #define Tsp_not_found " not found" | |
1289 | #define Tinacc_not_found "inaccessible or not found" | |
1257 | 1290 | #define Tnot_started "not started" |
1258 | 1291 | #define TOLDPWD "OLDPWD" |
1259 | 1292 | #define Topen "open" |
1268 | 1301 | #define Tread "read" |
1269 | 1302 | #define Tdsgreadonly "^*=readonly" |
1270 | 1303 | #define Treadonly "readonly" |
1304 | #define Tread_only "read-only" | |
1271 | 1305 | #define Tredirection_dup "can't finish (dup) redirection" |
1272 | 1306 | #define Tredirection "redirection" |
1273 | 1307 | #define Treal_sp1 "real " |
1291 | 1325 | #define Tsynerr "syntax error" |
1292 | 1326 | #define Ttime "time" |
1293 | 1327 | #define Ttoo_many_args "too many arguments" |
1294 | #define Ttoo_many_files "too many open files (%d -> %d): %s" | |
1328 | #define Ttoo_many_files "too many open files (%d -> %d)" | |
1295 | 1329 | #define Ttrue "true" |
1296 | 1330 | #define Tdgtypeset "^=typeset" |
1297 | 1331 | #define Ttypeset "typeset" |
1308 | 1342 | #define Tf__S " %S" |
1309 | 1343 | #define Tf__d " %d" |
1310 | 1344 | #define Tf__sN " %s\n" |
1345 | #define Tf_s_T "%s %T" | |
1311 | 1346 | #define Tf_T "%T" |
1312 | 1347 | #define Tf_dN "%d\n" |
1313 | 1348 | #define Tf_s_ "%s " |
1314 | #define Tf_s_T "%s %T" | |
1315 | 1349 | #define Tf_s_s_sN "%s %s %s\n" |
1316 | #define Tf_s_s "%s %s" | |
1317 | 1350 | #define Tf__s_s " %s %s" |
1318 | 1351 | #define Tf_s_sD_s "%s %s: %s" |
1319 | #define Tf_optdcs "-%c: %s" | |
1320 | #define Tf_optfoo "%s%s-%c: %s" | |
1321 | #define Tf_sD_ "%s: " | |
1322 | #define Tf_parm "%s: parameter not set" | |
1323 | #define Tf_coproc "-p: %s" | |
1352 | #define Tf_parm "parameter not set" | |
1324 | 1353 | #define Tf_cant_s "%s: can't %s" |
1325 | #define Tf_cant_ss_s "can't %s %s: %s" | |
1326 | 1354 | #define Tf_heredoc "here document '%s' unclosed" |
1327 | #if HAVE_MKNOD | |
1328 | #define Tf_nonnum "non-numeric %s %s '%s'" | |
1329 | #endif | |
1330 | 1355 | #define Tf_S_ "%S " |
1331 | 1356 | #define Tf_S "%S" |
1357 | #define Tf_sSQlu "%s[%lu]" | |
1358 | #define Tf_SQlu "[%lu]" | |
1332 | 1359 | #define Tf_lu "%lu" |
1333 | #define Tf_toolarge "%s %s too large: %lu" | |
1334 | #define Tf_ldfailed "%s %s(%d, %ld) failed: %s" | |
1360 | #define Tf_toolarge "%s too large: %lu" | |
1361 | #define Tf_ldfailed "%s tcsetpgrp(%d, %ld)" | |
1335 | 1362 | #define Tf_toomany "too many %ss" |
1336 | 1363 | #define Tf_sd "%s %d" |
1337 | 1364 | #define Tf_s "%s" |
1338 | 1365 | #define Tft_end "%;" |
1339 | 1366 | #define Tft_R "%R" |
1367 | #define Tft_s_R "%s %R" | |
1340 | 1368 | #define Tf_d "%d" |
1341 | 1369 | #define Tf_sD_s_qs "%s: %s '%s'" |
1342 | #define Tf_ro "read-only: %s" | |
1343 | #define Tf_temp "can't %s temporary file %s: %s" | |
1344 | #define Tf_ssfaileds "%s: %s failed: %s" | |
1345 | #define Tf_sD_sD_s "%s: %s: %s" | |
1370 | #define Tf_temp "can't %s temporary file %s" | |
1371 | #define Tf_ssfailed "%s: %s failed" | |
1346 | 1372 | #define Tf__c_ "-%c " |
1347 | 1373 | #define Tf_sD_s_s "%s: %s %s" |
1348 | 1374 | #define Tf_sN "%s\n" |
1349 | 1375 | #define Tf_sD_s "%s: %s" |
1350 | #define T_devtty "/dev/tty" | |
1351 | 1376 | #endif /* end of string pooling */ |
1377 | ||
1378 | #ifdef __OS2__ | |
1379 | EXTERN const char Textproc[] E_INIT("extproc"); | |
1380 | #endif | |
1352 | 1381 | |
1353 | 1382 | typedef kby Temp_type; |
1354 | 1383 | /* expanded heredoc */ |
1379 | 1408 | #ifdef DF |
1380 | 1409 | #define shl_dbg (&shf_iob[3]) /* for DF() */ |
1381 | 1410 | #endif |
1411 | EXTERN bool initio_done; /* shl_*out:true/1, shl_dbg:2 */ | |
1382 | 1412 | EXTERN bool shl_stdout_ok; |
1383 | 1413 | |
1384 | 1414 | /* |
1489 | 1519 | /* out of space, but one for *@ would make sense, possibly others */ |
1490 | 1520 | |
1491 | 1521 | /* compile-time initialised, ASCII only */ |
1492 | extern const uint32_t tpl_ctypes[128]; | |
1522 | extern const kui tpl_ctypes[128]; | |
1493 | 1523 | /* run-time, contains C_IFS as well, full 2⁸ octet range */ |
1494 | EXTERN uint32_t ksh_ctypes[256]; | |
1524 | EXTERN kui ksh_ctypes[256]; | |
1495 | 1525 | /* first octet of $IFS, for concatenating "$*" */ |
1496 | 1526 | EXTERN char ifs0; |
1497 | 1527 | |
1588 | 1618 | !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C) |
1589 | 1619 | extern kui eek_ord; |
1590 | 1620 | #define ORD(c) ((size_t)(c) > 0xFF ? eek_ord : KBI(c)) |
1591 | #define ord(c) __builtin_choose_expr( \ | |
1592 | __builtin_types_compatible_p(__typeof__(c), char) || \ | |
1593 | __builtin_types_compatible_p(__typeof__(c), unsigned char), \ | |
1594 | KBI(c), ({ \ | |
1595 | size_t ord_c = (c); \ | |
1596 | \ | |
1597 | if (ord_c > (size_t)0xFFU) \ | |
1598 | internal_errorf("%s:%d:ord(%zX)", \ | |
1599 | __FILE__, __LINE__, ord_c); \ | |
1600 | (KBI(ord_c)); \ | |
1621 | #define ord(c) __builtin_choose_expr( \ | |
1622 | __builtin_types_compatible_p(__typeof__(c), char) || \ | |
1623 | __builtin_types_compatible_p(__typeof__(c), unsigned char), \ | |
1624 | KBI(c), ({ \ | |
1625 | size_t ord_c = (c); \ | |
1626 | \ | |
1627 | if (ord_c > (size_t)0xFFU) \ | |
1628 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, \ | |
1629 | "%s:%d:ord(%zX)", __FILE__, __LINE__, ord_c); \ | |
1630 | (KBI(ord_c)); \ | |
1601 | 1631 | })) |
1602 | 1632 | #else |
1603 | 1633 | #define ord(c) KBI(c) |
1614 | 1644 | #define rtt2asc(c) ebcdic_rtt_toascii[KBY(c)] |
1615 | 1645 | #define asc2rtt(c) ebcdic_rtt_fromascii[KBY(c)] |
1616 | 1646 | /* case-independent char comparison */ |
1617 | #define ksh_eq(c,u,l) (ord(c) == ord(u) || ord(c) == ord(l)) | |
1618 | #else | |
1647 | #define isCh(c,u,l) (ord(c) == ord(u) || ord(c) == ord(l)) | |
1648 | #else | |
1649 | /* POSIX locale ordering */ | |
1619 | 1650 | #define asciibetical(c) ord(c) |
1651 | /* if inspecting numerical values (mapping on EBCDIC) */ | |
1620 | 1652 | #define rtt2asc(c) KBY(c) |
1621 | 1653 | #define asc2rtt(c) KBY(c) |
1622 | #define ksh_eq(c,u,l) ((ord(c) | 0x20U) == ord(l)) | |
1623 | #endif | |
1654 | /* case-independent char comparison */ | |
1655 | #define isCh(c,u,l) ((ord(c) | 0x20U) == ord(l)) | |
1656 | #endif | |
1657 | /* vs case-sensitive char comparison */ | |
1658 | #define isch(c,t) (ord(c) == ORD(t)) | |
1624 | 1659 | /* control character foo */ |
1625 | 1660 | #ifdef MKSH_EBCDIC |
1626 | 1661 | #define ksh_isctrl(c) (ord(c) < 0x40U || ord(c) == 0xFFU) |
1653 | 1688 | /* Argument parsing for built-in commands and getopts command */ |
1654 | 1689 | |
1655 | 1690 | /* Values for Getopt.flags */ |
1656 | #define GF_ERROR BIT(0) /* call errorf() if there is an error */ | |
1691 | #define GF_ERROR BIT(0) /* KWF_BIERR if there is an error */ | |
1657 | 1692 | #define GF_PLUSOPT BIT(1) /* allow +c as an option */ |
1658 | 1693 | #define GF_NONAME BIT(2) /* don't print argv[0] in errors */ |
1659 | 1694 | |
1681 | 1716 | |
1682 | 1717 | /* This for co-processes */ |
1683 | 1718 | |
1684 | /* something that won't (realisticly) wrap */ | |
1685 | typedef int Coproc_id; | |
1719 | /* something that won't (realistically) wrap */ | |
1720 | typedef unsigned int Coproc_id; | |
1686 | 1721 | |
1687 | 1722 | struct coproc { |
1688 | 1723 | void *job; /* 0 or job of co-process using input pipe */ |
1826 | 1861 | const char *fpath; /* temporary path to undef function */ |
1827 | 1862 | } u; |
1828 | 1863 | union { |
1864 | k32 hval; /* hash(name) */ | |
1865 | k32 index; /* index for an array */ | |
1866 | } ua; | |
1867 | union { | |
1829 | 1868 | int field; /* field with for -L/-R/-Z */ |
1830 | 1869 | int errnov; /* CEXEC/CTALIAS */ |
1831 | 1870 | } u2; |
1832 | union { | |
1833 | uint32_t hval; /* hash(name) */ | |
1834 | uint32_t index; /* index for an array */ | |
1835 | } ua; | |
1836 | 1871 | /* |
1837 | 1872 | * command type (see below), base (if INTEGER), |
1838 | 1873 | * offset from val.s of value (if EXPORT) |
1839 | 1874 | */ |
1840 | 1875 | int type; |
1841 | 1876 | /* flags (see below) */ |
1842 | uint32_t flag; | |
1877 | kui flag; | |
1843 | 1878 | |
1844 | 1879 | /* actually longer: name (variable length) */ |
1845 | 1880 | char name[4]; |
2437 | 2472 | #define notok2mul(max,val,c) (((val) != 0) && ((c) != 0) && \ |
2438 | 2473 | (((max) / (c)) < (val))) |
2439 | 2474 | #define notok2add(max,val,c) ((val) > ((max) - (c))) |
2440 | #define notoktomul(val,cnst) notok2mul(SIZE_MAX, (val), (cnst)) | |
2441 | #define notoktoadd(val,cnst) notok2add(SIZE_MAX, (val), (cnst)) | |
2475 | #define notoktomul(val,cnst) notok2mul(mksh_MAXSZ, (val), (cnst)) | |
2476 | #define notoktoadd(val,cnst) notok2add(mksh_MAXSZ, (val), (cnst)) | |
2442 | 2477 | #define checkoktoadd(val,cnst) do { \ |
2443 | 2478 | if (notoktoadd((val), (cnst))) \ |
2444 | internal_errorf(Tintovfl, (size_t)(val), \ | |
2445 | '+', (size_t)(cnst)); \ | |
2479 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, \ | |
2480 | Tintovfl, (size_t)(val), '+', (size_t)(cnst)); \ | |
2446 | 2481 | } while (/* CONSTCOND */ 0) |
2447 | 2482 | |
2448 | 2483 | /* lalloc.c */ |
2484 | 2519 | int execute(struct op * volatile, volatile int, volatile int * volatile); |
2485 | 2520 | int c_builtin(const char **); |
2486 | 2521 | struct tbl *get_builtin(const char *); |
2487 | struct tbl *findfunc(const char *, uint32_t, bool); | |
2522 | struct tbl *findfunc(const char *, k32, bool); | |
2488 | 2523 | int define(const char *, struct op *); |
2489 | 2524 | const char *builtin(const char *, int (*)(const char **)); |
2490 | 2525 | struct tbl *findcom(const char *, int); |
2629 | 2664 | int j_stopped_running(void); |
2630 | 2665 | /* lex.c */ |
2631 | 2666 | int yylex(int); |
2632 | void yyerror(const char *, ...) | |
2633 | MKSH_A_NORETURN | |
2634 | MKSH_A_FORMAT(__printf__, 1, 2); | |
2635 | 2667 | Source *pushs(int, Area *); |
2636 | 2668 | void set_prompt(int, Source *); |
2637 | 2669 | int pprompt(const char *, int); |
2638 | 2670 | /* main.c */ |
2671 | kby kshname_islogin(const char **); | |
2639 | 2672 | int include(const char *, int, const char **, bool); |
2640 | 2673 | int command(const char *, int); |
2641 | 2674 | int shell(Source * volatile, volatile int); |
2645 | 2678 | void quitenv(struct shf *); |
2646 | 2679 | void cleanup_parents_env(void); |
2647 | 2680 | void cleanup_proc_env(void); |
2648 | void errorf(const char *, ...) | |
2649 | MKSH_A_NORETURN | |
2650 | MKSH_A_FORMAT(__printf__, 1, 2); | |
2651 | void errorfx(int, const char *, ...) | |
2652 | MKSH_A_NORETURN | |
2653 | MKSH_A_FORMAT(__printf__, 2, 3); | |
2654 | void warningf(bool, const char *, ...) | |
2655 | MKSH_A_FORMAT(__printf__, 2, 3); | |
2681 | /* old {{{ */ | |
2656 | 2682 | void bi_errorf(const char *, ...) |
2657 | 2683 | MKSH_A_FORMAT(__printf__, 1, 2); |
2658 | void maybe_errorf(int *, int, const char *, ...) | |
2659 | MKSH_A_FORMAT(__printf__, 3, 4); | |
2660 | #define errorfz() errorf(NULL) | |
2661 | #define errorfxz(rc) errorfx((rc), NULL) | |
2662 | #define bi_errorfz() bi_errorf(NULL) | |
2663 | void internal_errorf(const char *, ...) | |
2664 | MKSH_A_NORETURN | |
2665 | MKSH_A_FORMAT(__printf__, 1, 2); | |
2666 | void internal_warningf(const char *, ...) | |
2667 | MKSH_A_FORMAT(__printf__, 1, 2); | |
2668 | void error_prefix(bool); | |
2684 | /* old }}} */ | |
2669 | 2685 | void shellf(const char *, ...) |
2670 | 2686 | MKSH_A_FORMAT(__printf__, 1, 2); |
2671 | 2687 | void shprintf(const char *, ...) |
2687 | 2703 | void coproc_cleanup(int); |
2688 | 2704 | struct temp *maketemp(Area *, Temp_type, struct temp **); |
2689 | 2705 | void ktinit(Area *, struct table *, kby); |
2690 | struct tbl *ktscan(struct table *, const char *, uint32_t, struct tbl ***); | |
2706 | struct tbl *ktscan(struct table *, const char *, k32, struct tbl ***); | |
2691 | 2707 | /* table, name (key) to search for, hash(n) */ |
2692 | 2708 | #define ktsearch(tp,s,h) ktscan((tp), (s), (h), NULL) |
2693 | struct tbl *ktenter(struct table *, const char *, uint32_t); | |
2709 | struct tbl *ktenter(struct table *, const char *, k32); | |
2694 | 2710 | #define ktdelete(p) do { p->flag = 0; } while (/* CONSTCOND */ 0) |
2695 | 2711 | void ktwalk(struct tstate *, struct table *); |
2696 | 2712 | struct tbl *ktnext(struct tstate *); |
2702 | 2718 | /* misc.c */ |
2703 | 2719 | size_t option(const char *) MKSH_A_PURE; |
2704 | 2720 | char *getoptions(void); |
2705 | void change_flag(enum sh_flag, int, bool); | |
2721 | void change_flag(enum sh_flag, unsigned int, bool); | |
2706 | 2722 | void change_xtrace(unsigned char, bool); |
2707 | int parse_args(const char **, int, bool *); | |
2723 | int parse_args(const char **, unsigned int, bool *); | |
2708 | 2724 | int getn(const char *, int *); |
2709 | 2725 | int getpn(const char **, int *); |
2710 | 2726 | int gmatchx(const char *, const char *, bool); |
2711 | 2727 | bool has_globbing(const char *) MKSH_A_PURE; |
2712 | 2728 | int ascstrcmp(const void *, const void *) MKSH_A_PURE; |
2713 | 2729 | int ascpstrcmp(const void *, const void *) MKSH_A_PURE; |
2730 | void ksh_getopt_opterr(int, const char *, const char *); | |
2714 | 2731 | void ksh_getopt_reset(Getopt *, int); |
2715 | 2732 | int ksh_getopt(const char **, Getopt *, const char *); |
2716 | 2733 | void print_value_quoted(struct shf *, const char *); |
2766 | 2783 | #define shf_putc shf_putc_i |
2767 | 2784 | #endif |
2768 | 2785 | int shf_putchar(int, struct shf *); |
2769 | ssize_t shf_puts(const char *, struct shf *); | |
2786 | #ifdef MKSH_SHF_NO_INLINE | |
2787 | #define shf_puts shf_putsv | |
2788 | #else | |
2789 | #define shf_puts(s,shf) ((s) ? shf_write((s), strlen(s), (shf)) : (ssize_t)-1) | |
2790 | #endif | |
2791 | ssize_t shf_putsv(const char *, struct shf *); | |
2770 | 2792 | ssize_t shf_write(const char *, ssize_t, struct shf *); |
2771 | 2793 | ssize_t shf_fprintf(struct shf *, const char *, ...) |
2772 | 2794 | MKSH_A_FORMAT(__printf__, 2, 3); |
2776 | 2798 | char *shf_smprintf(const char *, ...) |
2777 | 2799 | MKSH_A_FORMAT(__printf__, 1, 2); |
2778 | 2800 | ssize_t shf_vfprintf(struct shf *, const char *, va_list) |
2779 | MKSH_A_FORMAT(__printf__, 2, 0); | |
2801 | #ifdef MKSH_SHF_VFPRINTF_NO_GCC_FORMAT_ATTRIBUTE | |
2802 | #define shf_vfprintf poisoned_shf_vfprintf | |
2803 | #else | |
2804 | MKSH_A_FORMAT(__printf__, 2, 0) | |
2805 | #endif | |
2806 | ; | |
2780 | 2807 | void set_ifs(const char *); |
2808 | /* flags for numfmt below */ | |
2809 | #define FL_SGN 0x0000 /* signed decimal */ | |
2810 | #define FL_DEC 0x0001 /* unsigned decimal */ | |
2811 | #define FL_OCT 0x0002 /* unsigned octal */ | |
2812 | #define FL_HEX 0x0003 /* unsigned sedecimal */ | |
2813 | #define FM_TYPE 0x0003 /* mask: decimal/octal/hex */ | |
2814 | #define FL_UCASE 0x0004 /* use upper-case digits beyond 9 */ | |
2815 | #define FL_UPPER 0x000C /* use upper-case digits beyond 9 and 'X' */ | |
2816 | #define FL_PLUS 0x0010 /* FL_SGN force sign output */ | |
2817 | #define FL_BLANK 0x0020 /* FL_SGN output space unless sign present */ | |
2818 | #define FL_HASH 0x0040 /* FL_OCT force 0; FL_HEX force 0x/0X */ | |
2819 | /* internal flags to numfmt / shf_vfprintf */ | |
2820 | #define FL_NEG 0x0080 /* negative number, negated */ | |
2821 | #define FL_SHORT 0x0100 /* ‘h’ seen */ | |
2822 | #define FL_LONG 0x0200 /* ‘l’ seen */ | |
2823 | #define FL_SIZET 0x0400 /* ‘z’ seen */ | |
2824 | #define FM_SIZES 0x0700 /* mask: short/long/sizet */ | |
2825 | #define FL_NUMBER 0x0800 /* %[douxefg] a number was formatted */ | |
2826 | #define FL_RIGHT 0x1000 /* ‘-’ seen: right-pad, left-align */ | |
2827 | #define FL_ZERO 0x2000 /* ‘0’ seen: pad with leading zeros */ | |
2828 | #define FL_DOT 0x4000 /* ‘.’ seen: printf(3) precision specified */ | |
2829 | /* | |
2830 | * %#o produces the longest output: '0' + w/3 + NUL | |
2831 | * %#x produces '0x' + w/4 + NUL which is at least as long (w=8) | |
2832 | * %+d produces sign + w/log₂(10) + NUL | |
2833 | */ | |
2834 | #define NUMBUFSZ (1U + (mbiTYPE_UBITS(kul) + 2U) / 3U + /* NUL */ 1U) | |
2835 | #define NUMBUFLEN(base,result) ((base) + NUMBUFSZ - (result) - 1U) | |
2836 | char *kulfmt(kul number, kui flags, char *numbuf) | |
2837 | MKSH_A_BOUNDED(__minbytes__, 3, NUMBUFSZ); | |
2838 | char *kslfmt(ksl number, kui flags, char *numbuf) | |
2839 | MKSH_A_BOUNDED(__minbytes__, 3, NUMBUFSZ); | |
2781 | 2840 | /* syn.c */ |
2782 | 2841 | void initkeywords(void); |
2783 | 2842 | struct op *compile(Source *, bool); |
2784 | 2843 | bool parse_usec(const char *, struct timeval *); |
2785 | 2844 | char *yyrecursive(int); |
2786 | 2845 | void yyrecursive_pop(bool); |
2846 | void yyerror(const char *, ...) | |
2847 | MKSH_A_NORETURN | |
2848 | MKSH_A_FORMAT(__printf__, 1, 2); | |
2849 | /* shell error reporting */ | |
2850 | void bi_unwind(int); | |
2851 | bool error_prefix(bool); | |
2852 | #define KWF_BIERR (KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | \ | |
2853 | KWF_BUILTIN | KWF_BIUNWIND) | |
2854 | #define KWF_ERR(n) ((((unsigned int)(n)) & KWF_EXSTAT) | KWF_ERROR) | |
2855 | #define KWF_EXSTAT 0x0000FFU /* (mask) errorlevel to use */ | |
2856 | #define KWF_VERRNO 0x000100U /* int vararg: use ipv errno */ | |
2857 | #define KWF_INTERNAL 0x000200U /* internal {error,warning} */ | |
2858 | #define KWF_WARNING 0x000000U /* (default) warning */ | |
2859 | #define KWF_ERROR 0x000400U /* error + consequences */ | |
2860 | #define KWF_PREFIX 0x000800U /* run error_prefix() */ | |
2861 | #define KWF_FILELINE 0x001000U /* error_prefix arg:=true */ | |
2862 | #define KWF_BUILTIN 0x002000U /* possibly show builtin_argv0 */ | |
2863 | #define KWF_MSGMASK 0x00C000U /* (mask) message to display */ | |
2864 | #define KWF_MSGFMT 0x000000U /* (default) printf-style variadic */ | |
2865 | #define KWF_ONEMSG 0x004000U /* only one string to show */ | |
2866 | #define KWF_TWOMSG 0x008000U /* two strings to show with colon */ | |
2867 | #define KWF_THREEMSG 0x00C000U /* three strings to colonise */ | |
2868 | #define KWF_NOERRNO 0x010000U /* omit showing strerror */ | |
2869 | #define KWF_BIUNWIND 0x020000U /* let kwarnf* tailcall bi_unwind(0) */ | |
2870 | void kwarnf(unsigned int, ...); | |
2871 | #ifndef MKSH_SMALL | |
2872 | void kwarnf0(unsigned int, const char *, ...) | |
2873 | MKSH_A_FORMAT(__printf__, 2, 3); | |
2874 | void kwarnf1(unsigned int, int, const char *, ...) | |
2875 | MKSH_A_FORMAT(__printf__, 3, 4); | |
2876 | #else | |
2877 | #define kwarnf0 kwarnf /* with KWF_MSGFMT and !KWF_VERRNO */ | |
2878 | #define kwarnf1 kwarnf /* with KWF_MSGFMT and KWF_VERRNO */ | |
2879 | #endif | |
2880 | void kerrf(unsigned int, ...) | |
2881 | MKSH_A_NORETURN; | |
2882 | #ifndef MKSH_SMALL | |
2883 | void kerrf0(unsigned int, const char *, ...) | |
2884 | MKSH_A_NORETURN | |
2885 | MKSH_A_FORMAT(__printf__, 2, 3); | |
2886 | void kerrf1(unsigned int, int, const char *, ...) | |
2887 | MKSH_A_NORETURN | |
2888 | MKSH_A_FORMAT(__printf__, 3, 4); | |
2889 | #else | |
2890 | #define kerrf0 kerrf /* with KWF_MSGFMT and !KWF_VERRNO */ | |
2891 | #define kerrf1 kerrf /* with KWF_MSGFMT and KWF_VERRNO */ | |
2892 | #endif | |
2893 | void merrF(int *, unsigned int, ...); | |
2894 | #define merrf(rv,va) do { \ | |
2895 | merrF va; \ | |
2896 | return (rv); \ | |
2897 | } while (/* CONSTCOND */ 0) | |
2787 | 2898 | /* tree.c */ |
2788 | 2899 | void fptreef(struct shf *, int, const char *, ...); |
2789 | 2900 | char *snptreef(char *, ssize_t, const char *, ...); |
2812 | 2923 | void newblock(void); |
2813 | 2924 | void popblock(void); |
2814 | 2925 | void initvar(void); |
2815 | struct block *varsearch(struct block *, struct tbl **, const char *, uint32_t); | |
2926 | struct block *varsearch(struct block *, struct tbl **, const char *, k32); | |
2816 | 2927 | struct tbl *global(const char *); |
2817 | 2928 | struct tbl *isglobal(const char *, bool); |
2818 | 2929 | struct tbl *local(const char *, bool); |
2821 | 2932 | struct tbl *setint_v(struct tbl *, struct tbl *, bool); |
2822 | 2933 | void setint(struct tbl *, mksh_ari_t); |
2823 | 2934 | void setint_n(struct tbl *, mksh_ari_t, int); |
2824 | struct tbl *typeset(const char *, uint32_t, uint32_t, int, int); | |
2935 | struct tbl *typeset(const char *, kui, kui, int, int); | |
2825 | 2936 | void unset(struct tbl *, int); |
2826 | 2937 | const char *skip_varname(const char *, bool) MKSH_A_PURE; |
2827 | 2938 | const char *skip_wdvarname(const char *, bool) MKSH_A_PURE; |
2828 | 2939 | int is_wdvarname(const char *, bool) MKSH_A_PURE; |
2829 | 2940 | int is_wdvarassign(const char *) MKSH_A_PURE; |
2830 | struct tbl *arraysearch(struct tbl *, uint32_t); | |
2941 | struct tbl *arraysearch(struct tbl *, k32); | |
2831 | 2942 | char **makenv(void); |
2832 | 2943 | void change_winsz(void); |
2833 | 2944 | size_t array_ref_len(const char *) MKSH_A_PURE; |
2834 | 2945 | struct tbl *arraybase(const char *); |
2835 | 2946 | mksh_uari_t set_array(const char *, bool, const char **); |
2836 | uint32_t hash(const void *) MKSH_A_PURE; | |
2837 | uint32_t chvt_rndsetup(const void *, size_t) MKSH_A_PURE; | |
2838 | mksh_ari_t rndget(void); | |
2947 | k32 hash(const void *) MKSH_A_PURE; | |
2948 | k32 chvt_rndsetup(const void *, size_t) MKSH_A_PURE; | |
2949 | k32 rndget(void); | |
2839 | 2950 | void rndset(unsigned long); |
2840 | void rndpush(const void *); | |
2951 | void rndpush(const void *, size_t); | |
2841 | 2952 | void record_match(const char *); |
2842 | 2953 | |
2843 | 2954 | enum Test_op { |
2881 | 2992 | extern const struct t_op b_ops[]; |
2882 | 2993 | /* ensure order with funcs.c */ |
2883 | 2994 | #define Tda (u_ops[0].op_text) |
2995 | #define Tdc (u_ops[2].op_text) | |
2884 | 2996 | #define Tdn (u_ops[12].op_text) |
2885 | 2997 | #define Tdo (u_ops[14].op_text) |
2998 | #define Tdp (u_ops[15].op_text) | |
2886 | 2999 | #define Tdr (u_ops[16].op_text) |
2887 | 3000 | #define Tdu (u_ops[20].op_text) /* "-u" */ |
2888 | 3001 | #define Tdx (u_ops[23].op_text) |
1 | 1 | |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, |
4 | * 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2021 | |
4 | * 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2021, | |
5 | * 2022 | |
5 | 6 | * mirabilos <m@mirbsd.org> |
6 | 7 | * Copyright (c) 2015 |
7 | 8 | * Daniel Richard G. <skunk@iSKUNK.ORG> |
26 | 27 | |
27 | 28 | #include "sh.h" |
28 | 29 | |
29 | __RCSID("$MirOS: src/bin/mksh/shf.c,v 1.120 2021/10/01 23:25:35 tg Exp $"); | |
30 | __RCSID("$MirOS: src/bin/mksh/shf.c,v 1.128 2022/01/06 22:35:04 tg Exp $"); | |
30 | 31 | |
31 | 32 | /* flags to shf_emptybuf() */ |
32 | 33 | #define EB_READSW 0x01 /* about to switch to reading */ |
91 | 92 | } |
92 | 93 | |
93 | 94 | /* helper function for shf_fdopen and shf_reopen */ |
95 | /* pre-initio() *sflagsp=SHF_WR */ | |
94 | 96 | static void |
95 | 97 | shf_open_hlp(int fd, int *sflagsp, const char *where) |
96 | 98 | { |
120 | 122 | } |
121 | 123 | |
122 | 124 | if (!(sflags & (SHF_RD | SHF_WR))) |
123 | internal_errorf(Tbad_flags, where, sflags); | |
125 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
126 | Tbad_flags, where, sflags); | |
124 | 127 | } |
125 | 128 | |
126 | 129 | /* Set up the shf structure for a file descriptor. Doesn't fail. */ |
130 | /* pre-initio() sflags=SHF_WR */ | |
127 | 131 | struct shf * |
128 | 132 | shf_fdopen(int fd, int sflags, struct shf *shf) |
129 | 133 | { |
130 | 134 | ssize_t bsize = |
131 | 135 | /* at most 512 */ |
132 | sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; | |
136 | (sflags & SHF_UNBUF) ? ((sflags & SHF_RD) ? 1 : 0) : SHF_BSIZE; | |
133 | 137 | |
134 | 138 | shf_open_hlp(fd, &sflags, "shf_fdopen"); |
135 | 139 | if (shf) { |
139 | 143 | } else |
140 | 144 | shf->buf = NULL; |
141 | 145 | } else { |
142 | shf = alloc(sizeof(struct shf) + bsize, ATEMP); | |
143 | shf->buf = (unsigned char *)&shf[1]; | |
146 | unsigned char *cp; | |
147 | ||
148 | cp = alloc(sizeof(struct shf) + bsize, ATEMP); | |
149 | shf = (void *)cp; | |
150 | shf->buf = cp + sizeof(struct shf); | |
144 | 151 | sflags |= SHF_ALLOCS; |
145 | 152 | } |
146 | 153 | shf->areap = ATEMP; |
154 | 161 | shf->errnosv = 0; |
155 | 162 | shf->bsize = bsize; |
156 | 163 | if ((sflags & SHF_CLEXEC) && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) |
157 | internal_warningf(Tcloexec_failed, "set", fd, | |
158 | cstrerror(errno)); | |
164 | kwarnf0(KWF_INTERNAL | KWF_WARNING, Tcloexec_failed, "set", fd); | |
159 | 165 | return (shf); |
160 | 166 | } |
161 | 167 | |
169 | 175 | |
170 | 176 | shf_open_hlp(fd, &sflags, "shf_reopen"); |
171 | 177 | if (!shf->buf || shf->bsize < bsize) |
172 | internal_errorf(Tbad_buf, "shf_reopen", | |
173 | (size_t)shf->buf, shf->bsize); | |
178 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
179 | Tbad_buf, "shf_reopen", (size_t)shf->buf, shf->bsize); | |
174 | 180 | |
175 | 181 | /* assumes shf->buf and shf->bsize already set up */ |
176 | 182 | shf->fd = fd; |
182 | 188 | shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; |
183 | 189 | shf->errnosv = 0; |
184 | 190 | if ((sflags & SHF_CLEXEC) && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) |
185 | internal_warningf(Tcloexec_failed, "set", fd, | |
186 | cstrerror(errno)); | |
191 | kwarnf0(KWF_INTERNAL | KWF_WARNING, Tcloexec_failed, "set", fd); | |
187 | 192 | return (shf); |
188 | 193 | } |
189 | 194 | |
200 | 205 | shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf) |
201 | 206 | { |
202 | 207 | if (!((sflags & SHF_RD) ^ (sflags & SHF_WR))) |
203 | internal_errorf(Tbad_flags, "shf_sopen", sflags); | |
208 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
209 | Tbad_flags, "shf_sopen", sflags); | |
204 | 210 | |
205 | 211 | if (!shf) { |
206 | 212 | shf = alloc(sizeof(struct shf), ATEMP); |
243 | 249 | shf_scheck_grow(ssize_t n, struct shf *shf) |
244 | 250 | { |
245 | 251 | if (!(shf->flags & SHF_WR)) |
246 | internal_errorf(Tbad_flags, "shf_scheck", shf->flags); | |
252 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
253 | Tbad_flags, "shf_scheck", shf->flags); | |
247 | 254 | |
248 | 255 | /* if n < 0 we lose in the macro already */ |
249 | 256 | |
331 | 338 | if (shf->flags & SHF_STRING) |
332 | 339 | rv = (shf->flags & SHF_WR) ? -1 : 0; |
333 | 340 | else if (shf->fd < 0) |
334 | internal_errorf(Tf_sD_s, "shf_flush", "no fd"); | |
341 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG | KWF_NOERRNO, | |
342 | "shf_flush", "no fd"); | |
335 | 343 | else if (shf->flags & SHF_ERROR) { |
336 | 344 | errno = shf->errnosv; |
337 | 345 | rv = -1; |
363 | 371 | int ret = 0; |
364 | 372 | |
365 | 373 | if (!(shf->flags & SHF_STRING) && shf->fd < 0) |
366 | internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd"); | |
374 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG | KWF_NOERRNO, | |
375 | "shf_emptybuf", "no fd"); | |
367 | 376 | |
368 | 377 | if (shf->flags & SHF_ERROR) { |
369 | 378 | errno = shf->errnosv; |
451 | 460 | return (0); |
452 | 461 | |
453 | 462 | if (shf->fd < 0) |
454 | internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd"); | |
463 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG | KWF_NOERRNO, | |
464 | "shf_fillbuf", "no fd"); | |
455 | 465 | |
456 | 466 | if (shf->flags & (SHF_EOF | SHF_ERROR)) { |
457 | 467 | if (shf->flags & SHF_ERROR) |
494 | 504 | ssize_t ncopy, orig_bsize = bsize; |
495 | 505 | |
496 | 506 | if (!(shf->flags & SHF_RD)) |
497 | internal_errorf(Tbad_flags, Tshf_read, shf->flags); | |
507 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
508 | Tbad_flags, Tshf_read, shf->flags); | |
498 | 509 | |
499 | 510 | if (bsize <= 0) |
500 | internal_errorf(Tbad_buf, Tshf_read, (size_t)buf, bsize); | |
511 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
512 | Tbad_buf, Tshf_read, (size_t)buf, bsize); | |
501 | 513 | |
502 | 514 | while (bsize > 0) { |
503 | 515 | if (shf->rnleft == 0 && |
531 | 543 | char *orig_buf = buf; |
532 | 544 | |
533 | 545 | if (!(shf->flags & SHF_RD)) |
534 | internal_errorf(Tbad_flags, "shf_getse", shf->flags); | |
546 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
547 | Tbad_flags, "shf_getse", shf->flags); | |
535 | 548 | |
536 | 549 | if (bsize <= 0) |
537 | 550 | return (NULL); |
552 | 565 | ncopy = end ? end - shf->rp + 1 : shf->rnleft; |
553 | 566 | if (ncopy > bsize) |
554 | 567 | ncopy = bsize; |
555 | memcpy(buf, (char *) shf->rp, ncopy); | |
568 | memcpy(buf, shf->rp, ncopy); | |
556 | 569 | shf->rp += ncopy; |
557 | 570 | shf->rnleft -= ncopy; |
558 | 571 | buf += ncopy; |
584 | 597 | shf_getchar(struct shf *shf) |
585 | 598 | { |
586 | 599 | if (!(shf->flags & SHF_RD)) |
587 | internal_errorf(Tbad_flags, "shf_getchar", shf->flags); | |
600 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
601 | Tbad_flags, "shf_getchar", shf->flags); | |
588 | 602 | |
589 | 603 | if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0)) |
590 | 604 | return (-1); |
600 | 614 | shf_ungetc(int c, struct shf *shf) |
601 | 615 | { |
602 | 616 | if (!(shf->flags & SHF_RD)) |
603 | internal_errorf(Tbad_flags, "shf_ungetc", shf->flags); | |
617 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
618 | Tbad_flags, "shf_ungetc", shf->flags); | |
604 | 619 | |
605 | 620 | if ((shf->flags & SHF_ERROR) || c == -1 || |
606 | 621 | (shf->rp == shf->buf && shf->rnleft)) |
637 | 652 | shf_putchar(int c, struct shf *shf) |
638 | 653 | { |
639 | 654 | if (!(shf->flags & SHF_WR)) |
640 | internal_errorf(Tbad_flags, "shf_putchar",shf->flags); | |
655 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
656 | Tbad_flags, "shf_putchar", shf->flags); | |
641 | 657 | |
642 | 658 | if (c == -1) |
643 | 659 | return (-1); |
647 | 663 | ssize_t n; |
648 | 664 | |
649 | 665 | if (shf->fd < 0) |
650 | internal_errorf(Tf_sD_s, "shf_putchar", "no fd"); | |
666 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_TWOMSG | KWF_NOERRNO, | |
667 | "shf_putchar", "no fd"); | |
651 | 668 | if (shf->flags & SHF_ERROR) { |
652 | 669 | errno = shf->errnosv; |
653 | 670 | return (-1); |
677 | 694 | * less if truncated, and -1 if the string could not be written. |
678 | 695 | */ |
679 | 696 | ssize_t |
680 | shf_puts(const char *s, struct shf *shf) | |
697 | shf_putsv(const char *s, struct shf *shf) | |
681 | 698 | { |
682 | 699 | if (!s) |
683 | 700 | return (-1); |
695 | 712 | ssize_t n, ncopy, orig_nbytes = nbytes; |
696 | 713 | |
697 | 714 | if (!(shf->flags & SHF_WR)) |
698 | internal_errorf(Tbad_flags, Tshf_write, shf->flags); | |
715 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
716 | Tbad_flags, Tshf_write, shf->flags); | |
699 | 717 | |
700 | 718 | if (nbytes < 0) |
701 | internal_errorf(Tbad_buf, Tshf_write, (size_t)buf, nbytes); | |
719 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
720 | Tbad_buf, Tshf_write, (size_t)buf, nbytes); | |
702 | 721 | |
703 | 722 | /* don't buffer if buffer is empty and we're writing a large amount */ |
704 | 723 | if ((ncopy = shf->wnleft) && |
786 | 805 | ssize_t n; |
787 | 806 | |
788 | 807 | if (!buf || bsize <= 0) |
789 | internal_errorf(Tbad_buf, "shf_snprintf", (size_t)buf, bsize); | |
808 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
809 | Tbad_buf, "shf_snprintf", (size_t)buf, bsize); | |
790 | 810 | |
791 | 811 | shf_sopen(buf, bsize, SHF_WR, &shf); |
792 | 812 | va_start(args, fmt); |
811 | 831 | return (shf_sclose(&shf)); |
812 | 832 | } |
813 | 833 | |
814 | #define FL_HASH 0x001 /* '#' seen */ | |
815 | #define FL_PLUS 0x002 /* '+' seen */ | |
816 | #define FL_RIGHT 0x004 /* '-' seen */ | |
817 | #define FL_BLANK 0x008 /* ' ' seen */ | |
818 | #define FL_SHORT 0x010 /* 'h' seen */ | |
819 | #define FL_LONG 0x020 /* 'l' seen */ | |
820 | #define FL_ZERO 0x040 /* '0' seen */ | |
821 | #define FL_DOT 0x080 /* '.' seen */ | |
822 | #define FL_UPPER 0x100 /* format character was uppercase */ | |
823 | #define FL_NUMBER 0x200 /* a number was formatted %[douxefg] */ | |
824 | #define FL_SIZET 0x400 /* 'z' seen */ | |
825 | #define FM_SIZES 0x430 /* h/l/z mask */ | |
834 | /* pre-initio() */ | |
835 | char * | |
836 | kslfmt(ksl number, kui flags, char *numbuf) | |
837 | { | |
838 | if (!IS(flags, FM_TYPE, FL_SGN)) { | |
839 | /* uh-oh, unsigned? what? be bitwise faithful here */ | |
840 | union { | |
841 | /*XXX hopefully not UB… */ | |
842 | ksl s; | |
843 | kul u; | |
844 | } v; | |
845 | ||
846 | v.s = number; | |
847 | return (kulfmt(v.u, flags, numbuf)); | |
848 | } | |
849 | if (number < 0) | |
850 | flags |= FL_NEG; | |
851 | return (kulfmt(KSL2NEGUL(number), flags, numbuf)); | |
852 | } | |
853 | ||
854 | /* pre-initio() */ | |
855 | char * | |
856 | kulfmt(kul number, kui flags, char *numbuf) | |
857 | { | |
858 | char *cp; | |
859 | ||
860 | cp = numbuf + NUMBUFSZ; | |
861 | *--cp = '\0'; | |
862 | switch (flags & FM_TYPE) { | |
863 | case FL_OCT: | |
864 | do { | |
865 | *--cp = digits_lc[number & 07UL]; | |
866 | number >>= 3; | |
867 | } while (number); | |
868 | ||
869 | if (HAS(flags, FL_HASH) && ord(*cp) != ORD('0')) | |
870 | *--cp = '0'; | |
871 | break; | |
872 | case FL_HEX: { | |
873 | const char *digits; | |
874 | ||
875 | digits = HAS(flags, FL_UCASE) ? digits_uc : digits_lc; | |
876 | do { | |
877 | *--cp = digits[number & 0xFUL]; | |
878 | number >>= 4; | |
879 | } while (number); | |
880 | ||
881 | if (HAS(flags, FL_HASH)) { | |
882 | *--cp = IS(flags, FL_UPPER, FL_UPPER) ? 'X' : 'x'; | |
883 | *--cp = '0'; | |
884 | } | |
885 | break; | |
886 | } | |
887 | default: | |
888 | do { | |
889 | *--cp = digits_lc[number % 10UL]; | |
890 | number /= 10UL; | |
891 | } while (number); | |
892 | ||
893 | if (!IS(flags, FM_TYPE, FL_DEC)) { | |
894 | if (HAS(flags, FL_NEG)) | |
895 | *--cp = '-'; | |
896 | else if (HAS(flags, FL_PLUS)) | |
897 | *--cp = '+'; | |
898 | else if (HAS(flags, FL_BLANK)) | |
899 | *--cp = '-'; | |
900 | } | |
901 | break; | |
902 | } | |
903 | ||
904 | return (cp); | |
905 | } | |
826 | 906 | |
827 | 907 | ssize_t |
828 | 908 | shf_vfprintf(struct shf *shf, const char *fmt, va_list args) |
829 | 909 | { |
910 | char numbuf[NUMBUFSZ]; | |
830 | 911 | const char *s; |
831 | char c, *cp; | |
912 | char c; | |
832 | 913 | int tmp = 0, flags; |
833 | 914 | size_t field, precision, len; |
834 | unsigned long lnum; | |
835 | /* %#o produces the longest output */ | |
836 | char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1]; | |
837 | 915 | /* this stuff for dealing with the buffer */ |
838 | 916 | ssize_t nwritten = 0; |
839 | 917 | /* for width determination */ |
941 | 1019 | switch (c) { |
942 | 1020 | case 'd': |
943 | 1021 | case 'i': |
944 | if (flags & FL_SIZET) | |
945 | lnum = (long)VA(ssize_t); | |
946 | else if (flags & FL_LONG) | |
947 | lnum = VA(long); | |
948 | else if (flags & FL_SHORT) | |
949 | lnum = (long)(short)VA(int); | |
950 | else | |
951 | lnum = (long)VA(int); | |
1022 | s = kslfmt(HAS(flags, FL_SIZET) ? (ksl)VA(ssize_t) : | |
1023 | HAS(flags, FL_LONG) ? (ksl)VA(long) : | |
1024 | HAS(flags, FL_SHORT) ? (ksl)(short)VA(int) : | |
1025 | (ksl)VA(int), flags | FL_SGN, numbuf); | |
952 | 1026 | goto integral; |
953 | 1027 | |
954 | 1028 | case 'o': |
1029 | flags |= FL_OCT; | |
1030 | if (0) | |
1031 | /* FALLTHROUGH */ | |
955 | 1032 | case 'u': |
1033 | flags |= FL_DEC; | |
1034 | if (0) | |
1035 | /* FALLTHROUGH */ | |
956 | 1036 | case 'x': |
957 | if (flags & FL_SIZET) | |
958 | lnum = VA(size_t); | |
959 | else if (flags & FL_LONG) | |
960 | lnum = VA(unsigned long); | |
961 | else if (flags & FL_SHORT) | |
962 | lnum = (unsigned long)(unsigned short)VA(int); | |
963 | else | |
964 | lnum = (unsigned long)VA(unsigned int); | |
965 | ||
1037 | flags |= FL_HEX; | |
1038 | ||
1039 | s = kulfmt(HAS(flags, FL_SIZET) ? (kul)VA(size_t) : | |
1040 | HAS(flags, FL_LONG) ? (kul)VA(unsigned long) : | |
1041 | HAS(flags, FL_SHORT) ? (kul)(unsigned short)VA(int) : | |
1042 | (kul)VA(unsigned int), flags, numbuf); | |
966 | 1043 | integral: |
967 | 1044 | flags |= FL_NUMBER; |
968 | cp = numbuf + sizeof(numbuf); | |
969 | *--cp = '\0'; | |
970 | ||
971 | switch (c) { | |
972 | case 'd': | |
973 | case 'i': | |
974 | if (0 > (long)lnum) { | |
975 | lnum = -(long)lnum; | |
976 | tmp = 1; | |
977 | } else | |
978 | tmp = 0; | |
979 | /* FALLTHROUGH */ | |
980 | case 'u': | |
981 | do { | |
982 | *--cp = digits_lc[lnum % 10]; | |
983 | lnum /= 10; | |
984 | } while (lnum); | |
985 | ||
986 | if (c != 'u') { | |
987 | if (tmp) | |
988 | *--cp = '-'; | |
989 | else if (flags & FL_PLUS) | |
990 | *--cp = '+'; | |
991 | else if (flags & FL_BLANK) | |
992 | *--cp = ' '; | |
993 | } | |
994 | break; | |
995 | ||
996 | case 'o': | |
997 | do { | |
998 | *--cp = digits_lc[lnum & 0x7]; | |
999 | lnum >>= 3; | |
1000 | } while (lnum); | |
1001 | ||
1002 | if ((flags & FL_HASH) && *cp != '0') | |
1003 | *--cp = '0'; | |
1004 | break; | |
1005 | ||
1006 | case 'x': { | |
1007 | const char *digits = (flags & FL_UPPER) ? | |
1008 | digits_uc : digits_lc; | |
1009 | do { | |
1010 | *--cp = digits[lnum & 0xF]; | |
1011 | lnum >>= 4; | |
1012 | } while (lnum); | |
1013 | ||
1014 | if (flags & FL_HASH) { | |
1015 | *--cp = (flags & FL_UPPER) ? 'X' : 'x'; | |
1016 | *--cp = '0'; | |
1017 | } | |
1018 | } | |
1019 | } | |
1020 | len = numbuf + sizeof(numbuf) - 1 - (s = cp); | |
1045 | len = NUMBUFLEN(numbuf, s); | |
1021 | 1046 | if (flags & FL_DOT) { |
1022 | 1047 | if (precision > len) { |
1023 | 1048 | field = precision; |
1030 | 1055 | |
1031 | 1056 | case 's': |
1032 | 1057 | if ((s = VA(const char *)) == NULL) |
1033 | s = "(null)"; | |
1058 | s = Tnil; | |
1034 | 1059 | else if (flags & FL_HASH) { |
1035 | 1060 | print_value_quoted(shf, s); |
1036 | 1061 | continue; |
1092 | 1117 | s++; |
1093 | 1118 | nwritten++; |
1094 | 1119 | if (--precision && |
1095 | ksh_eq(*s, 'X', 'x')) { | |
1120 | isCh(*s, 'X', 'x')) { | |
1096 | 1121 | shf_putc(*s, shf); |
1097 | 1122 | s++; |
1098 | 1123 | precision--; |
1138 | 1163 | } |
1139 | 1164 | #endif |
1140 | 1165 | |
1141 | #ifdef DEBUG | |
1142 | const char * | |
1143 | cstrerror(int errnum) | |
1144 | { | |
1145 | #undef strerror | |
1146 | return (strerror(errnum)); | |
1147 | #define strerror dontuse_strerror /* poisoned */ | |
1148 | } | |
1149 | #elif !HAVE_STRERROR | |
1150 | ||
1151 | #if HAVE_SYS_ERRLIST | |
1166 | #if !HAVE_STRERROR | |
1167 | ||
1168 | #if HAVE_STRERRORDESC_NP | |
1169 | /* assume prototype, _GNU_SOURCE may be needed */ | |
1170 | #elif HAVE_SYS_ERRLIST | |
1152 | 1171 | #if !HAVE_SYS_ERRLIST_DECL |
1153 | 1172 | extern const int sys_nerr; |
1154 | 1173 | extern const char * const sys_errlist[]; |
1155 | 1174 | #endif |
1156 | 1175 | #endif |
1157 | 1176 | |
1177 | /* pre-initio() */ | |
1158 | 1178 | const char * |
1159 | 1179 | cstrerror(int errnum) |
1160 | 1180 | { |
1161 | /* "Unknown error: " + sign + rough estimate + NUL */ | |
1162 | static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1]; | |
1163 | ||
1164 | #if HAVE_SYS_ERRLIST | |
1181 | #define unkerrstr "Unknown error: " | |
1182 | #define unkerrlen (sizeof(unkerrstr) - 1U) | |
1183 | static char errbuf[unkerrlen + NUMBUFSZ]; | |
1184 | #if HAVE_STRERRORDESC_NP | |
1185 | const char *ccp; | |
1186 | #endif | |
1187 | char *cp; | |
1188 | ||
1189 | #if HAVE_STRERRORDESC_NP | |
1190 | if ((ccp = strerrordesc_np(errnum))) | |
1191 | return (ccp); | |
1192 | #elif HAVE_SYS_ERRLIST | |
1165 | 1193 | if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum]) |
1166 | 1194 | return (sys_errlist[errnum]); |
1167 | 1195 | #endif |
1168 | 1196 | |
1197 | /* do not add ERANGE, might be EOVERFLOW */ | |
1169 | 1198 | switch (errnum) { |
1170 | 1199 | case 0: |
1171 | 1200 | return ("Undefined error: 0"); |
1177 | 1206 | case ESRCH: |
1178 | 1207 | return ("No such process"); |
1179 | 1208 | #endif |
1180 | #ifdef E2BIG | |
1181 | 1209 | case E2BIG: |
1182 | 1210 | return ("Argument list too long"); |
1183 | #endif | |
1184 | 1211 | case ENOEXEC: |
1185 | 1212 | return ("Exec format error"); |
1186 | 1213 | case EBADF: |
1195 | 1222 | return ("File exists"); |
1196 | 1223 | case ENOTDIR: |
1197 | 1224 | return ("Not a directory"); |
1198 | #ifdef EINVAL | |
1199 | 1225 | case EINVAL: |
1200 | 1226 | return ("Invalid argument"); |
1201 | #endif | |
1202 | 1227 | #ifdef ELOOP |
1203 | 1228 | case ELOOP: |
1204 | 1229 | return ("Too many levels of symbolic links"); |
1205 | 1230 | #endif |
1231 | case EOVERFLOW: | |
1232 | return ("Value too large"); | |
1206 | 1233 | default: |
1207 | shf_snprintf(errbuf, sizeof(errbuf), | |
1208 | "Unknown error: %d", errnum); | |
1209 | return (errbuf); | |
1210 | } | |
1234 | cp = kslfmt(errnum, FL_SGN, errbuf + unkerrlen); | |
1235 | cp -= unkerrlen; | |
1236 | memcpy(cp, unkerrstr, unkerrlen); | |
1237 | return (cp); | |
1238 | } | |
1239 | #undef unkerrlen | |
1240 | #undef unkerrstr | |
1241 | } | |
1242 | #elif defined(DEBUG) | |
1243 | /* pre-initio() */ | |
1244 | const char * | |
1245 | cstrerror(int errnum) | |
1246 | { | |
1247 | #undef strerror | |
1248 | return (strerror(errnum)); | |
1249 | #define strerror dontuse_strerror /* poisoned */ | |
1211 | 1250 | } |
1212 | 1251 | #endif |
1213 | 1252 | |
1214 | 1253 | /* fast character classes */ |
1215 | const uint32_t tpl_ctypes[128] = { | |
1254 | const kui tpl_ctypes[128] = { | |
1216 | 1255 | /* 0x00 */ |
1217 | 1256 | CiNUL, CiCNTRL, CiCNTRL, CiCNTRL, |
1218 | 1257 | CiCNTRL, CiCNTRL, CiCNTRL, CiCNTRL, |
1263 | 1302 | static int debug_ccls(void); |
1264 | 1303 | #endif |
1265 | 1304 | |
1305 | /* pre-initio() */ | |
1266 | 1306 | static void |
1267 | 1307 | set_ccls(void) |
1268 | 1308 | { |
1280 | 1320 | #endif |
1281 | 1321 | } |
1282 | 1322 | |
1323 | /* pre-initio() */ | |
1283 | 1324 | void |
1284 | 1325 | set_ifs(const char *s) |
1285 | 1326 | { |
1294 | 1335 | } |
1295 | 1336 | |
1296 | 1337 | #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC) |
1297 | #if !HAVE_SETLOCALE_CTYPE | |
1338 | #if !HAVE_SETLOCALE_LCALL && !defined(MKSH_FAUX_EBCDIC) | |
1298 | 1339 | # error EBCDIC support requires use of the system locale |
1299 | 1340 | #endif |
1300 | 1341 | #include <locale.h> |
1342 | ||
1343 | static void ebcdic_initerr(const char *, size_t, int, int, int) MKSH_A_NORETURN; | |
1301 | 1344 | |
1302 | 1345 | /* |
1303 | 1346 | * Many headaches with EBCDIC: |
1338 | 1381 | * side, but as it's not really used anyway we decided to take the risk. |
1339 | 1382 | */ |
1340 | 1383 | |
1384 | /* pre-initio() */ | |
1341 | 1385 | void |
1342 | 1386 | ebcdic_init(void) |
1343 | 1387 | { |
1350 | 1394 | memset(ebcdic_rtt_fromascii, 0xFF, sizeof(ebcdic_rtt_fromascii)); |
1351 | 1395 | setlocale(LC_ALL, ""); |
1352 | 1396 | #ifdef MKSH_EBCDIC |
1353 | if (__etoa_l(ebcdic_rtt_toascii, 256) != 256) { | |
1354 | write(2, "mksh: could not map EBCDIC to ASCII\n", 36); | |
1355 | exit(255); | |
1356 | } | |
1397 | errno = ENOTDIR; | |
1398 | if ((i = __etoa_l(ebcdic_rtt_toascii, 256)) != 256) | |
1399 | ebcdic_initerr(SC("mksh: could not map EBCDIC to ASCII"), | |
1400 | -1, i, errno); | |
1357 | 1401 | #endif |
1358 | 1402 | |
1359 | 1403 | memset(mapcache, 0, sizeof(mapcache)); |
1361 | 1405 | while (i--) { |
1362 | 1406 | t = ebcdic_rtt_toascii[i]; |
1363 | 1407 | /* ensure unique round-trip capable mapping */ |
1364 | if (mapcache[t]) { | |
1365 | write(2, "mksh: duplicate EBCDIC to ASCII mapping\n", 40); | |
1366 | exit(255); | |
1367 | } | |
1408 | if (mapcache[t]) | |
1409 | ebcdic_initerr(SC("mksh: duplicate EBCDIC to ASCII mapping"), | |
1410 | -2, i, ebcdic_rtt_fromascii[t]); | |
1368 | 1411 | /* |
1369 | 1412 | * since there are 256 input octets, this also ensures |
1370 | 1413 | * the other mapping direction is completely filled |
1388 | 1431 | else |
1389 | 1432 | ebcdic_map[i] = (unsigned short)(0x100U | ord(i)); |
1390 | 1433 | } |
1391 | if (ebcdic_rtt_toascii[0] || ebcdic_rtt_fromascii[0] || ebcdic_map[0]) { | |
1392 | write(2, "mksh: NUL not at position 0\n", 28); | |
1393 | exit(255); | |
1394 | } | |
1434 | if (ebcdic_rtt_toascii[0] || ebcdic_rtt_fromascii[0] || ebcdic_map[0]) | |
1435 | ebcdic_initerr(SC("mksh: NUL not at position 0"), | |
1436 | ebcdic_rtt_toascii[0], ebcdic_rtt_fromascii[0], | |
1437 | ebcdic_map[0]); | |
1395 | 1438 | /* ensure control characters, i.e. 0x00‥0x3F and 0xFF, map sanely */ |
1396 | 1439 | for (i = 0x00; i < 0x20; ++i) |
1397 | 1440 | if (!ksh_isctrl(asc2rtt(i))) |
1399 | 1442 | for (i = 0x7F; i < 0xA0; ++i) |
1400 | 1443 | if (!ksh_isctrl(asc2rtt(i))) { |
1401 | 1444 | ebcdic_ctrlmis: |
1402 | write(2, "mksh: control character mismapping\n", 35); | |
1403 | exit(255); | |
1445 | ebcdic_initerr(SC("mksh: control character mismapping"), | |
1446 | -2, i, asc2rtt(i)); | |
1404 | 1447 | } |
1405 | 1448 | /* validate character literals used in the code */ |
1406 | if (rtt2asc('\n') != 0x0AU || rtt2asc('\r') != 0x0DU || | |
1407 | rtt2asc(' ') != 0x20U || | |
1408 | rtt2asc('!') != 0x21U || | |
1409 | rtt2asc('"') != 0x22U || | |
1410 | rtt2asc('#') != 0x23U || | |
1411 | rtt2asc('$') != 0x24U || | |
1412 | rtt2asc('%') != 0x25U || | |
1413 | rtt2asc('&') != 0x26U || | |
1414 | rtt2asc('\'') != 0x27U || | |
1415 | rtt2asc('(') != 0x28U || | |
1416 | rtt2asc(')') != 0x29U || | |
1417 | rtt2asc('*') != 0x2AU || | |
1418 | rtt2asc('+') != 0x2BU || | |
1419 | rtt2asc(',') != 0x2CU || | |
1420 | rtt2asc('-') != 0x2DU || | |
1421 | rtt2asc('.') != 0x2EU || | |
1422 | rtt2asc('/') != 0x2FU || | |
1423 | rtt2asc('0') != 0x30U || | |
1424 | rtt2asc(':') != 0x3AU || | |
1425 | rtt2asc(';') != 0x3BU || | |
1426 | rtt2asc('<') != 0x3CU || | |
1427 | rtt2asc('=') != 0x3DU || | |
1428 | rtt2asc('>') != 0x3EU || | |
1429 | rtt2asc('?') != 0x3FU || | |
1430 | rtt2asc('@') != 0x40U || | |
1431 | rtt2asc('A') != 0x41U || | |
1432 | rtt2asc('B') != 0x42U || | |
1433 | rtt2asc('C') != 0x43U || | |
1434 | rtt2asc('D') != 0x44U || | |
1435 | rtt2asc('E') != 0x45U || | |
1436 | rtt2asc('F') != 0x46U || | |
1437 | rtt2asc('G') != 0x47U || | |
1438 | rtt2asc('H') != 0x48U || | |
1439 | rtt2asc('I') != 0x49U || | |
1440 | rtt2asc('N') != 0x4EU || | |
1441 | rtt2asc('O') != 0x4FU || | |
1442 | rtt2asc('P') != 0x50U || | |
1443 | rtt2asc('Q') != 0x51U || | |
1444 | rtt2asc('R') != 0x52U || | |
1445 | rtt2asc('S') != 0x53U || | |
1446 | rtt2asc('T') != 0x54U || | |
1447 | rtt2asc('U') != 0x55U || | |
1448 | rtt2asc('W') != 0x57U || | |
1449 | rtt2asc('X') != 0x58U || | |
1450 | rtt2asc('Y') != 0x59U || | |
1451 | rtt2asc('[') != 0x5BU || | |
1452 | rtt2asc('\\') != 0x5CU || | |
1453 | rtt2asc(']') != 0x5DU || | |
1454 | rtt2asc('^') != 0x5EU || | |
1455 | rtt2asc('_') != 0x5FU || | |
1456 | rtt2asc('`') != 0x60U || | |
1457 | rtt2asc('a') != 0x61U || | |
1458 | rtt2asc('b') != 0x62U || | |
1459 | rtt2asc('c') != 0x63U || | |
1460 | rtt2asc('d') != 0x64U || | |
1461 | rtt2asc('e') != 0x65U || | |
1462 | rtt2asc('f') != 0x66U || | |
1463 | rtt2asc('g') != 0x67U || | |
1464 | rtt2asc('h') != 0x68U || | |
1465 | rtt2asc('i') != 0x69U || | |
1466 | rtt2asc('j') != 0x6AU || | |
1467 | rtt2asc('k') != 0x6BU || | |
1468 | rtt2asc('l') != 0x6CU || | |
1469 | rtt2asc('n') != 0x6EU || | |
1470 | rtt2asc('p') != 0x70U || | |
1471 | rtt2asc('r') != 0x72U || | |
1472 | rtt2asc('s') != 0x73U || | |
1473 | rtt2asc('t') != 0x74U || | |
1474 | rtt2asc('u') != 0x75U || | |
1475 | rtt2asc('v') != 0x76U || | |
1476 | rtt2asc('w') != 0x77U || | |
1477 | rtt2asc('x') != 0x78U || | |
1478 | rtt2asc('y') != 0x79U || | |
1479 | rtt2asc('{') != 0x7BU || | |
1480 | rtt2asc('|') != 0x7CU || | |
1481 | rtt2asc('}') != 0x7DU || | |
1482 | rtt2asc('~') != 0x7EU) { | |
1483 | write(2, "mksh: compiler vs. runtime codepage mismatch!\n", 46); | |
1449 | #define litcheck(c,v) \ | |
1450 | if (rtt2asc(c) != v) \ | |
1451 | ebcdic_initerr(SC("mksh: compiler vs. runtime codepage mismatch"), \ | |
1452 | -3, c, rtt2asc(c)) | |
1453 | litcheck('\n', 0x0AU); | |
1454 | litcheck('\r', 0x0DU); | |
1455 | litcheck(' ', 0x20U); | |
1456 | litcheck('!', 0x21U); | |
1457 | litcheck('"', 0x22U); | |
1458 | litcheck('#', 0x23U); | |
1459 | litcheck('$', 0x24U); | |
1460 | litcheck('%', 0x25U); | |
1461 | litcheck('&', 0x26U); | |
1462 | litcheck('\'', 0x27U); | |
1463 | litcheck('(', 0x28U); | |
1464 | litcheck(')', 0x29U); | |
1465 | litcheck('*', 0x2AU); | |
1466 | litcheck('+', 0x2BU); | |
1467 | litcheck(',', 0x2CU); | |
1468 | litcheck('-', 0x2DU); | |
1469 | litcheck('.', 0x2EU); | |
1470 | litcheck('/', 0x2FU); | |
1471 | litcheck('0', 0x30U); | |
1472 | litcheck(':', 0x3AU); | |
1473 | litcheck(';', 0x3BU); | |
1474 | litcheck('<', 0x3CU); | |
1475 | litcheck('=', 0x3DU); | |
1476 | litcheck('>', 0x3EU); | |
1477 | litcheck('?', 0x3FU); | |
1478 | litcheck('@', 0x40U); | |
1479 | litcheck('A', 0x41U); | |
1480 | litcheck('B', 0x42U); | |
1481 | litcheck('C', 0x43U); | |
1482 | litcheck('D', 0x44U); | |
1483 | litcheck('E', 0x45U); | |
1484 | litcheck('F', 0x46U); | |
1485 | litcheck('G', 0x47U); | |
1486 | litcheck('H', 0x48U); | |
1487 | litcheck('I', 0x49U); | |
1488 | litcheck('N', 0x4EU); | |
1489 | litcheck('O', 0x4FU); | |
1490 | litcheck('P', 0x50U); | |
1491 | litcheck('Q', 0x51U); | |
1492 | litcheck('R', 0x52U); | |
1493 | litcheck('S', 0x53U); | |
1494 | litcheck('T', 0x54U); | |
1495 | litcheck('U', 0x55U); | |
1496 | litcheck('W', 0x57U); | |
1497 | litcheck('X', 0x58U); | |
1498 | litcheck('Y', 0x59U); | |
1499 | litcheck('[', 0x5BU); | |
1500 | litcheck('\\', 0x5CU); | |
1501 | litcheck(']', 0x5DU); | |
1502 | litcheck('^', 0x5EU); | |
1503 | litcheck('_', 0x5FU); | |
1504 | litcheck('`', 0x60U); | |
1505 | litcheck('a', 0x61U); | |
1506 | litcheck('b', 0x62U); | |
1507 | litcheck('c', 0x63U); | |
1508 | litcheck('d', 0x64U); | |
1509 | litcheck('e', 0x65U); | |
1510 | litcheck('f', 0x66U); | |
1511 | litcheck('g', 0x67U); | |
1512 | litcheck('h', 0x68U); | |
1513 | litcheck('i', 0x69U); | |
1514 | litcheck('j', 0x6AU); | |
1515 | litcheck('k', 0x6BU); | |
1516 | litcheck('l', 0x6CU); | |
1517 | litcheck('n', 0x6EU); | |
1518 | litcheck('p', 0x70U); | |
1519 | litcheck('r', 0x72U); | |
1520 | litcheck('s', 0x73U); | |
1521 | litcheck('t', 0x74U); | |
1522 | litcheck('u', 0x75U); | |
1523 | litcheck('v', 0x76U); | |
1524 | litcheck('w', 0x77U); | |
1525 | litcheck('x', 0x78U); | |
1526 | litcheck('y', 0x79U); | |
1527 | litcheck('{', 0x7BU); | |
1528 | litcheck('|', 0x7CU); | |
1529 | litcheck('}', 0x7DU); | |
1530 | litcheck('~', 0x7EU); | |
1531 | #undef litcheck | |
1532 | /* validate sh.h control character literals */ | |
1533 | #define ctlcheck(n,c,v) \ | |
1534 | if (rtt2asc(c) != v) \ | |
1535 | ebcdic_initerr(SC("mksh: control character mismapping"), \ | |
1536 | -3, n, rtt2asc(c)) | |
1537 | ctlcheck('@', CTRL_AT, 0x00U); | |
1538 | ctlcheck('A', CTRL_A, 0x01U); | |
1539 | ctlcheck('B', CTRL_B, 0x02U); | |
1540 | ctlcheck('C', CTRL_C, 0x03U); | |
1541 | ctlcheck('D', CTRL_D, 0x04U); | |
1542 | ctlcheck('E', CTRL_E, 0x05U); | |
1543 | ctlcheck('F', CTRL_F, 0x06U); | |
1544 | ctlcheck('G', CTRL_G, 0x07U); | |
1545 | ctlcheck('H', CTRL_H, 0x08U); | |
1546 | ctlcheck('I', CTRL_I, 0x09U); | |
1547 | ctlcheck('J', CTRL_J, 0x0AU); | |
1548 | ctlcheck('K', CTRL_K, 0x0BU); | |
1549 | ctlcheck('L', CTRL_L, 0x0CU); | |
1550 | ctlcheck('M', CTRL_M, 0x0DU); | |
1551 | ctlcheck('N', CTRL_N, 0x0EU); | |
1552 | ctlcheck('O', CTRL_O, 0x0FU); | |
1553 | ctlcheck('P', CTRL_P, 0x10U); | |
1554 | ctlcheck('Q', CTRL_Q, 0x11U); | |
1555 | ctlcheck('R', CTRL_R, 0x12U); | |
1556 | ctlcheck('S', CTRL_S, 0x13U); | |
1557 | ctlcheck('T', CTRL_T, 0x14U); | |
1558 | ctlcheck('U', CTRL_U, 0x15U); | |
1559 | ctlcheck('V', CTRL_V, 0x16U); | |
1560 | ctlcheck('W', CTRL_W, 0x17U); | |
1561 | ctlcheck('X', CTRL_X, 0x18U); | |
1562 | ctlcheck('Y', CTRL_Y, 0x19U); | |
1563 | ctlcheck('Z', CTRL_Z, 0x1AU); | |
1564 | ctlcheck('[', CTRL_BO, 0x1BU); | |
1565 | ctlcheck('\\', CTRL_BK, 0x1CU); | |
1566 | ctlcheck(']', CTRL_BC, 0x1DU); | |
1567 | ctlcheck('^', CTRL_CA, 0x1EU); | |
1568 | ctlcheck('_', CTRL_US, 0x1FU); | |
1569 | ctlcheck('?', CTRL_QM, 0x7FU); | |
1570 | #undef ctlcheck | |
1571 | } | |
1572 | ||
1573 | /* pre-initio() */ | |
1574 | static void | |
1575 | ebcdic_initerr(const char *s, size_t n, int a, int b, int c) | |
1576 | { | |
1577 | char buf[NUMBUFSZ + 3]; | |
1578 | char *cp; | |
1579 | const char *ccp; | |
1580 | ||
1581 | SHIKATANAI write(2, s, n); | |
1582 | /* | |
1583 | * a>=0: a,b,c=hex | |
1584 | * a=-1: b=sgn c=errno | |
1585 | * a=-2: b=hex c=hex | |
1586 | * a=-3: b=chr c=hex | |
1587 | */ | |
1588 | if (a == -1) { | |
1589 | ccp = cstrerror(c); | |
1590 | cp = kslfmt(b, FL_SGN, buf + 1U); | |
1591 | *--cp = '<'; | |
1592 | buf[NUMBUFSZ] = '>'; | |
1593 | buf[NUMBUFSZ + 1U] = ccp ? '<' : '('; | |
1594 | SHIKATANAI write(2, cp, NUMBUFLEN(buf + 1U, cp) + 2U); | |
1595 | if (ccp) { | |
1596 | SHIKATANAI write(2, SZ(ccp)); | |
1597 | SHIKATANAI write(2, SC(">\n")); | |
1598 | } else | |
1599 | SHIKATANAI write(2, SC("unknown error)\n")); | |
1484 | 1600 | exit(255); |
1485 | 1601 | } |
1486 | /* validate sh.h control character literals */ | |
1487 | if (rtt2asc(CTRL_AT) != 0x00U || | |
1488 | rtt2asc(CTRL_A) != 0x01U || | |
1489 | rtt2asc(CTRL_B) != 0x02U || | |
1490 | rtt2asc(CTRL_C) != 0x03U || | |
1491 | rtt2asc(CTRL_D) != 0x04U || | |
1492 | rtt2asc(CTRL_E) != 0x05U || | |
1493 | rtt2asc(CTRL_F) != 0x06U || | |
1494 | rtt2asc(CTRL_G) != 0x07U || | |
1495 | rtt2asc(CTRL_H) != 0x08U || | |
1496 | rtt2asc(CTRL_I) != 0x09U || | |
1497 | rtt2asc(CTRL_J) != 0x0AU || | |
1498 | rtt2asc(CTRL_K) != 0x0BU || | |
1499 | rtt2asc(CTRL_L) != 0x0CU || | |
1500 | rtt2asc(CTRL_M) != 0x0DU || | |
1501 | rtt2asc(CTRL_N) != 0x0EU || | |
1502 | rtt2asc(CTRL_O) != 0x0FU || | |
1503 | rtt2asc(CTRL_P) != 0x10U || | |
1504 | rtt2asc(CTRL_Q) != 0x11U || | |
1505 | rtt2asc(CTRL_R) != 0x12U || | |
1506 | rtt2asc(CTRL_S) != 0x13U || | |
1507 | rtt2asc(CTRL_T) != 0x14U || | |
1508 | rtt2asc(CTRL_U) != 0x15U || | |
1509 | rtt2asc(CTRL_V) != 0x16U || | |
1510 | rtt2asc(CTRL_W) != 0x17U || | |
1511 | rtt2asc(CTRL_X) != 0x18U || | |
1512 | rtt2asc(CTRL_Y) != 0x19U || | |
1513 | rtt2asc(CTRL_Z) != 0x1AU || | |
1514 | rtt2asc(CTRL_BO) != 0x1BU || | |
1515 | rtt2asc(CTRL_BK) != 0x1CU || | |
1516 | rtt2asc(CTRL_BC) != 0x1DU || | |
1517 | rtt2asc(CTRL_CA) != 0x1EU || | |
1518 | rtt2asc(CTRL_US) != 0x1FU || | |
1519 | rtt2asc(CTRL_QM) != 0x7FU) | |
1520 | goto ebcdic_ctrlmis; | |
1602 | if (a == -3) { | |
1603 | buf[0] = '<'; | |
1604 | buf[1] = b; | |
1605 | buf[2] = '>'; | |
1606 | SHIKATANAI write(2, buf, 3); | |
1607 | } else { | |
1608 | if (a != -2) { | |
1609 | cp = kslfmt(a, FL_HEX | FL_UCASE | FL_HASH, buf + 1); | |
1610 | *--cp = '<'; | |
1611 | buf[NUMBUFSZ] = '>'; | |
1612 | SHIKATANAI write(2, cp, NUMBUFLEN(buf + 1U, cp) + 1U); | |
1613 | } | |
1614 | cp = kslfmt(b, FL_HEX | FL_UCASE | FL_HASH, buf + 1); | |
1615 | *--cp = '<'; | |
1616 | buf[NUMBUFSZ] = '>'; | |
1617 | SHIKATANAI write(2, cp, NUMBUFLEN(buf + 1U, cp) + 1U); | |
1618 | } | |
1619 | cp = kslfmt(c, FL_HEX | FL_UCASE | FL_HASH, buf + 1); | |
1620 | *--cp = '<'; | |
1621 | buf[NUMBUFSZ] = '>'; | |
1622 | buf[NUMBUFSZ + 1U] = '\n'; | |
1623 | SHIKATANAI write(2, cp, NUMBUFLEN(buf + 1U, cp) + 2U); | |
1624 | exit(255); | |
1521 | 1625 | } |
1522 | 1626 | #endif |
1523 | 1627 | |
1528 | 1632 | * style, or anything really. |
1529 | 1633 | */ |
1530 | 1634 | |
1635 | /* pre-initio() */ | |
1531 | 1636 | static unsigned int |
1532 | 1637 | v(unsigned int c) |
1533 | 1638 | { |
1554 | 1659 | |
1555 | 1660 | static struct ciname { |
1556 | 1661 | const char *name; |
1557 | uint32_t val; | |
1558 | uint32_t bit; | |
1662 | kui val; | |
1663 | kui bit; | |
1559 | 1664 | } ci[32], *cibit[32]; |
1560 | 1665 | |
1666 | /* pre-initio() */ | |
1561 | 1667 | static int |
1562 | 1668 | cicomp(const void *a_, const void *b_) |
1563 | 1669 | { |
1566 | 1672 | return (strcmp(a->name, b->name)); |
1567 | 1673 | } |
1568 | 1674 | |
1675 | /* pre-initio() */ | |
1569 | 1676 | static int |
1570 | 1677 | debug_ccls(void) |
1571 | 1678 | { |
1710 | 1817 | z += strlen(#x); \ |
1711 | 1818 | } \ |
1712 | 1819 | } while (/* CONSTCOND */ 0) |
1713 | printf("// shf.c {{{ begin\n/* fast character classes */\n"); | |
1714 | printf("const uint32_t tpl_ctypes[128] = {\n"); | |
1820 | printf("// shf.c begin {{{\n/* fast character classes */\n"); | |
1821 | printf("const kui tpl_ctypes[128] = {\n"); | |
1715 | 1822 | x = 0, y = 0; /* fsck GCC */ |
1716 | 1823 | for (i = 0; i <= 0x7F; ++i) { |
1717 | 1824 | if (!(i & 0x0F)) { |
1743 | 1850 | } |
1744 | 1851 | } |
1745 | 1852 | #undef D |
1746 | printf("};\n// shf.c }}} end\n\n"); | |
1853 | printf("};\n// shf.c end }}}\n\n"); | |
1747 | 1854 | |
1748 | 1855 | #define putrangef(len,cond,count) do { \ |
1749 | 1856 | for (count = 0; count <= 0xFF; ++count) \ |
1848 | 1955 | } while (/* CONSTCOND */ 0) |
1849 | 1956 | DD("??IFS", CiIFS, CiCNTRL); |
1850 | 1957 | |
1851 | printf("// sh.h {{{ begin\n/*\n * fast character classes\n */\n\n"); | |
1958 | printf("// sh.h begin {{{\n/*\n * fast character classes\n */\n\n"); | |
1852 | 1959 | printf("/* internal types, do not reference */\n\n"); |
1853 | 1960 | |
1854 | 1961 | #define D(x) DD(#x, x, CiIFS) |
1859 | 1966 | printf("/* out of space, but one for *@ would make sense, possibly others */\n\n"); |
1860 | 1967 | |
1861 | 1968 | printf("/* compile-time initialised, ASCII only */\n" |
1862 | "extern const uint32_t tpl_ctypes[128];\n" | |
1969 | "extern const kui tpl_ctypes[128];\n" | |
1863 | 1970 | "/* run-time, contains C_IFS as well, full 2⁸ octet range */\n" |
1864 | "EXTERN uint32_t ksh_ctypes[256];\n" | |
1971 | "EXTERN kui ksh_ctypes[256];\n" | |
1865 | 1972 | "/* first octet of $IFS, for concatenating \"$*\" */\n" |
1866 | 1973 | "EXTERN char ifs0;\n" |
1867 | 1974 | "\n"); |
1980 | 2087 | D(C_TAB, "ASCII horizontal tabulator"); |
1981 | 2088 | D(C_UNDER, "underscore"); |
1982 | 2089 | |
1983 | printf("// sh.h }}} end\n"); | |
2090 | printf("// sh.h end }}}\n"); | |
1984 | 2091 | return (ksh_ctypes[0] == CiNUL); |
1985 | 2092 | } |
1986 | 2093 | #endif |
21 | 21 | * of said person's immediate fault when using the work as intended. |
22 | 22 | */ |
23 | 23 | |
24 | /* to avoid -Wmissing-format-attribute on vwarnf(), which is no candidate */ | |
25 | #define MKSH_SHF_VFPRINTF_NO_GCC_FORMAT_ATTRIBUTE | |
24 | 26 | #include "sh.h" |
25 | 27 | |
26 | __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.133 2021/10/10 21:36:54 tg Exp $"); | |
28 | __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.141 2022/01/06 22:35:04 tg Exp $"); | |
27 | 29 | |
28 | 30 | struct nesting_state { |
29 | 31 | int start_token; /* token than began nesting (eg, FOR) */ |
64 | 66 | static int dbtestp_eval(Test_env *, Test_op, const char *, |
65 | 67 | const char *, bool); |
66 | 68 | static void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN; |
69 | ||
70 | static void vwarnf(unsigned int, int, const char *, va_list); | |
71 | #ifndef MKSH_SMALL | |
72 | static void vwarnf0(unsigned int, int, const char *, va_list) | |
73 | MKSH_A_FORMAT(__printf__, 3, 0); | |
74 | #else | |
75 | #define vwarnf0 vwarnf | |
76 | #endif | |
67 | 77 | |
68 | 78 | static struct op *outtree; /* yyparse output */ |
69 | 79 | static struct nesting_state nesting; /* \n changed to ; */ |
316 | 326 | ACCEPT; |
317 | 327 | if (check_decl_utility) { |
318 | 328 | struct tbl *tt = get_builtin(ident); |
319 | uint32_t flag; | |
329 | kui flag; | |
320 | 330 | |
321 | 331 | flag = tt ? tt->flag : 0; |
322 | 332 | if (flag & DECL_UTIL) |
1053 | 1063 | } |
1054 | 1064 | |
1055 | 1065 | #if HAVE_SELECT |
1056 | ||
1057 | #ifndef EOVERFLOW | |
1058 | #ifdef ERANGE | |
1059 | #define EOVERFLOW ERANGE | |
1060 | #else | |
1061 | #define EOVERFLOW EINVAL | |
1062 | #endif | |
1063 | #endif | |
1064 | ||
1065 | 1066 | bool |
1066 | 1067 | parse_usec(const char *s, struct timeval *tv) |
1067 | 1068 | { |
1178 | 1179 | if (popall) |
1179 | 1180 | goto popnext; |
1180 | 1181 | } |
1182 | ||
1183 | void | |
1184 | yyerror(const char *fmt, ...) | |
1185 | { | |
1186 | va_list ap; | |
1187 | ||
1188 | /* pop aliases and re-reads */ | |
1189 | while (source->type == SALIAS || source->type == SREREAD) | |
1190 | source = source->next; | |
1191 | /* zap pending input */ | |
1192 | source->str = null; | |
1193 | ||
1194 | va_start(ap, fmt); | |
1195 | vwarnf0(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | KWF_NOERRNO, | |
1196 | 0, fmt, ap); | |
1197 | va_end(ap); | |
1198 | unwind(LERROR); | |
1199 | } | |
1200 | ||
1201 | /* used by error reporting functions to print "ksh: .kshrc[25]: " */ | |
1202 | bool | |
1203 | error_prefix(bool fileline) | |
1204 | { | |
1205 | bool kshname_shown = false; | |
1206 | ||
1207 | /* Avoid foo: foo[2]: ... */ | |
1208 | if (!fileline || !source || !source->file || | |
1209 | strcmp(source->file, kshname) != 0) { | |
1210 | kshname_shown = true; | |
1211 | shf_puts(kshname + (isch(*kshname, '-') ? 1 : 0), shl_out); | |
1212 | shf_putc_i(':', shl_out); | |
1213 | shf_putc_i(' ', shl_out); | |
1214 | } | |
1215 | if (fileline && source && source->file != NULL) { | |
1216 | shf_fprintf(shl_out, "%s[%d]: ", source->file, source->errline ? | |
1217 | source->errline : source->line); | |
1218 | source->errline = 0; | |
1219 | } | |
1220 | return (kshname_shown); | |
1221 | } | |
1222 | ||
1223 | /* error reporting functions */ | |
1224 | ||
1225 | static void | |
1226 | vwarnf(unsigned int flags, int verrno, const char *fmt, va_list ap) | |
1227 | { | |
1228 | int rept = 0; | |
1229 | bool show_builtin_argv0 = false; | |
1230 | ||
1231 | if (HAS(flags, KWF_ERROR)) { | |
1232 | if (HAS(flags, KWF_INTERNAL)) | |
1233 | shf_write(SC("internal error: "), shl_out); | |
1234 | else | |
1235 | shf_write(SC("E: "), shl_out); | |
1236 | /* additional things to do on error */ | |
1237 | exstat = flags & KWF_EXSTAT; | |
1238 | if (HAS(flags, KWF_INTERNAL) && trap_exstat != -1) | |
1239 | trap_exstat = exstat; | |
1240 | /* debugging: note that stdout not valid */ | |
1241 | shl_stdout_ok = false; | |
1242 | } else { | |
1243 | if (HAS(flags, KWF_INTERNAL)) | |
1244 | shf_write(SC("internal warning: "), shl_out); | |
1245 | else | |
1246 | shf_write(SC("W: "), shl_out); | |
1247 | } | |
1248 | if (HAS(flags, KWF_BUILTIN) && | |
1249 | /* not set when main() calls parse_args() */ | |
1250 | builtin_argv0 && builtin_argv0 != kshname) | |
1251 | show_builtin_argv0 = true; | |
1252 | if (HAS(flags, KWF_PREFIX) && error_prefix(HAS(flags, KWF_FILELINE)) && | |
1253 | show_builtin_argv0) { | |
1254 | const char *kshbasename; | |
1255 | ||
1256 | kshname_islogin(&kshbasename); | |
1257 | show_builtin_argv0 = strcmp(builtin_argv0, kshbasename) != 0; | |
1258 | } | |
1259 | if (show_builtin_argv0) { | |
1260 | shf_puts(builtin_argv0, shl_out); | |
1261 | shf_putc_i(':', shl_out); | |
1262 | shf_putc_i(' ', shl_out); | |
1263 | } | |
1264 | switch (flags & KWF_MSGMASK) { | |
1265 | default: | |
1266 | #undef shf_vfprintf | |
1267 | shf_vfprintf(shl_out, fmt, ap); | |
1268 | #define shf_vfprintf poisoned_shf_vfprintf | |
1269 | break; | |
1270 | case KWF_THREEMSG: | |
1271 | rept = 2; | |
1272 | if (0) | |
1273 | /* FALLTHROUGH */ | |
1274 | case KWF_TWOMSG: | |
1275 | rept = 1; | |
1276 | /* FALLTHROUGH */ | |
1277 | case KWF_ONEMSG: | |
1278 | while (/* CONSTCOND */ 1) { | |
1279 | shf_puts(fmt ? fmt : Tnil, shl_out); | |
1280 | if (!rept--) | |
1281 | break; | |
1282 | shf_putc_i(':', shl_out); | |
1283 | shf_putc_i(' ', shl_out); | |
1284 | fmt = va_arg(ap, const char *); | |
1285 | } | |
1286 | break; | |
1287 | } | |
1288 | if (!HAS(flags, KWF_NOERRNO)) { | |
1289 | /* compare shf.c */ | |
1290 | #if !HAVE_STRERROR | |
1291 | shf_putc_i(':', shl_out); | |
1292 | shf_putc_i(' ', shl_out); | |
1293 | shf_putsv(cstrerror(verrno), shl_out); | |
1294 | #else | |
1295 | /* may be nil */ | |
1296 | shf_fprintf(shl_out, ": %s", cstrerror(verrno)); | |
1297 | #endif | |
1298 | } | |
1299 | shf_putc_i('\n', shl_out); | |
1300 | shf_flush(shl_out); | |
1301 | } | |
1302 | ||
1303 | #ifndef MKSH_SMALL | |
1304 | static void | |
1305 | vwarnf0(unsigned int flags, int verrno, const char *fmt, va_list ap) | |
1306 | { | |
1307 | return (vwarnf(flags, verrno, fmt, ap)); | |
1308 | } | |
1309 | #endif | |
1310 | ||
1311 | void | |
1312 | kwarnf(unsigned int flags, ...) | |
1313 | { | |
1314 | const char *fmt; | |
1315 | va_list ap; | |
1316 | int verrno; | |
1317 | ||
1318 | verrno = errno; | |
1319 | ||
1320 | va_start(ap, flags); | |
1321 | if (HAS(flags, KWF_VERRNO)) | |
1322 | verrno = va_arg(ap, int); | |
1323 | fmt = va_arg(ap, const char *); | |
1324 | vwarnf(flags, verrno, fmt, ap); | |
1325 | va_end(ap); | |
1326 | if (HAS(flags, KWF_BIUNWIND)) | |
1327 | bi_unwind(0); | |
1328 | } | |
1329 | ||
1330 | #ifndef MKSH_SMALL | |
1331 | void | |
1332 | kwarnf0(unsigned int flags, const char *fmt, ...) | |
1333 | { | |
1334 | va_list ap; | |
1335 | int verrno; | |
1336 | ||
1337 | verrno = errno; | |
1338 | ||
1339 | va_start(ap, fmt); | |
1340 | vwarnf0(flags, verrno, fmt, ap); | |
1341 | va_end(ap); | |
1342 | if (HAS(flags, KWF_BIUNWIND)) | |
1343 | bi_unwind(0); | |
1344 | } | |
1345 | ||
1346 | void | |
1347 | kwarnf1(unsigned int flags, int verrno, const char *fmt, ...) | |
1348 | { | |
1349 | va_list ap; | |
1350 | ||
1351 | va_start(ap, fmt); | |
1352 | vwarnf0(flags, verrno, fmt, ap); | |
1353 | va_end(ap); | |
1354 | if (HAS(flags, KWF_BIUNWIND)) | |
1355 | bi_unwind(0); | |
1356 | } | |
1357 | #endif | |
1358 | ||
1359 | /* presented by lack of portable variadic macros in early C */ | |
1360 | ||
1361 | void | |
1362 | kerrf(unsigned int flags, ...) | |
1363 | { | |
1364 | const char *fmt; | |
1365 | va_list ap; | |
1366 | int verrno; | |
1367 | ||
1368 | verrno = errno; | |
1369 | ||
1370 | va_start(ap, flags); | |
1371 | if (HAS(flags, KWF_VERRNO)) | |
1372 | verrno = va_arg(ap, int); | |
1373 | fmt = va_arg(ap, const char *); | |
1374 | vwarnf(flags, verrno, fmt, ap); | |
1375 | va_end(ap); | |
1376 | unwind(LERROR); | |
1377 | } | |
1378 | ||
1379 | #ifndef MKSH_SMALL | |
1380 | void | |
1381 | kerrf0(unsigned int flags, const char *fmt, ...) | |
1382 | { | |
1383 | va_list ap; | |
1384 | int verrno; | |
1385 | ||
1386 | verrno = errno; | |
1387 | ||
1388 | va_start(ap, fmt); | |
1389 | vwarnf0(flags, verrno, fmt, ap); | |
1390 | va_end(ap); | |
1391 | unwind(LERROR); | |
1392 | } | |
1393 | ||
1394 | #if 0 /* not used */ | |
1395 | void | |
1396 | kerrf1(unsigned int flags, int verrno, const char *fmt, ...) | |
1397 | { | |
1398 | va_list ap; | |
1399 | ||
1400 | va_start(ap, fmt); | |
1401 | vwarnf0(flags, verrno, fmt, ap); | |
1402 | va_end(ap); | |
1403 | unwind(LERROR); | |
1404 | } | |
1405 | #endif | |
1406 | #endif | |
1407 | ||
1408 | /* maybe error, maybe builtin error; use merrf() macro */ | |
1409 | void | |
1410 | merrF(int *ep, unsigned int flags, ...) | |
1411 | { | |
1412 | const char *fmt; | |
1413 | va_list ap; | |
1414 | int verrno; | |
1415 | ||
1416 | verrno = errno; | |
1417 | ||
1418 | if (ep) | |
1419 | flags |= KWF_BUILTIN; | |
1420 | ||
1421 | va_start(ap, flags); | |
1422 | if (HAS(flags, KWF_VERRNO)) | |
1423 | verrno = va_arg(ap, int); | |
1424 | fmt = va_arg(ap, const char *); | |
1425 | vwarnf(flags, verrno, fmt, ap); | |
1426 | va_end(ap); | |
1427 | ||
1428 | if (ep) { | |
1429 | *ep = exstat; | |
1430 | bi_unwind(0); | |
1431 | } else | |
1432 | unwind(LERROR); | |
1433 | } | |
1434 | ||
1435 | /* transform warning into bi_errorf */ | |
1436 | void | |
1437 | bi_unwind(int rc) | |
1438 | { | |
1439 | if (rc) | |
1440 | exstat = rc; | |
1441 | /* debugging: note that stdout not valid */ | |
1442 | shl_stdout_ok = false; | |
1443 | ||
1444 | /* POSIX special builtins cause non-interactive shells to exit */ | |
1445 | if (builtin_spec) { | |
1446 | builtin_argv0 = NULL; | |
1447 | /* may not want to use LERROR here */ | |
1448 | unwind(LERROR); | |
1449 | } | |
1450 | } | |
1451 | ||
1452 | /*XXX old */ | |
1453 | void | |
1454 | bi_errorf(const char *fmt, ...) | |
1455 | { | |
1456 | va_list ap; | |
1457 | ||
1458 | va_start(ap, fmt); | |
1459 | vwarnf0(/*XXX*/ KWF_BIERR | KWF_NOERRNO, /*XXX*/ 0, fmt, ap); | |
1460 | va_end(ap); | |
1461 | bi_unwind(0); | |
1462 | } |
22 | 22 | |
23 | 23 | #include "sh.h" |
24 | 24 | |
25 | __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.111 2021/10/16 02:20:02 tg Exp $"); | |
25 | __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.112 2021/11/12 05:06:03 tg Exp $"); | |
26 | 26 | |
27 | 27 | #define INDENT 8 |
28 | 28 | |
183 | 183 | fptreef(shf, indent, "%Nesac "); |
184 | 184 | break; |
185 | 185 | case TELIF: |
186 | internal_errorf(TELIF_unexpected); | |
186 | kerrf(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_ONEMSG | KWF_NOERRNO, | |
187 | TELIF_unexpected); | |
187 | 188 | /* FALLTHROUGH */ |
188 | 189 | case TIF: |
189 | 190 | i = 2; |
284 | 285 | shf_putc('\n', &ptree_heredoc); |
285 | 286 | shf_puts(iop->heredoc, &ptree_heredoc); |
286 | 287 | /* iop->delim is set before iop->heredoc */ |
287 | shf_puts(evalstr(iop->delim, 0), &ptree_heredoc); | |
288 | shf_putsv(evalstr(iop->delim, 0), &ptree_heredoc); | |
288 | 289 | } |
289 | 290 | ioheredelim: |
290 | 291 | /* delim is NULL during syntax error printing */ |
480 | 481 | switch ((c = ord(*fmt++))) { |
481 | 482 | case ORD('s'): |
482 | 483 | /* string */ |
483 | shf_puts(va_arg(va, char *), shf); | |
484 | shf_putsv(va_arg(va, char *), shf); | |
484 | 485 | break; |
485 | 486 | case ORD('S'): |
486 | 487 | /* word */ |
668 | 669 | nest--; |
669 | 670 | break; |
670 | 671 | default: |
671 | internal_warningf( | |
672 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, | |
672 | 673 | "wdscan: unknown char 0x%X (carrying on)", |
673 | (unsigned char)wp[-1]); | |
674 | KBI(wp[-1])); | |
674 | 675 | } |
675 | 676 | } |
676 | 677 | |
1249 | 1250 | ++nesting; |
1250 | 1251 | shf_puts("{tree:" /*}*/, shf); |
1251 | 1252 | if (t == NULL) { |
1252 | name = "(null)"; | |
1253 | name = Tnil; | |
1253 | 1254 | goto out; |
1254 | 1255 | } |
1255 | 1256 | dumpioact(shf, t); |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
4 | 4 | * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, |
5 | * 2019, 2020 | |
5 | * 2019, 2020, 2021 | |
6 | 6 | * mirabilos <m@mirbsd.org> |
7 | 7 | * |
8 | 8 | * Provided that these terms and disclaimer and all copyright notices |
23 | 23 | |
24 | 24 | #include "sh.h" |
25 | 25 | |
26 | __RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.3 2020/07/24 21:08:26 tg Exp $"); | |
26 | __RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.4 2021/11/12 05:06:03 tg Exp $"); | |
27 | 27 | |
28 | 28 | #define SOFT 0x1 |
29 | 29 | #define HARD 0x2 |
231 | 231 | /* silently accept */ |
232 | 232 | return 0; |
233 | 233 | #endif |
234 | internal_warningf("ulimit: %c", what); | |
234 | kwarnf0(KWF_INTERNAL | KWF_WARNING | KWF_NOERRNO, "ulimit: %c", what); | |
235 | 235 | return (1); |
236 | 236 | found: |
237 | 237 | if (wp[builtin_opt.optind]) { |
309 | 309 | #else |
310 | 310 | if (l->writable == false) { |
311 | 311 | /* check.t:ulimit-2 fails if we return 1 and/or do: |
312 | bi_errorf(Tf_ro, l->name); | |
312 | bi_errorf(Tread_only ": %s", l->name); | |
313 | 313 | */ |
314 | 314 | return (0); |
315 | 315 | } |
2 | 2 | /*- |
3 | 3 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | 4 | * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, |
5 | * 2019, 2021 | |
5 | * 2019, 2021, 2022 | |
6 | 6 | * mirabilos <m@mirbsd.org> |
7 | 7 | * |
8 | 8 | * Provided that these terms and disclaimer and all copyright notices |
35 | 35 | #include <sys/ptem.h> |
36 | 36 | #endif |
37 | 37 | |
38 | __RCSID("$MirOS: src/bin/mksh/var.c,v 1.252 2021/09/30 03:20:12 tg Exp $"); | |
38 | __RCSID("$MirOS: src/bin/mksh/var.c,v 1.264 2022/01/28 10:28:22 tg Exp $"); | |
39 | 39 | |
40 | 40 | /*- |
41 | 41 | * Variables |
48 | 48 | */ |
49 | 49 | |
50 | 50 | static struct table specials; |
51 | static uint32_t lcg_state = 5381, qh_state = 4711; | |
51 | static k32 lcg_state = 5381U, qh_state = 4711U; | |
52 | 52 | /* may only be set by typeset() just before call to array_index_calc() */ |
53 | 53 | static enum namerefflag innermost_refflag = SRF_NOP; |
54 | 54 | |
60 | 60 | mksh_uari_t u; |
61 | 61 | } mksh_ari_u; |
62 | 62 | |
63 | static void c_typeset_vardump(struct tbl *, uint32_t, int, int, bool, bool); | |
64 | static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool, | |
63 | static void c_typeset_vardump(struct tbl *, kui, int, int, bool, bool); | |
64 | static void c_typeset_vardump_recursive(struct block *, kui, int, bool, | |
65 | 65 | bool); |
66 | 66 | static char *formatstr(struct tbl *, const char *); |
67 | 67 | static void exportprep(struct tbl *, const char *, size_t); |
72 | 72 | static void unsetspec(struct tbl *, bool); |
73 | 73 | static int getint(struct tbl *, mksh_ari_u *, bool); |
74 | 74 | static int getnum(const char *, mksh_ari_u *, bool, bool); |
75 | static const char *array_index_calc(const char *, bool *, uint32_t *); | |
76 | static struct tbl *vtypeset(int *, const char *, uint32_t, uint32_t, int, int); | |
75 | static const char *array_index_calc(const char *, bool *, k32 *); | |
76 | static struct tbl *vtypeset(int *, const char *, kui, kui, int, int); | |
77 | 77 | |
78 | 78 | /* |
79 | 79 | * create a new block for function calls and simple commands |
80 | 80 | * assume caller has allocated and set up e->loc |
81 | 81 | */ |
82 | /* pre-initio() */ | |
82 | 83 | void |
83 | 84 | newblock(void) |
84 | 85 | { |
165 | 166 | |
166 | 167 | /* common code for several functions below and c_typeset() */ |
167 | 168 | struct block * |
168 | varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) | |
169 | varsearch(struct block *l, struct tbl **vpp, const char *vn, k32 h) | |
169 | 170 | { |
170 | 171 | register struct tbl *vp; |
171 | 172 | |
186 | 187 | |
187 | 188 | /* |
188 | 189 | * Used to calculate an array index for global()/local(). Sets *arrayp |
189 | * to true if this is an array, sets *valp to the array index, returns | |
190 | * to true if this is an array, sets *idxp to the array index, returns | |
190 | 191 | * the basename of the array. May only be called from global()/local() |
191 | 192 | * and must be their first callee. |
192 | 193 | */ |
193 | 194 | static const char * |
194 | array_index_calc(const char *n, bool *arrayp, uint32_t *valp) | |
195 | array_index_calc(const char *n, bool *arrayp, k32 *idxp) | |
195 | 196 | { |
196 | 197 | const char *p; |
197 | 198 | size_t len; |
200 | 201 | *arrayp = false; |
201 | 202 | redo_from_ref: |
202 | 203 | p = skip_varname(n, false); |
204 | if ((size_t)(p - n) > (size_t)(INT_MAX - X_EXTRA)) | |
205 | kerrf(KWF_ERR(255) | KWF_PREFIX | KWF_FILELINE | KWF_ONEMSG | | |
206 | KWF_NOERRNO, "parameter name too long"); | |
203 | 207 | if (innermost_refflag == SRF_NOP && (p != n) && ctype(n[0], C_ALPHX)) { |
204 | 208 | struct tbl *vp; |
205 | 209 | char *vn; |
223 | 227 | |
224 | 228 | if (p != n && ord(*p) == ORD('[') && (len = array_ref_len(p))) { |
225 | 229 | char *sub, *tmp; |
226 | mksh_ari_t rval; | |
230 | mksh_ari_u rval; | |
227 | 231 | size_t tmplen = p - n; |
228 | 232 | |
229 | 233 | /* calculate the value of the subscript */ |
233 | 237 | memcpy(tmp, p + 1, len); |
234 | 238 | tmp[len] = '\0'; |
235 | 239 | sub = substitute(tmp, 0); |
236 | evaluate(sub, &rval, KSH_UNWIND_ERROR, true); | |
237 | *valp = (uint32_t)rval; | |
240 | evaluate(sub, &rval.i, KSH_UNWIND_ERROR, true); | |
241 | *idxp = K32(rval.u); | |
238 | 242 | afree(sub, ATEMP); |
239 | 243 | memcpy(tmp, n, tmplen); |
240 | 244 | tmp[tmplen] = '\0'; |
262 | 266 | struct block *l = e->loc; |
263 | 267 | int c; |
264 | 268 | bool array; |
265 | uint32_t h, val; | |
269 | k32 h; | |
270 | k32 idx; | |
266 | 271 | |
267 | 272 | /* |
268 | 273 | * check to see if this is an array; |
269 | 274 | * dereference namerefs; must come first |
270 | 275 | */ |
271 | vn = array_index_calc(n, &array, &val); | |
276 | vn = array_index_calc(n, &array, &idx); | |
272 | 277 | h = hash(vn); |
273 | 278 | c = (unsigned char)vn[0]; |
274 | 279 | if (!ctype(c, C_ALPHX)) { |
275 | 280 | if (array) |
276 | errorf(Tbadsubst); | |
281 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
282 | KWF_ONEMSG | KWF_NOERRNO, Tbadsubst); | |
277 | 283 | vp = vtemp; |
278 | 284 | vp->flag = DEFINED; |
279 | 285 | vp->type = 0; |
329 | 335 | docreate = false; |
330 | 336 | if (vp != NULL) { |
331 | 337 | if (array) |
332 | vp = arraysearch(vp, val); | |
338 | vp = arraysearch(vp, idx); | |
333 | 339 | if (docreate) { |
334 | 340 | vp->flag |= DEFINED; |
335 | 341 | if (special(vn)) |
353 | 359 | union mksh_cchack vname; |
354 | 360 | struct block *l = e->loc; |
355 | 361 | bool array; |
356 | uint32_t h, val; | |
362 | k32 h; | |
363 | k32 idx; | |
357 | 364 | |
358 | 365 | /* |
359 | 366 | * check to see if this is an array; |
360 | 367 | * dereference namerefs; must come first |
361 | 368 | */ |
362 | vn = array_index_calc(n, &array, &val); | |
369 | vn = array_index_calc(n, &array, &idx); | |
363 | 370 | h = hash(vn); |
364 | 371 | if (!ctype(*vn, C_ALPHX)) { |
365 | 372 | vp = vtemp; |
383 | 390 | } |
384 | 391 | } |
385 | 392 | if (array) |
386 | vp = arraysearch(vp, val); | |
393 | vp = arraysearch(vp, idx); | |
387 | 394 | vp->flag |= DEFINED; |
388 | 395 | if (special(vn)) |
389 | 396 | vp->flag |= SPECIAL; |
472 | 479 | |
473 | 480 | error_ok &= ~0x4; |
474 | 481 | if ((vq->flag & RDONLY) && !no_ro_check) { |
475 | warningf(true, Tf_ro, vq->name); | |
482 | kwarnf((error_ok ? KWF_WARNING : KWF_ERR(2)) | KWF_PREFIX | | |
483 | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
484 | Tread_only, vq->name); | |
476 | 485 | if (!error_ok) |
477 | errorfxz(2); | |
486 | unwind(LERROR); | |
478 | 487 | return (0); |
479 | 488 | } |
480 | 489 | if (!(vq->flag&INTEGER)) { |
486 | 495 | #ifndef MKSH_SMALL |
487 | 496 | /* debugging */ |
488 | 497 | if (s >= vq->val.s && s < (vq->val.s + cursz)) { |
489 | internal_errorf( | |
498 | kerrf0(KWF_INTERNAL | KWF_ERR(0xFF) | KWF_NOERRNO, | |
490 | 499 | "setstr: %s=%s: assigning to self", |
491 | 500 | vq->name, s); |
492 | 501 | } |
542 | 551 | if (vp->flag & SPECIAL) |
543 | 552 | getspec(vp); |
544 | 553 | /* XXX is it possible for ISSET to be set and val.s to be NULL? */ |
545 | if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL)) | |
554 | if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL)) { | |
555 | errno = EINVAL; | |
546 | 556 | return (-1); |
557 | } | |
547 | 558 | if (vp->flag & INTEGER) { |
548 | 559 | nump->i = vp->val.i; |
549 | 560 | return (vp->type); |
572 | 583 | } |
573 | 584 | |
574 | 585 | if (c == '0' && arith) { |
575 | if (ksh_eq(s[0], 'X', 'x')) { | |
586 | if (isCh(s[0], 'X', 'x')) { | |
576 | 587 | /* interpret as hexadecimal */ |
577 | 588 | base = 16; |
578 | 589 | ++s; |
589 | 600 | do { |
590 | 601 | if (c == '#') { |
591 | 602 | /* ksh-style base determination */ |
592 | if (have_base || num < 1) | |
603 | if (have_base || num < 1) { | |
604 | errno = EINVAL; | |
593 | 605 | return (-1); |
606 | } | |
594 | 607 | if ((base = num) == 1) { |
595 | 608 | /* mksh-specific extension */ |
596 | 609 | unsigned int wc; |
610 | 623 | c = ksh_numuc(c) + 10; |
611 | 624 | else if (ctype(c, C_LOWER)) |
612 | 625 | c = ksh_numlc(c) + 10; |
613 | else | |
626 | else { | |
627 | errno = EINVAL; | |
614 | 628 | return (-1); |
615 | if (c >= base) | |
629 | } | |
630 | if (c >= base) { | |
631 | errno = EINVAL; | |
616 | 632 | return (-1); |
633 | } | |
617 | 634 | /* handle overflow as truncation */ |
618 | 635 | num = num * base + c; |
619 | 636 | } while ((c = (unsigned char)*s++)); |
664 | 681 | static char * |
665 | 682 | formatstr(struct tbl *vp, const char *s) |
666 | 683 | { |
667 | int olen, nlen; | |
668 | 684 | char *p, *q; |
669 | size_t psiz; | |
670 | ||
671 | olen = (int)utf_mbswidth(s); | |
672 | ||
673 | if (vp->flag & (RJUST|LJUST)) { | |
685 | ||
686 | if (vp->flag & (RJUST | LJUST)) { | |
687 | int slen, nlen; | |
688 | size_t psiz; | |
689 | ||
690 | psiz = utf_mbswidth(s); | |
691 | if (psiz > (size_t)INT_MAX) { | |
692 | errno = EOVERFLOW; | |
693 | kerrf0(KWF_ERR(0xFF) | KWF_PREFIX | KWF_FILELINE, | |
694 | "string width %zu", psiz); | |
695 | } | |
696 | slen = (int)psiz; | |
674 | 697 | if (!vp->u2.field) |
675 | 698 | /* default field width */ |
676 | vp->u2.field = olen; | |
699 | vp->u2.field = slen; | |
677 | 700 | nlen = vp->u2.field; |
678 | } else | |
679 | nlen = olen; | |
680 | ||
681 | p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); | |
682 | if (vp->flag & (RJUST|LJUST)) { | |
683 | int slen = olen; | |
701 | ||
702 | p = alloc2(nlen + 1, /* MB_LEN_MAX */ 4, ATEMP); | |
703 | psiz = ((size_t)nlen + 1U) * 4U; | |
684 | 704 | |
685 | 705 | if (vp->flag & RJUST) { |
686 | 706 | const char *qq; |
728 | 748 | vp->u2.field, vp->u2.field, s); |
729 | 749 | } |
730 | 750 | } else |
731 | memcpy(p, s, strlen(s) + 1); | |
751 | strdupx(p, s, ATEMP); | |
732 | 752 | |
733 | 753 | if (vp->flag & UCASEV_AL) { |
734 | 754 | for (q = p; *q; q++) |
766 | 786 | * UCASEV_AL), and optionally set its value if an assignment. |
767 | 787 | */ |
768 | 788 | struct tbl * |
769 | typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) | |
789 | typeset(const char *var, kui set, kui clr, int field, int base) | |
770 | 790 | { |
771 | 791 | return (vtypeset(NULL, var, set, clr, field, base)); |
772 | 792 | } |
773 | 793 | static struct tbl * |
774 | vtypeset(int *ep, const char *var, uint32_t set, uint32_t clr, | |
794 | vtypeset(int *ep, const char *var, kui set, kui clr, | |
775 | 795 | int field, int base) |
776 | 796 | { |
777 | 797 | struct tbl *vp; |
802 | 822 | } |
803 | 823 | if (ord(*val) == ORD('[')) { |
804 | 824 | if (new_refflag != SRF_NOP) |
805 | return (maybe_errorf(ep, 1, Tf_sD_s, var, | |
806 | "reference variable can't be an array"), NULL); | |
825 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
826 | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
827 | var, "reference variable can't be an array")); | |
807 | 828 | len = array_ref_len(val); |
808 | 829 | if (len < 3) |
809 | 830 | return (NULL); |
861 | 882 | |
862 | 883 | /* bail out on 'nameref foo+=bar' */ |
863 | 884 | if (vappend) |
864 | return (maybe_errorf(ep, 1, | |
865 | "appending not allowed for nameref"), NULL); | |
885 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
886 | KWF_FILELINE | KWF_ONEMSG | KWF_NOERRNO, | |
887 | "appending not allowed for nameref")); | |
866 | 888 | /* find value if variable already exists */ |
867 | 889 | if ((qval = val) == NULL) { |
868 | 890 | varsearch(e->loc, &vp, tvar, hash(tvar)); |
888 | 910 | goto nameref_rhs_checked; |
889 | 911 | } |
890 | 912 | nameref_empty: |
891 | return (maybe_errorf(ep, 1, Tf_sD_s, var, | |
892 | "empty nameref target"), NULL); | |
913 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
914 | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
915 | var, "empty nameref target")); | |
893 | 916 | } |
894 | 917 | len = (ord(*ccp) == ORD('[')) ? array_ref_len(ccp) : 0; |
895 | 918 | if (ccp[len]) { |
898 | 921 | * junk after it" and "invalid array"; in the |
899 | 922 | * latter case, len is also 0 and points to '[' |
900 | 923 | */ |
901 | return (maybe_errorf(ep, 1, Tf_sD_s, qval, | |
902 | "nameref target not a valid parameter name"), NULL); | |
924 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
925 | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
926 | qval, "nameref target not a valid parameter name")); | |
903 | 927 | } |
904 | 928 | nameref_rhs_checked: |
905 | 929 | /* prevent nameref loops */ |
906 | 930 | while (qval) { |
907 | 931 | if (!strcmp(qval, tvar)) |
908 | return (maybe_errorf(ep, 1, Tf_sD_s, qval, | |
909 | "expression recurses on parameter"), NULL); | |
932 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
933 | KWF_FILELINE | KWF_TWOMSG | KWF_NOERRNO, | |
934 | qval, "expression recurses on parameter")); | |
910 | 935 | varsearch(e->loc, &vp, qval, hash(qval)); |
911 | 936 | qval = NULL; |
912 | 937 | if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC)) |
917 | 942 | /* prevent typeset from creating a local PATH/ENV/SHELL */ |
918 | 943 | if (Flag(FRESTRICTED) && (strcmp(tvar, TPATH) == 0 || |
919 | 944 | strcmp(tvar, TENV) == 0 || strcmp(tvar, TSHELL) == 0)) |
920 | return (maybe_errorf(ep, 1, Tf_sD_s, | |
921 | tvar, "restricted"), NULL); | |
945 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
946 | KWF_TWOMSG | KWF_NOERRNO, tvar, "restricted")); | |
922 | 947 | |
923 | 948 | innermost_refflag = new_refflag; |
924 | 949 | vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : |
952 | 977 | vpbase = (vp->flag & ARRAY) ? arraybase(tvar) : vp; |
953 | 978 | |
954 | 979 | /* |
955 | * only allow export and readonly flag to be set; AT&T ksh | |
980 | * only allow export and read-only flag to be set; AT&T ksh | |
956 | 981 | * allows any attribute to be changed which means it can be |
957 | 982 | * truncated or modified (-L/-R/-Z/-i) |
958 | 983 | */ |
959 | 984 | if ((vpbase->flag & RDONLY) && |
960 | 985 | (val || clr || (set & ~(EXPORT | RDONLY)))) |
961 | return (maybe_errorf(ep, 2, Tf_ro, tvar), NULL); | |
986 | merrf(NULL, (ep, KWF_ERR(2) | KWF_PREFIX | KWF_FILELINE | | |
987 | KWF_TWOMSG | KWF_NOERRNO, Tread_only, tvar)); | |
962 | 988 | if (tvar != tvarbuf) |
963 | 989 | afree(tvar, ATEMP); |
964 | 990 | |
1039 | 1065 | } |
1040 | 1066 | } |
1041 | 1067 | if (!ok) |
1042 | return (maybe_errorf(ep, 1, NULL), NULL); | |
1068 | merrf(NULL, (ep, KWF_ERR(1) | KWF_PREFIX | | |
1069 | KWF_FILELINE | KWF_ONEMSG | KWF_NOERRNO, | |
1070 | "failed to set string value")); | |
1043 | 1071 | } |
1044 | 1072 | |
1045 | 1073 | if (vappend) { |
1064 | 1092 | if (base > 0) |
1065 | 1093 | vp->type = base; |
1066 | 1094 | } else { |
1067 | /* setstr can't fail (readonly check already done) */ | |
1095 | /* setstr can't fail (read-only check already done) */ | |
1068 | 1096 | setstr(vp, val, KSH_RETURN_ERROR | 0x4); |
1069 | 1097 | vp->flag |= (set & IMPORT); |
1070 | 1098 | } |
1224 | 1252 | (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { |
1225 | 1253 | struct block *l2; |
1226 | 1254 | struct tbl *vp2; |
1227 | uint32_t h = hash(vp->name); | |
1255 | k32 h = hash(vp->name); | |
1228 | 1256 | |
1229 | 1257 | /* unexport any redefined instances */ |
1230 | 1258 | for (l2 = l->next; l2 != NULL; l2 = l2->next) { |
1332 | 1360 | |
1333 | 1361 | vp->flag &= ~SPECIAL; |
1334 | 1362 | mksh_TIME(tv); |
1335 | shf_snprintf(buf, sizeof(buf), "%u.%06u", | |
1336 | (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); | |
1337 | setstr(vp, buf, KSH_RETURN_ERROR | 0x4); | |
1363 | if (vp->flag & INTEGER) | |
1364 | setint(vp, (mksh_ari_t)tv.tv_sec); | |
1365 | else { | |
1366 | shf_snprintf(buf, sizeof(buf), "%u.%06u", | |
1367 | (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); | |
1368 | setstr(vp, buf, KSH_RETURN_ERROR | 0x4); | |
1369 | } | |
1338 | 1370 | vp->flag |= SPECIAL; |
1339 | 1371 | return; |
1340 | 1372 | } |
1457 | 1489 | if (getint(vp, &num, false) == -1) { |
1458 | 1490 | s = str_val(vp); |
1459 | 1491 | if (st != V_RANDOM) |
1460 | errorf(Tf_sD_sD_s, vp->name, Tbadnum, s); | |
1492 | kerrf(KWF_ERR(1) | KWF_PREFIX | KWF_FILELINE | | |
1493 | KWF_THREEMSG | KWF_NOERRNO, | |
1494 | vp->name, Tbadnum, s); | |
1461 | 1495 | num.u = hash(s); |
1462 | 1496 | } |
1463 | 1497 | vp->flag |= SPECIAL; |
1589 | 1623 | * vp, indexed by val. |
1590 | 1624 | */ |
1591 | 1625 | struct tbl * |
1592 | arraysearch(struct tbl *vp, uint32_t val) | |
1626 | arraysearch(struct tbl *vp, k32 idx) | |
1593 | 1627 | { |
1594 | 1628 | struct tbl *prev, *curr, *news; |
1595 | 1629 | size_t len; |
1596 | 1630 | |
1597 | 1631 | vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC; |
1598 | 1632 | /* the table entry is always [0] */ |
1599 | if (val == 0) | |
1633 | if (idx == 0) | |
1600 | 1634 | return (vp); |
1601 | 1635 | prev = vp; |
1602 | 1636 | curr = vp->u.array; |
1603 | while (curr && curr->ua.index < val) { | |
1637 | while (curr && curr->ua.index < idx) { | |
1604 | 1638 | prev = curr; |
1605 | 1639 | curr = curr->u.array; |
1606 | 1640 | } |
1607 | if (curr && curr->ua.index == val) { | |
1641 | if (curr && curr->ua.index == idx) { | |
1608 | 1642 | if (curr->flag&ISSET) |
1609 | 1643 | return (curr); |
1610 | 1644 | news = curr; |
1612 | 1646 | news = NULL; |
1613 | 1647 | if (!news) { |
1614 | 1648 | len = strlen(vp->name); |
1615 | checkoktoadd(len, 1 + offsetof(struct tbl, name[0])); | |
1649 | /* no need to checkoktoadd, it comes from a vp->name */ | |
1616 | 1650 | news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap); |
1617 | 1651 | memcpy(news->name, vp->name, len); |
1618 | 1652 | } |
1620 | 1654 | news->type = vp->type; |
1621 | 1655 | news->areap = vp->areap; |
1622 | 1656 | news->u2.field = vp->u2.field; |
1623 | news->ua.index = val; | |
1657 | news->ua.index = idx; | |
1624 | 1658 | |
1625 | 1659 | if (curr != news) { |
1626 | 1660 | /* not reusing old array entry */ |
1696 | 1730 | |
1697 | 1731 | /* Note: AT&T ksh allows set -A but not set +A of a read-only var */ |
1698 | 1732 | if ((vp->flag&RDONLY)) |
1699 | errorfx(2, Tf_ro, ccp); | |
1733 | kerrf(KWF_ERR(2) | KWF_PREFIX | KWF_FILELINE | KWF_TWOMSG | | |
1734 | KWF_NOERRNO, Tread_only, ccp); | |
1700 | 1735 | /* This code is quite non-optimal */ |
1701 | 1736 | if (reset) { |
1702 | 1737 | /* trash existing values and attributes */ |
1747 | 1782 | } |
1748 | 1783 | #endif |
1749 | 1784 | |
1750 | vq = arraysearch(vp, j); | |
1785 | vq = arraysearch(vp, K32(j)); | |
1751 | 1786 | /* would be nice to deal with errors here... (see above) */ |
1752 | 1787 | setstr(vq, ccp, KSH_RETURN_ERROR); |
1753 | 1788 | i++; |
1760 | 1795 | void |
1761 | 1796 | change_winsz(void) |
1762 | 1797 | { |
1763 | struct timeval tv; | |
1764 | ||
1765 | mksh_TIME(tv); | |
1766 | BAFHUpdateMem_mem(qh_state, &tv, sizeof(tv)); | |
1767 | ||
1798 | struct { | |
1799 | struct timeval tv; | |
1768 | 1800 | #ifdef TIOCGWINSZ |
1769 | /* check if window size has changed */ | |
1770 | if (tty_init_fd() < 2) { | |
1771 | 1801 | struct winsize ws; |
1772 | ||
1773 | if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) { | |
1774 | if (ws.ws_col) | |
1775 | x_cols = ws.ws_col; | |
1776 | if (ws.ws_row) | |
1777 | x_lins = ws.ws_row; | |
1802 | int tif; | |
1803 | int ioc; | |
1804 | int eno; | |
1805 | #endif | |
1806 | } z; | |
1807 | ||
1808 | memset(&z, 0, sizeof(z)); | |
1809 | mksh_TIME(z.tv); | |
1810 | ||
1811 | #ifdef TIOCGWINSZ | |
1812 | if ((z.tif = tty_init_fd()) < 2) { | |
1813 | /* check if window size has changed */ | |
1814 | z.ioc = ioctl(tty_fd, TIOCGWINSZ, &z.ws); | |
1815 | z.eno = errno; | |
1816 | if (z.ioc >= 0) { | |
1817 | if (z.ws.ws_col) | |
1818 | x_cols = z.ws.ws_col; | |
1819 | if (z.ws.ws_row) | |
1820 | x_lins = z.ws.ws_row; | |
1778 | 1821 | } |
1779 | 1822 | } |
1780 | 1823 | #endif |
1785 | 1828 | if (x_lins < MIN_LINS) |
1786 | 1829 | x_lins = 24; |
1787 | 1830 | |
1831 | rndpush(&z, sizeof(z)); | |
1788 | 1832 | #ifdef SIGWINCH |
1789 | 1833 | got_winch = 0; |
1790 | 1834 | #endif |
1791 | 1835 | } |
1792 | 1836 | |
1793 | uint32_t | |
1837 | k32 | |
1794 | 1838 | hash(const void *s) |
1795 | 1839 | { |
1796 | register uint32_t h; | |
1840 | register k32 h; | |
1797 | 1841 | |
1798 | 1842 | BAFHInit(h); |
1799 | BAFHUpdateStr_reg(h, s); | |
1800 | BAFHFinish_reg(h); | |
1843 | BAFHUpdateStr(h, s); | |
1844 | BAFHFinish(h); | |
1801 | 1845 | return (h); |
1802 | 1846 | } |
1803 | 1847 | |
1804 | uint32_t | |
1848 | k32 | |
1805 | 1849 | chvt_rndsetup(const void *bp, size_t sz) |
1806 | 1850 | { |
1807 | register uint32_t h; | |
1851 | register k32 h; | |
1808 | 1852 | |
1809 | 1853 | /* use LCG as seed but try to get them to deviate immediately */ |
1810 | 1854 | h = lcg_state; |
1811 | 1855 | (void)rndget(); |
1812 | BAFHFinish_reg(h); | |
1856 | BAFHFinish(h); | |
1813 | 1857 | /* variation through pid, ppid, and the works */ |
1814 | BAFHUpdateMem_reg(h, &rndsetupstate, sizeof(rndsetupstate)); | |
1858 | BAFHUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate)); | |
1815 | 1859 | /* some variation, some possibly entropy, depending on OE */ |
1816 | BAFHUpdateMem_reg(h, bp, sz); | |
1860 | BAFHUpdateMem(h, bp, sz); | |
1817 | 1861 | /* mix them all up */ |
1818 | BAFHFinish_reg(h); | |
1862 | BAFHFinish(h); | |
1819 | 1863 | |
1820 | 1864 | return (h); |
1821 | 1865 | } |
1822 | 1866 | |
1823 | mksh_ari_t | |
1867 | k32 | |
1824 | 1868 | rndget(void) |
1825 | 1869 | { |
1870 | register k32 v = lcg_state; | |
1871 | ||
1826 | 1872 | /* |
1827 | 1873 | * this is the same Linear Congruential PRNG as Borland |
1828 | 1874 | * C/C++ allegedly uses in its built-in rand() function |
1829 | 1875 | */ |
1830 | return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF); | |
1876 | v = K32(22695477U * v + 1U); | |
1877 | lcg_state = v; | |
1878 | return ((k32)(v >> 16) & 0x7FFFU); | |
1831 | 1879 | } |
1832 | 1880 | |
1833 | 1881 | void |
1834 | 1882 | rndset(unsigned long v) |
1835 | 1883 | { |
1836 | register uint32_t h; | |
1884 | register k32 h; | |
1837 | 1885 | #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) |
1838 | register uint32_t t; | |
1886 | register k32 t; | |
1839 | 1887 | #endif |
1840 | 1888 | struct { |
1841 | 1889 | struct timeval tv; |
1842 | 1890 | void *sp; |
1843 | uint32_t qh; | |
1891 | k32 qh; | |
1844 | 1892 | pid_t pp; |
1845 | short r; | |
1893 | unsigned short r; | |
1846 | 1894 | } z; |
1847 | 1895 | |
1848 | 1896 | /* clear the allocated space, for valgrind and to avoid UB */ |
1849 | 1897 | memset(&z, 0, sizeof(z)); |
1850 | 1898 | |
1851 | 1899 | h = lcg_state; |
1852 | BAFHFinish_reg(h); | |
1853 | BAFHUpdateMem_reg(h, &v, sizeof(v)); | |
1900 | BAFHFinish(h); | |
1901 | BAFHUpdateMem(h, &v, sizeof(v)); | |
1854 | 1902 | |
1855 | 1903 | mksh_TIME(z.tv); |
1856 | z.sp = &lcg_state; | |
1904 | z.sp = &z; | |
1857 | 1905 | z.pp = procpid; |
1858 | z.r = (short)rndget(); | |
1906 | z.r = rndget(); | |
1859 | 1907 | |
1860 | 1908 | #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) |
1861 | t = qh_state; | |
1862 | BAFHFinish_reg(t); | |
1863 | z.qh = (t & 0xFFFF8000) | rndget(); | |
1864 | lcg_state = (t << 15) | rndget(); | |
1909 | z.qh = (qh_state & 0xFFFF8000U) | rndget(); | |
1910 | lcg_state = K32(qh_state << 15) | rndget(); | |
1865 | 1911 | /* |
1866 | 1912 | * either we have very chap entropy get and push available, |
1867 | 1913 | * with malloc() pulling in this code already anyway, or the |
1868 | 1914 | * user requested us to use the old functions |
1869 | 1915 | */ |
1870 | 1916 | t = h; |
1871 | BAFHUpdateMem_reg(t, &lcg_state, sizeof(lcg_state)); | |
1872 | BAFHFinish_reg(t); | |
1917 | BAFHUpdateMem(t, &lcg_state, sizeof(lcg_state)); | |
1918 | BAFHFinish(t); | |
1873 | 1919 | lcg_state = t; |
1874 | 1920 | #if defined(arc4random_pushb_fast) |
1875 | 1921 | arc4random_pushb_fast(&lcg_state, sizeof(lcg_state)); |
1877 | 1923 | #else |
1878 | 1924 | lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state)); |
1879 | 1925 | #endif |
1880 | BAFHUpdateMem_reg(h, &lcg_state, sizeof(lcg_state)); | |
1926 | BAFHUpdateMem(h, &lcg_state, sizeof(lcg_state)); | |
1881 | 1927 | #else |
1882 | 1928 | z.qh = qh_state; |
1883 | 1929 | #endif |
1884 | 1930 | |
1885 | BAFHUpdateMem_reg(h, &z, sizeof(z)); | |
1886 | BAFHFinish_reg(h); | |
1931 | BAFHUpdateMem(h, &z, sizeof(z)); | |
1932 | BAFHFinish(h); | |
1887 | 1933 | lcg_state = h; |
1888 | 1934 | } |
1889 | 1935 | |
1890 | 1936 | void |
1891 | rndpush(const void *s) | |
1892 | { | |
1893 | register uint32_t h = qh_state; | |
1894 | ||
1895 | BAFHUpdateStr_reg(h, s); | |
1896 | BAFHUpdateOctet_reg(h, 0); | |
1937 | rndpush(const void *s, size_t n) | |
1938 | { | |
1939 | register k32 h = qh_state; | |
1940 | ||
1941 | BAFHUpdateMem(h, s, n); | |
1942 | BAFHFinish(h); | |
1897 | 1943 | qh_state = h; |
1898 | 1944 | } |
1899 | 1945 | |
1914 | 1960 | c_typeset(const char **wp) |
1915 | 1961 | { |
1916 | 1962 | struct tbl *vp, **p; |
1917 | uint32_t fset = 0, fclr = 0, flag; | |
1963 | kui fset = 0, fclr = 0, flag; | |
1918 | 1964 | int thing = 0, field = 0, base = 0, i; |
1919 | 1965 | struct block *l; |
1920 | 1966 | const char *opts; |
2042 | 2088 | } |
2043 | 2089 | |
2044 | 2090 | if (fieldstr && !getn(fieldstr, &field)) { |
2045 | bi_errorf(Tf_sD_s, Tbadnum, fieldstr); | |
2091 | kwarnf(KWF_BIERR | KWF_TWOMSG, Tbadnum, fieldstr); | |
2046 | 2092 | return (1); |
2047 | 2093 | } |
2048 | 2094 | if (basestr) { |
2049 | 2095 | if (!getn(basestr, &base)) { |
2050 | bi_errorf(Tf_sD_s, "bad integer base", basestr); | |
2096 | kwarnf(KWF_BIERR | KWF_TWOMSG, | |
2097 | "bad integer base", basestr); | |
2051 | 2098 | return (1); |
2052 | 2099 | } |
2053 | 2100 | if (base < 1 || base > 36) |
2064 | 2111 | |
2065 | 2112 | if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) || |
2066 | 2113 | new_refflag != SRF_NOP)) { |
2067 | bi_errorf("only -t, -u and -x options may be used with -f"); | |
2114 | kwarnf(KWF_BIERR | KWF_ONEMSG | KWF_NOERRNO, | |
2115 | "only -t, -u and -x options may be used with -f"); | |
2068 | 2116 | return (1); |
2069 | 2117 | } |
2070 | 2118 | if (wp[builtin_opt.optind]) { |
2133 | 2181 | field, base)) { |
2134 | 2182 | if (x) |
2135 | 2183 | return (x); |
2136 | bi_errorf(Tf_sD_s, wp[i], Tnot_ident); | |
2184 | kwarnf(KWF_BIERR | KWF_TWOMSG | KWF_NOERRNO, | |
2185 | wp[i], Tnot_ident); | |
2137 | 2186 | return (1); |
2138 | 2187 | } |
2139 | 2188 | } |
2170 | 2219 | } |
2171 | 2220 | |
2172 | 2221 | static void |
2173 | c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing, | |
2222 | c_typeset_vardump_recursive(struct block *l, kui flag, int thing, | |
2174 | 2223 | bool pflag, bool istset) |
2175 | 2224 | { |
2176 | 2225 | struct tbl **blockvars, *vp; |
2184 | 2233 | } |
2185 | 2234 | |
2186 | 2235 | static void |
2187 | c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, int any_set, | |
2236 | c_typeset_vardump(struct tbl *vp, kui flag, int thing, int any_set, | |
2188 | 2237 | bool pflag, bool istset) |
2189 | 2238 | { |
2190 | 2239 | struct tbl *tvp; |
2273 | 2322 | } |
2274 | 2323 | shf_puts(vp->name, shl_stdout); |
2275 | 2324 | if (any_set) |
2276 | shprintf("[%lu]", arrayindex(vp)); | |
2325 | shprintf(Tf_SQlu, arrayindex(vp)); | |
2277 | 2326 | if ((!thing && !flag && pflag) || |
2278 | 2327 | (thing == '-' && (vp->flag & ISSET))) { |
2279 | 2328 | shf_putc('=', shl_stdout); |