16d49e1aeSJan Lentfer /* 23ff40c12SJohn Marino * OS specific functions for UNIX/POSIX systems 3*a1157835SDaniel Fojt * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi> 46d49e1aeSJan Lentfer * 53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license. 63ff40c12SJohn Marino * See README for more details. 76d49e1aeSJan Lentfer */ 86d49e1aeSJan Lentfer 96d49e1aeSJan Lentfer #include "includes.h" 106d49e1aeSJan Lentfer 113ff40c12SJohn Marino #include <time.h> 12*a1157835SDaniel Fojt #include <sys/wait.h> 133ff40c12SJohn Marino 143ff40c12SJohn Marino #ifdef ANDROID 153ff40c12SJohn Marino #include <sys/capability.h> 16*a1157835SDaniel Fojt #include <sys/prctl.h> 173ff40c12SJohn Marino #include <private/android_filesystem_config.h> 183ff40c12SJohn Marino #endif /* ANDROID */ 193ff40c12SJohn Marino 20*a1157835SDaniel Fojt #ifdef __MACH__ 21*a1157835SDaniel Fojt #include <CoreServices/CoreServices.h> 22*a1157835SDaniel Fojt #include <mach/mach.h> 23*a1157835SDaniel Fojt #include <mach/mach_time.h> 24*a1157835SDaniel Fojt #endif /* __MACH__ */ 25*a1157835SDaniel Fojt 266d49e1aeSJan Lentfer #include "os.h" 273ff40c12SJohn Marino #include "common.h" 283ff40c12SJohn Marino 293ff40c12SJohn Marino #ifdef WPA_TRACE 303ff40c12SJohn Marino 313ff40c12SJohn Marino #include "wpa_debug.h" 323ff40c12SJohn Marino #include "trace.h" 333ff40c12SJohn Marino #include "list.h" 343ff40c12SJohn Marino 35*a1157835SDaniel Fojt static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list); 363ff40c12SJohn Marino 373ff40c12SJohn Marino #define ALLOC_MAGIC 0xa84ef1b2 383ff40c12SJohn Marino #define FREED_MAGIC 0x67fd487a 393ff40c12SJohn Marino 403ff40c12SJohn Marino struct os_alloc_trace { 413ff40c12SJohn Marino unsigned int magic; 423ff40c12SJohn Marino struct dl_list list; 433ff40c12SJohn Marino size_t len; 443ff40c12SJohn Marino WPA_TRACE_INFO 45*a1157835SDaniel Fojt } __attribute__((aligned(16))); 463ff40c12SJohn Marino 473ff40c12SJohn Marino #endif /* WPA_TRACE */ 483ff40c12SJohn Marino 496d49e1aeSJan Lentfer 506d49e1aeSJan Lentfer void os_sleep(os_time_t sec, os_time_t usec) 516d49e1aeSJan Lentfer { 526d49e1aeSJan Lentfer if (sec) 536d49e1aeSJan Lentfer sleep(sec); 546d49e1aeSJan Lentfer if (usec) 556d49e1aeSJan Lentfer usleep(usec); 566d49e1aeSJan Lentfer } 576d49e1aeSJan Lentfer 586d49e1aeSJan Lentfer 596d49e1aeSJan Lentfer int os_get_time(struct os_time *t) 606d49e1aeSJan Lentfer { 616d49e1aeSJan Lentfer int res; 626d49e1aeSJan Lentfer struct timeval tv; 636d49e1aeSJan Lentfer res = gettimeofday(&tv, NULL); 646d49e1aeSJan Lentfer t->sec = tv.tv_sec; 656d49e1aeSJan Lentfer t->usec = tv.tv_usec; 666d49e1aeSJan Lentfer return res; 676d49e1aeSJan Lentfer } 686d49e1aeSJan Lentfer 696d49e1aeSJan Lentfer 703ff40c12SJohn Marino int os_get_reltime(struct os_reltime *t) 713ff40c12SJohn Marino { 72*a1157835SDaniel Fojt #ifndef __MACH__ 733ff40c12SJohn Marino #if defined(CLOCK_BOOTTIME) 743ff40c12SJohn Marino static clockid_t clock_id = CLOCK_BOOTTIME; 753ff40c12SJohn Marino #elif defined(CLOCK_MONOTONIC) 763ff40c12SJohn Marino static clockid_t clock_id = CLOCK_MONOTONIC; 773ff40c12SJohn Marino #else 783ff40c12SJohn Marino static clockid_t clock_id = CLOCK_REALTIME; 793ff40c12SJohn Marino #endif 803ff40c12SJohn Marino struct timespec ts; 813ff40c12SJohn Marino int res; 823ff40c12SJohn Marino 83*a1157835SDaniel Fojt if (TEST_FAIL()) 84*a1157835SDaniel Fojt return -1; 85*a1157835SDaniel Fojt 863ff40c12SJohn Marino while (1) { 873ff40c12SJohn Marino res = clock_gettime(clock_id, &ts); 883ff40c12SJohn Marino if (res == 0) { 893ff40c12SJohn Marino t->sec = ts.tv_sec; 903ff40c12SJohn Marino t->usec = ts.tv_nsec / 1000; 913ff40c12SJohn Marino return 0; 923ff40c12SJohn Marino } 933ff40c12SJohn Marino switch (clock_id) { 943ff40c12SJohn Marino #ifdef CLOCK_BOOTTIME 953ff40c12SJohn Marino case CLOCK_BOOTTIME: 963ff40c12SJohn Marino clock_id = CLOCK_MONOTONIC; 973ff40c12SJohn Marino break; 983ff40c12SJohn Marino #endif 993ff40c12SJohn Marino #ifdef CLOCK_MONOTONIC 1003ff40c12SJohn Marino case CLOCK_MONOTONIC: 1013ff40c12SJohn Marino clock_id = CLOCK_REALTIME; 1023ff40c12SJohn Marino break; 1033ff40c12SJohn Marino #endif 1043ff40c12SJohn Marino case CLOCK_REALTIME: 1053ff40c12SJohn Marino return -1; 1063ff40c12SJohn Marino } 1073ff40c12SJohn Marino } 108*a1157835SDaniel Fojt #else /* __MACH__ */ 109*a1157835SDaniel Fojt uint64_t abstime, nano; 110*a1157835SDaniel Fojt static mach_timebase_info_data_t info = { 0, 0 }; 111*a1157835SDaniel Fojt 112*a1157835SDaniel Fojt if (!info.denom) { 113*a1157835SDaniel Fojt if (mach_timebase_info(&info) != KERN_SUCCESS) 114*a1157835SDaniel Fojt return -1; 115*a1157835SDaniel Fojt } 116*a1157835SDaniel Fojt 117*a1157835SDaniel Fojt abstime = mach_absolute_time(); 118*a1157835SDaniel Fojt nano = (abstime * info.numer) / info.denom; 119*a1157835SDaniel Fojt 120*a1157835SDaniel Fojt t->sec = nano / NSEC_PER_SEC; 121*a1157835SDaniel Fojt t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC; 122*a1157835SDaniel Fojt 123*a1157835SDaniel Fojt return 0; 124*a1157835SDaniel Fojt #endif /* __MACH__ */ 1253ff40c12SJohn Marino } 1263ff40c12SJohn Marino 1273ff40c12SJohn Marino 1286d49e1aeSJan Lentfer int os_mktime(int year, int month, int day, int hour, int min, int sec, 1296d49e1aeSJan Lentfer os_time_t *t) 1306d49e1aeSJan Lentfer { 1316d49e1aeSJan Lentfer struct tm tm, *tm1; 1326d49e1aeSJan Lentfer time_t t_local, t1, t2; 1336d49e1aeSJan Lentfer os_time_t tz_offset; 1346d49e1aeSJan Lentfer 1356d49e1aeSJan Lentfer if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 1366d49e1aeSJan Lentfer hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 1376d49e1aeSJan Lentfer sec > 60) 1386d49e1aeSJan Lentfer return -1; 1396d49e1aeSJan Lentfer 1406d49e1aeSJan Lentfer memset(&tm, 0, sizeof(tm)); 1416d49e1aeSJan Lentfer tm.tm_year = year - 1900; 1426d49e1aeSJan Lentfer tm.tm_mon = month - 1; 1436d49e1aeSJan Lentfer tm.tm_mday = day; 1446d49e1aeSJan Lentfer tm.tm_hour = hour; 1456d49e1aeSJan Lentfer tm.tm_min = min; 1466d49e1aeSJan Lentfer tm.tm_sec = sec; 1476d49e1aeSJan Lentfer 1486d49e1aeSJan Lentfer t_local = mktime(&tm); 1496d49e1aeSJan Lentfer 1506d49e1aeSJan Lentfer /* figure out offset to UTC */ 1516d49e1aeSJan Lentfer tm1 = localtime(&t_local); 1526d49e1aeSJan Lentfer if (tm1) { 1536d49e1aeSJan Lentfer t1 = mktime(tm1); 1546d49e1aeSJan Lentfer tm1 = gmtime(&t_local); 1556d49e1aeSJan Lentfer if (tm1) { 1566d49e1aeSJan Lentfer t2 = mktime(tm1); 1576d49e1aeSJan Lentfer tz_offset = t2 - t1; 1586d49e1aeSJan Lentfer } else 1596d49e1aeSJan Lentfer tz_offset = 0; 1606d49e1aeSJan Lentfer } else 1616d49e1aeSJan Lentfer tz_offset = 0; 1626d49e1aeSJan Lentfer 1636d49e1aeSJan Lentfer *t = (os_time_t) t_local - tz_offset; 1646d49e1aeSJan Lentfer return 0; 1656d49e1aeSJan Lentfer } 1666d49e1aeSJan Lentfer 1676d49e1aeSJan Lentfer 1683ff40c12SJohn Marino int os_gmtime(os_time_t t, struct os_tm *tm) 1693ff40c12SJohn Marino { 1703ff40c12SJohn Marino struct tm *tm2; 1713ff40c12SJohn Marino time_t t2 = t; 1723ff40c12SJohn Marino 1733ff40c12SJohn Marino tm2 = gmtime(&t2); 1743ff40c12SJohn Marino if (tm2 == NULL) 1753ff40c12SJohn Marino return -1; 1763ff40c12SJohn Marino tm->sec = tm2->tm_sec; 1773ff40c12SJohn Marino tm->min = tm2->tm_min; 1783ff40c12SJohn Marino tm->hour = tm2->tm_hour; 1793ff40c12SJohn Marino tm->day = tm2->tm_mday; 1803ff40c12SJohn Marino tm->month = tm2->tm_mon + 1; 1813ff40c12SJohn Marino tm->year = tm2->tm_year + 1900; 1823ff40c12SJohn Marino return 0; 1833ff40c12SJohn Marino } 1843ff40c12SJohn Marino 1853ff40c12SJohn Marino 1866d49e1aeSJan Lentfer #ifdef __APPLE__ 1876d49e1aeSJan Lentfer #include <fcntl.h> 1886d49e1aeSJan Lentfer static int os_daemon(int nochdir, int noclose) 1896d49e1aeSJan Lentfer { 1906d49e1aeSJan Lentfer int devnull; 1916d49e1aeSJan Lentfer 1926d49e1aeSJan Lentfer if (chdir("/") < 0) 1936d49e1aeSJan Lentfer return -1; 1946d49e1aeSJan Lentfer 1956d49e1aeSJan Lentfer devnull = open("/dev/null", O_RDWR); 1966d49e1aeSJan Lentfer if (devnull < 0) 1976d49e1aeSJan Lentfer return -1; 1986d49e1aeSJan Lentfer 1996d49e1aeSJan Lentfer if (dup2(devnull, STDIN_FILENO) < 0) { 2006d49e1aeSJan Lentfer close(devnull); 2016d49e1aeSJan Lentfer return -1; 2026d49e1aeSJan Lentfer } 2036d49e1aeSJan Lentfer 2046d49e1aeSJan Lentfer if (dup2(devnull, STDOUT_FILENO) < 0) { 2056d49e1aeSJan Lentfer close(devnull); 2066d49e1aeSJan Lentfer return -1; 2076d49e1aeSJan Lentfer } 2086d49e1aeSJan Lentfer 2096d49e1aeSJan Lentfer if (dup2(devnull, STDERR_FILENO) < 0) { 2106d49e1aeSJan Lentfer close(devnull); 2116d49e1aeSJan Lentfer return -1; 2126d49e1aeSJan Lentfer } 2136d49e1aeSJan Lentfer 2146d49e1aeSJan Lentfer return 0; 2156d49e1aeSJan Lentfer } 2166d49e1aeSJan Lentfer #else /* __APPLE__ */ 2176d49e1aeSJan Lentfer #define os_daemon daemon 2186d49e1aeSJan Lentfer #endif /* __APPLE__ */ 2196d49e1aeSJan Lentfer 2206d49e1aeSJan Lentfer 2216d49e1aeSJan Lentfer int os_daemonize(const char *pid_file) 2226d49e1aeSJan Lentfer { 2233ff40c12SJohn Marino #if defined(__uClinux__) || defined(__sun__) 2246d49e1aeSJan Lentfer return -1; 2253ff40c12SJohn Marino #else /* defined(__uClinux__) || defined(__sun__) */ 2266d49e1aeSJan Lentfer if (os_daemon(0, 0)) { 2276d49e1aeSJan Lentfer perror("daemon"); 2286d49e1aeSJan Lentfer return -1; 2296d49e1aeSJan Lentfer } 2306d49e1aeSJan Lentfer 2316d49e1aeSJan Lentfer if (pid_file) { 2326d49e1aeSJan Lentfer FILE *f = fopen(pid_file, "w"); 2336d49e1aeSJan Lentfer if (f) { 2346d49e1aeSJan Lentfer fprintf(f, "%u\n", getpid()); 2356d49e1aeSJan Lentfer fclose(f); 2366d49e1aeSJan Lentfer } 2376d49e1aeSJan Lentfer } 2386d49e1aeSJan Lentfer 2396d49e1aeSJan Lentfer return -0; 2403ff40c12SJohn Marino #endif /* defined(__uClinux__) || defined(__sun__) */ 2416d49e1aeSJan Lentfer } 2426d49e1aeSJan Lentfer 2436d49e1aeSJan Lentfer 2446d49e1aeSJan Lentfer void os_daemonize_terminate(const char *pid_file) 2456d49e1aeSJan Lentfer { 2466d49e1aeSJan Lentfer if (pid_file) 2476d49e1aeSJan Lentfer unlink(pid_file); 2486d49e1aeSJan Lentfer } 2496d49e1aeSJan Lentfer 2506d49e1aeSJan Lentfer 2516d49e1aeSJan Lentfer int os_get_random(unsigned char *buf, size_t len) 2526d49e1aeSJan Lentfer { 253*a1157835SDaniel Fojt #ifdef TEST_FUZZ 254*a1157835SDaniel Fojt size_t i; 255*a1157835SDaniel Fojt 256*a1157835SDaniel Fojt for (i = 0; i < len; i++) 257*a1157835SDaniel Fojt buf[i] = i & 0xff; 258*a1157835SDaniel Fojt return 0; 259*a1157835SDaniel Fojt #else /* TEST_FUZZ */ 2606d49e1aeSJan Lentfer FILE *f; 2616d49e1aeSJan Lentfer size_t rc; 2626d49e1aeSJan Lentfer 263*a1157835SDaniel Fojt if (TEST_FAIL()) 264*a1157835SDaniel Fojt return -1; 265*a1157835SDaniel Fojt 2666d49e1aeSJan Lentfer f = fopen("/dev/urandom", "rb"); 2676d49e1aeSJan Lentfer if (f == NULL) { 2686d49e1aeSJan Lentfer printf("Could not open /dev/urandom.\n"); 2696d49e1aeSJan Lentfer return -1; 2706d49e1aeSJan Lentfer } 2716d49e1aeSJan Lentfer 2726d49e1aeSJan Lentfer rc = fread(buf, 1, len, f); 2736d49e1aeSJan Lentfer fclose(f); 2746d49e1aeSJan Lentfer 2756d49e1aeSJan Lentfer return rc != len ? -1 : 0; 276*a1157835SDaniel Fojt #endif /* TEST_FUZZ */ 2776d49e1aeSJan Lentfer } 2786d49e1aeSJan Lentfer 2796d49e1aeSJan Lentfer 2806d49e1aeSJan Lentfer unsigned long os_random(void) 2816d49e1aeSJan Lentfer { 2826d49e1aeSJan Lentfer return random(); 2836d49e1aeSJan Lentfer } 2846d49e1aeSJan Lentfer 2856d49e1aeSJan Lentfer 2866d49e1aeSJan Lentfer char * os_rel2abs_path(const char *rel_path) 2876d49e1aeSJan Lentfer { 2886d49e1aeSJan Lentfer char *buf = NULL, *cwd, *ret; 2896d49e1aeSJan Lentfer size_t len = 128, cwd_len, rel_len, ret_len; 2906d49e1aeSJan Lentfer int last_errno; 2916d49e1aeSJan Lentfer 2923ff40c12SJohn Marino if (!rel_path) 2933ff40c12SJohn Marino return NULL; 2943ff40c12SJohn Marino 2956d49e1aeSJan Lentfer if (rel_path[0] == '/') 2963ff40c12SJohn Marino return os_strdup(rel_path); 2976d49e1aeSJan Lentfer 2986d49e1aeSJan Lentfer for (;;) { 2993ff40c12SJohn Marino buf = os_malloc(len); 3006d49e1aeSJan Lentfer if (buf == NULL) 3016d49e1aeSJan Lentfer return NULL; 3026d49e1aeSJan Lentfer cwd = getcwd(buf, len); 3036d49e1aeSJan Lentfer if (cwd == NULL) { 3046d49e1aeSJan Lentfer last_errno = errno; 3053ff40c12SJohn Marino os_free(buf); 3066d49e1aeSJan Lentfer if (last_errno != ERANGE) 3076d49e1aeSJan Lentfer return NULL; 3086d49e1aeSJan Lentfer len *= 2; 3096d49e1aeSJan Lentfer if (len > 2000) 3106d49e1aeSJan Lentfer return NULL; 3116d49e1aeSJan Lentfer } else { 3126d49e1aeSJan Lentfer buf[len - 1] = '\0'; 3136d49e1aeSJan Lentfer break; 3146d49e1aeSJan Lentfer } 3156d49e1aeSJan Lentfer } 3166d49e1aeSJan Lentfer 3173ff40c12SJohn Marino cwd_len = os_strlen(cwd); 3183ff40c12SJohn Marino rel_len = os_strlen(rel_path); 3196d49e1aeSJan Lentfer ret_len = cwd_len + 1 + rel_len + 1; 3203ff40c12SJohn Marino ret = os_malloc(ret_len); 3216d49e1aeSJan Lentfer if (ret) { 3223ff40c12SJohn Marino os_memcpy(ret, cwd, cwd_len); 3236d49e1aeSJan Lentfer ret[cwd_len] = '/'; 3243ff40c12SJohn Marino os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 3256d49e1aeSJan Lentfer ret[ret_len - 1] = '\0'; 3266d49e1aeSJan Lentfer } 3273ff40c12SJohn Marino os_free(buf); 3286d49e1aeSJan Lentfer return ret; 3296d49e1aeSJan Lentfer } 3306d49e1aeSJan Lentfer 3316d49e1aeSJan Lentfer 3326d49e1aeSJan Lentfer int os_program_init(void) 3336d49e1aeSJan Lentfer { 3343ff40c12SJohn Marino #ifdef ANDROID 3353ff40c12SJohn Marino /* 3363ff40c12SJohn Marino * We ignore errors here since errors are normal if we 3373ff40c12SJohn Marino * are already running as non-root. 3383ff40c12SJohn Marino */ 3393ff40c12SJohn Marino #ifdef ANDROID_SETGROUPS_OVERRIDE 3403ff40c12SJohn Marino gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; 3413ff40c12SJohn Marino #else /* ANDROID_SETGROUPS_OVERRIDE */ 3423ff40c12SJohn Marino gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; 3433ff40c12SJohn Marino #endif /* ANDROID_SETGROUPS_OVERRIDE */ 3443ff40c12SJohn Marino struct __user_cap_header_struct header; 3453ff40c12SJohn Marino struct __user_cap_data_struct cap; 3463ff40c12SJohn Marino 3473ff40c12SJohn Marino setgroups(ARRAY_SIZE(groups), groups); 3483ff40c12SJohn Marino 3493ff40c12SJohn Marino prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 3503ff40c12SJohn Marino 3513ff40c12SJohn Marino setgid(AID_WIFI); 3523ff40c12SJohn Marino setuid(AID_WIFI); 3533ff40c12SJohn Marino 3543ff40c12SJohn Marino header.version = _LINUX_CAPABILITY_VERSION; 3553ff40c12SJohn Marino header.pid = 0; 3563ff40c12SJohn Marino cap.effective = cap.permitted = 3573ff40c12SJohn Marino (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); 3583ff40c12SJohn Marino cap.inheritable = 0; 3593ff40c12SJohn Marino capset(&header, &cap); 3603ff40c12SJohn Marino #endif /* ANDROID */ 3613ff40c12SJohn Marino 3626d49e1aeSJan Lentfer return 0; 3636d49e1aeSJan Lentfer } 3646d49e1aeSJan Lentfer 3656d49e1aeSJan Lentfer 3666d49e1aeSJan Lentfer void os_program_deinit(void) 3676d49e1aeSJan Lentfer { 3683ff40c12SJohn Marino #ifdef WPA_TRACE 3693ff40c12SJohn Marino struct os_alloc_trace *a; 3703ff40c12SJohn Marino unsigned long total = 0; 3713ff40c12SJohn Marino dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 3723ff40c12SJohn Marino total += a->len; 3733ff40c12SJohn Marino if (a->magic != ALLOC_MAGIC) { 3743ff40c12SJohn Marino wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 3753ff40c12SJohn Marino "len %lu", 3763ff40c12SJohn Marino a, a->magic, (unsigned long) a->len); 3773ff40c12SJohn Marino continue; 3783ff40c12SJohn Marino } 3793ff40c12SJohn Marino wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 3803ff40c12SJohn Marino a, (unsigned long) a->len); 3813ff40c12SJohn Marino wpa_trace_dump("memleak", a); 3823ff40c12SJohn Marino } 3833ff40c12SJohn Marino if (total) 3843ff40c12SJohn Marino wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 3853ff40c12SJohn Marino (unsigned long) total); 386*a1157835SDaniel Fojt wpa_trace_deinit(); 3873ff40c12SJohn Marino #endif /* WPA_TRACE */ 3886d49e1aeSJan Lentfer } 3896d49e1aeSJan Lentfer 3906d49e1aeSJan Lentfer 3916d49e1aeSJan Lentfer int os_setenv(const char *name, const char *value, int overwrite) 3926d49e1aeSJan Lentfer { 3936d49e1aeSJan Lentfer return setenv(name, value, overwrite); 3946d49e1aeSJan Lentfer } 3956d49e1aeSJan Lentfer 3966d49e1aeSJan Lentfer 3976d49e1aeSJan Lentfer int os_unsetenv(const char *name) 3986d49e1aeSJan Lentfer { 3996d49e1aeSJan Lentfer #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 4006d49e1aeSJan Lentfer defined(__OpenBSD__) 4016d49e1aeSJan Lentfer unsetenv(name); 4026d49e1aeSJan Lentfer return 0; 4036d49e1aeSJan Lentfer #else 4046d49e1aeSJan Lentfer return unsetenv(name); 4056d49e1aeSJan Lentfer #endif 4066d49e1aeSJan Lentfer } 4076d49e1aeSJan Lentfer 4086d49e1aeSJan Lentfer 4096d49e1aeSJan Lentfer char * os_readfile(const char *name, size_t *len) 4106d49e1aeSJan Lentfer { 4116d49e1aeSJan Lentfer FILE *f; 4126d49e1aeSJan Lentfer char *buf; 4133ff40c12SJohn Marino long pos; 4146d49e1aeSJan Lentfer 4156d49e1aeSJan Lentfer f = fopen(name, "rb"); 4166d49e1aeSJan Lentfer if (f == NULL) 4176d49e1aeSJan Lentfer return NULL; 4186d49e1aeSJan Lentfer 4193ff40c12SJohn Marino if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { 4203ff40c12SJohn Marino fclose(f); 4213ff40c12SJohn Marino return NULL; 4223ff40c12SJohn Marino } 4233ff40c12SJohn Marino *len = pos; 4243ff40c12SJohn Marino if (fseek(f, 0, SEEK_SET) < 0) { 4253ff40c12SJohn Marino fclose(f); 4263ff40c12SJohn Marino return NULL; 4273ff40c12SJohn Marino } 4286d49e1aeSJan Lentfer 4293ff40c12SJohn Marino buf = os_malloc(*len); 4306d49e1aeSJan Lentfer if (buf == NULL) { 4316d49e1aeSJan Lentfer fclose(f); 4326d49e1aeSJan Lentfer return NULL; 4336d49e1aeSJan Lentfer } 4346d49e1aeSJan Lentfer 4356d49e1aeSJan Lentfer if (fread(buf, 1, *len, f) != *len) { 4366d49e1aeSJan Lentfer fclose(f); 4373ff40c12SJohn Marino os_free(buf); 4386d49e1aeSJan Lentfer return NULL; 4396d49e1aeSJan Lentfer } 4406d49e1aeSJan Lentfer 4416d49e1aeSJan Lentfer fclose(f); 4426d49e1aeSJan Lentfer 4436d49e1aeSJan Lentfer return buf; 4446d49e1aeSJan Lentfer } 4456d49e1aeSJan Lentfer 4466d49e1aeSJan Lentfer 447*a1157835SDaniel Fojt int os_file_exists(const char *fname) 448*a1157835SDaniel Fojt { 449*a1157835SDaniel Fojt return access(fname, F_OK) == 0; 450*a1157835SDaniel Fojt } 451*a1157835SDaniel Fojt 452*a1157835SDaniel Fojt 453*a1157835SDaniel Fojt int os_fdatasync(FILE *stream) 454*a1157835SDaniel Fojt { 455*a1157835SDaniel Fojt if (!fflush(stream)) { 456*a1157835SDaniel Fojt #ifdef __linux__ 457*a1157835SDaniel Fojt return fdatasync(fileno(stream)); 458*a1157835SDaniel Fojt #else /* !__linux__ */ 459*a1157835SDaniel Fojt #ifdef F_FULLFSYNC 460*a1157835SDaniel Fojt /* OS X does not implement fdatasync(). */ 461*a1157835SDaniel Fojt return fcntl(fileno(stream), F_FULLFSYNC); 462*a1157835SDaniel Fojt #else /* F_FULLFSYNC */ 463*a1157835SDaniel Fojt return fsync(fileno(stream)); 464*a1157835SDaniel Fojt #endif /* F_FULLFSYNC */ 465*a1157835SDaniel Fojt #endif /* __linux__ */ 466*a1157835SDaniel Fojt } 467*a1157835SDaniel Fojt 468*a1157835SDaniel Fojt return -1; 469*a1157835SDaniel Fojt } 470*a1157835SDaniel Fojt 471*a1157835SDaniel Fojt 4723ff40c12SJohn Marino #ifndef WPA_TRACE 4736d49e1aeSJan Lentfer void * os_zalloc(size_t size) 4746d49e1aeSJan Lentfer { 4756d49e1aeSJan Lentfer return calloc(1, size); 4766d49e1aeSJan Lentfer } 4773ff40c12SJohn Marino #endif /* WPA_TRACE */ 4786d49e1aeSJan Lentfer 4796d49e1aeSJan Lentfer 4806d49e1aeSJan Lentfer size_t os_strlcpy(char *dest, const char *src, size_t siz) 4816d49e1aeSJan Lentfer { 4826d49e1aeSJan Lentfer const char *s = src; 4836d49e1aeSJan Lentfer size_t left = siz; 4846d49e1aeSJan Lentfer 4856d49e1aeSJan Lentfer if (left) { 4866d49e1aeSJan Lentfer /* Copy string up to the maximum size of the dest buffer */ 4876d49e1aeSJan Lentfer while (--left != 0) { 4886d49e1aeSJan Lentfer if ((*dest++ = *s++) == '\0') 4896d49e1aeSJan Lentfer break; 4906d49e1aeSJan Lentfer } 4916d49e1aeSJan Lentfer } 4926d49e1aeSJan Lentfer 4936d49e1aeSJan Lentfer if (left == 0) { 4946d49e1aeSJan Lentfer /* Not enough room for the string; force NUL-termination */ 4956d49e1aeSJan Lentfer if (siz != 0) 4966d49e1aeSJan Lentfer *dest = '\0'; 4976d49e1aeSJan Lentfer while (*s++) 4986d49e1aeSJan Lentfer ; /* determine total src string length */ 4996d49e1aeSJan Lentfer } 5006d49e1aeSJan Lentfer 5016d49e1aeSJan Lentfer return s - src - 1; 5026d49e1aeSJan Lentfer } 5033ff40c12SJohn Marino 5043ff40c12SJohn Marino 505*a1157835SDaniel Fojt int os_memcmp_const(const void *a, const void *b, size_t len) 506*a1157835SDaniel Fojt { 507*a1157835SDaniel Fojt const u8 *aa = a; 508*a1157835SDaniel Fojt const u8 *bb = b; 509*a1157835SDaniel Fojt size_t i; 510*a1157835SDaniel Fojt u8 res; 511*a1157835SDaniel Fojt 512*a1157835SDaniel Fojt for (res = 0, i = 0; i < len; i++) 513*a1157835SDaniel Fojt res |= aa[i] ^ bb[i]; 514*a1157835SDaniel Fojt 515*a1157835SDaniel Fojt return res; 516*a1157835SDaniel Fojt } 517*a1157835SDaniel Fojt 518*a1157835SDaniel Fojt 519*a1157835SDaniel Fojt void * os_memdup(const void *src, size_t len) 520*a1157835SDaniel Fojt { 521*a1157835SDaniel Fojt void *r = os_malloc(len); 522*a1157835SDaniel Fojt 523*a1157835SDaniel Fojt if (r && src) 524*a1157835SDaniel Fojt os_memcpy(r, src, len); 525*a1157835SDaniel Fojt return r; 526*a1157835SDaniel Fojt } 527*a1157835SDaniel Fojt 528*a1157835SDaniel Fojt 5293ff40c12SJohn Marino #ifdef WPA_TRACE 5303ff40c12SJohn Marino 531*a1157835SDaniel Fojt #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) 532*a1157835SDaniel Fojt char wpa_trace_fail_func[256] = { 0 }; 533*a1157835SDaniel Fojt unsigned int wpa_trace_fail_after; 534*a1157835SDaniel Fojt 535*a1157835SDaniel Fojt static int testing_fail_alloc(void) 536*a1157835SDaniel Fojt { 537*a1157835SDaniel Fojt const char *func[WPA_TRACE_LEN]; 538*a1157835SDaniel Fojt size_t i, res, len; 539*a1157835SDaniel Fojt char *pos, *next; 540*a1157835SDaniel Fojt int match; 541*a1157835SDaniel Fojt 542*a1157835SDaniel Fojt if (!wpa_trace_fail_after) 543*a1157835SDaniel Fojt return 0; 544*a1157835SDaniel Fojt 545*a1157835SDaniel Fojt res = wpa_trace_calling_func(func, WPA_TRACE_LEN); 546*a1157835SDaniel Fojt i = 0; 547*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], __func__) == 0) 548*a1157835SDaniel Fojt i++; 549*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_malloc") == 0) 550*a1157835SDaniel Fojt i++; 551*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_zalloc") == 0) 552*a1157835SDaniel Fojt i++; 553*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_calloc") == 0) 554*a1157835SDaniel Fojt i++; 555*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_realloc") == 0) 556*a1157835SDaniel Fojt i++; 557*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_realloc_array") == 0) 558*a1157835SDaniel Fojt i++; 559*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_strdup") == 0) 560*a1157835SDaniel Fojt i++; 561*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], "os_memdup") == 0) 562*a1157835SDaniel Fojt i++; 563*a1157835SDaniel Fojt 564*a1157835SDaniel Fojt pos = wpa_trace_fail_func; 565*a1157835SDaniel Fojt 566*a1157835SDaniel Fojt match = 0; 567*a1157835SDaniel Fojt while (i < res) { 568*a1157835SDaniel Fojt int allow_skip = 1; 569*a1157835SDaniel Fojt int maybe = 0; 570*a1157835SDaniel Fojt 571*a1157835SDaniel Fojt if (*pos == '=') { 572*a1157835SDaniel Fojt allow_skip = 0; 573*a1157835SDaniel Fojt pos++; 574*a1157835SDaniel Fojt } else if (*pos == '?') { 575*a1157835SDaniel Fojt maybe = 1; 576*a1157835SDaniel Fojt pos++; 577*a1157835SDaniel Fojt } 578*a1157835SDaniel Fojt next = os_strchr(pos, ';'); 579*a1157835SDaniel Fojt if (next) 580*a1157835SDaniel Fojt len = next - pos; 581*a1157835SDaniel Fojt else 582*a1157835SDaniel Fojt len = os_strlen(pos); 583*a1157835SDaniel Fojt if (os_memcmp(pos, func[i], len) != 0) { 584*a1157835SDaniel Fojt if (maybe && next) { 585*a1157835SDaniel Fojt pos = next + 1; 586*a1157835SDaniel Fojt continue; 587*a1157835SDaniel Fojt } 588*a1157835SDaniel Fojt if (allow_skip) { 589*a1157835SDaniel Fojt i++; 590*a1157835SDaniel Fojt continue; 591*a1157835SDaniel Fojt } 592*a1157835SDaniel Fojt return 0; 593*a1157835SDaniel Fojt } 594*a1157835SDaniel Fojt if (!next) { 595*a1157835SDaniel Fojt match = 1; 596*a1157835SDaniel Fojt break; 597*a1157835SDaniel Fojt } 598*a1157835SDaniel Fojt pos = next + 1; 599*a1157835SDaniel Fojt i++; 600*a1157835SDaniel Fojt } 601*a1157835SDaniel Fojt if (!match) 602*a1157835SDaniel Fojt return 0; 603*a1157835SDaniel Fojt 604*a1157835SDaniel Fojt wpa_trace_fail_after--; 605*a1157835SDaniel Fojt if (wpa_trace_fail_after == 0) { 606*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "TESTING: fail allocation at %s", 607*a1157835SDaniel Fojt wpa_trace_fail_func); 608*a1157835SDaniel Fojt for (i = 0; i < res; i++) 609*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "backtrace[%d] = %s", 610*a1157835SDaniel Fojt (int) i, func[i]); 611*a1157835SDaniel Fojt return 1; 612*a1157835SDaniel Fojt } 613*a1157835SDaniel Fojt 614*a1157835SDaniel Fojt return 0; 615*a1157835SDaniel Fojt } 616*a1157835SDaniel Fojt 617*a1157835SDaniel Fojt 618*a1157835SDaniel Fojt char wpa_trace_test_fail_func[256] = { 0 }; 619*a1157835SDaniel Fojt unsigned int wpa_trace_test_fail_after; 620*a1157835SDaniel Fojt 621*a1157835SDaniel Fojt int testing_test_fail(void) 622*a1157835SDaniel Fojt { 623*a1157835SDaniel Fojt const char *func[WPA_TRACE_LEN]; 624*a1157835SDaniel Fojt size_t i, res, len; 625*a1157835SDaniel Fojt char *pos, *next; 626*a1157835SDaniel Fojt int match; 627*a1157835SDaniel Fojt 628*a1157835SDaniel Fojt if (!wpa_trace_test_fail_after) 629*a1157835SDaniel Fojt return 0; 630*a1157835SDaniel Fojt 631*a1157835SDaniel Fojt res = wpa_trace_calling_func(func, WPA_TRACE_LEN); 632*a1157835SDaniel Fojt i = 0; 633*a1157835SDaniel Fojt if (i < res && os_strcmp(func[i], __func__) == 0) 634*a1157835SDaniel Fojt i++; 635*a1157835SDaniel Fojt 636*a1157835SDaniel Fojt pos = wpa_trace_test_fail_func; 637*a1157835SDaniel Fojt 638*a1157835SDaniel Fojt match = 0; 639*a1157835SDaniel Fojt while (i < res) { 640*a1157835SDaniel Fojt int allow_skip = 1; 641*a1157835SDaniel Fojt int maybe = 0; 642*a1157835SDaniel Fojt 643*a1157835SDaniel Fojt if (*pos == '=') { 644*a1157835SDaniel Fojt allow_skip = 0; 645*a1157835SDaniel Fojt pos++; 646*a1157835SDaniel Fojt } else if (*pos == '?') { 647*a1157835SDaniel Fojt maybe = 1; 648*a1157835SDaniel Fojt pos++; 649*a1157835SDaniel Fojt } 650*a1157835SDaniel Fojt next = os_strchr(pos, ';'); 651*a1157835SDaniel Fojt if (next) 652*a1157835SDaniel Fojt len = next - pos; 653*a1157835SDaniel Fojt else 654*a1157835SDaniel Fojt len = os_strlen(pos); 655*a1157835SDaniel Fojt if (os_memcmp(pos, func[i], len) != 0) { 656*a1157835SDaniel Fojt if (maybe && next) { 657*a1157835SDaniel Fojt pos = next + 1; 658*a1157835SDaniel Fojt continue; 659*a1157835SDaniel Fojt } 660*a1157835SDaniel Fojt if (allow_skip) { 661*a1157835SDaniel Fojt i++; 662*a1157835SDaniel Fojt continue; 663*a1157835SDaniel Fojt } 664*a1157835SDaniel Fojt return 0; 665*a1157835SDaniel Fojt } 666*a1157835SDaniel Fojt if (!next) { 667*a1157835SDaniel Fojt match = 1; 668*a1157835SDaniel Fojt break; 669*a1157835SDaniel Fojt } 670*a1157835SDaniel Fojt pos = next + 1; 671*a1157835SDaniel Fojt i++; 672*a1157835SDaniel Fojt } 673*a1157835SDaniel Fojt if (!match) 674*a1157835SDaniel Fojt return 0; 675*a1157835SDaniel Fojt 676*a1157835SDaniel Fojt wpa_trace_test_fail_after--; 677*a1157835SDaniel Fojt if (wpa_trace_test_fail_after == 0) { 678*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "TESTING: fail at %s", 679*a1157835SDaniel Fojt wpa_trace_test_fail_func); 680*a1157835SDaniel Fojt for (i = 0; i < res; i++) 681*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "backtrace[%d] = %s", 682*a1157835SDaniel Fojt (int) i, func[i]); 683*a1157835SDaniel Fojt return 1; 684*a1157835SDaniel Fojt } 685*a1157835SDaniel Fojt 686*a1157835SDaniel Fojt return 0; 687*a1157835SDaniel Fojt } 688*a1157835SDaniel Fojt 689*a1157835SDaniel Fojt #else 690*a1157835SDaniel Fojt 691*a1157835SDaniel Fojt static inline int testing_fail_alloc(void) 692*a1157835SDaniel Fojt { 693*a1157835SDaniel Fojt return 0; 694*a1157835SDaniel Fojt } 695*a1157835SDaniel Fojt #endif 696*a1157835SDaniel Fojt 6973ff40c12SJohn Marino void * os_malloc(size_t size) 6983ff40c12SJohn Marino { 6993ff40c12SJohn Marino struct os_alloc_trace *a; 700*a1157835SDaniel Fojt 701*a1157835SDaniel Fojt if (testing_fail_alloc()) 702*a1157835SDaniel Fojt return NULL; 703*a1157835SDaniel Fojt 7043ff40c12SJohn Marino a = malloc(sizeof(*a) + size); 7053ff40c12SJohn Marino if (a == NULL) 7063ff40c12SJohn Marino return NULL; 7073ff40c12SJohn Marino a->magic = ALLOC_MAGIC; 7083ff40c12SJohn Marino dl_list_add(&alloc_list, &a->list); 7093ff40c12SJohn Marino a->len = size; 7103ff40c12SJohn Marino wpa_trace_record(a); 7113ff40c12SJohn Marino return a + 1; 7123ff40c12SJohn Marino } 7133ff40c12SJohn Marino 7143ff40c12SJohn Marino 7153ff40c12SJohn Marino void * os_realloc(void *ptr, size_t size) 7163ff40c12SJohn Marino { 7173ff40c12SJohn Marino struct os_alloc_trace *a; 7183ff40c12SJohn Marino size_t copy_len; 7193ff40c12SJohn Marino void *n; 7203ff40c12SJohn Marino 7213ff40c12SJohn Marino if (ptr == NULL) 7223ff40c12SJohn Marino return os_malloc(size); 7233ff40c12SJohn Marino 7243ff40c12SJohn Marino a = (struct os_alloc_trace *) ptr - 1; 7253ff40c12SJohn Marino if (a->magic != ALLOC_MAGIC) { 7263ff40c12SJohn Marino wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 7273ff40c12SJohn Marino a, a->magic, 7283ff40c12SJohn Marino a->magic == FREED_MAGIC ? " (already freed)" : ""); 7293ff40c12SJohn Marino wpa_trace_show("Invalid os_realloc() call"); 7303ff40c12SJohn Marino abort(); 7313ff40c12SJohn Marino } 7323ff40c12SJohn Marino n = os_malloc(size); 7333ff40c12SJohn Marino if (n == NULL) 7343ff40c12SJohn Marino return NULL; 7353ff40c12SJohn Marino copy_len = a->len; 7363ff40c12SJohn Marino if (copy_len > size) 7373ff40c12SJohn Marino copy_len = size; 7383ff40c12SJohn Marino os_memcpy(n, a + 1, copy_len); 7393ff40c12SJohn Marino os_free(ptr); 7403ff40c12SJohn Marino return n; 7413ff40c12SJohn Marino } 7423ff40c12SJohn Marino 7433ff40c12SJohn Marino 7443ff40c12SJohn Marino void os_free(void *ptr) 7453ff40c12SJohn Marino { 7463ff40c12SJohn Marino struct os_alloc_trace *a; 7473ff40c12SJohn Marino 7483ff40c12SJohn Marino if (ptr == NULL) 7493ff40c12SJohn Marino return; 7503ff40c12SJohn Marino a = (struct os_alloc_trace *) ptr - 1; 7513ff40c12SJohn Marino if (a->magic != ALLOC_MAGIC) { 7523ff40c12SJohn Marino wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 7533ff40c12SJohn Marino a, a->magic, 7543ff40c12SJohn Marino a->magic == FREED_MAGIC ? " (already freed)" : ""); 7553ff40c12SJohn Marino wpa_trace_show("Invalid os_free() call"); 7563ff40c12SJohn Marino abort(); 7573ff40c12SJohn Marino } 7583ff40c12SJohn Marino dl_list_del(&a->list); 7593ff40c12SJohn Marino a->magic = FREED_MAGIC; 7603ff40c12SJohn Marino 7613ff40c12SJohn Marino wpa_trace_check_ref(ptr); 7623ff40c12SJohn Marino free(a); 7633ff40c12SJohn Marino } 7643ff40c12SJohn Marino 7653ff40c12SJohn Marino 7663ff40c12SJohn Marino void * os_zalloc(size_t size) 7673ff40c12SJohn Marino { 7683ff40c12SJohn Marino void *ptr = os_malloc(size); 7693ff40c12SJohn Marino if (ptr) 7703ff40c12SJohn Marino os_memset(ptr, 0, size); 7713ff40c12SJohn Marino return ptr; 7723ff40c12SJohn Marino } 7733ff40c12SJohn Marino 7743ff40c12SJohn Marino 7753ff40c12SJohn Marino char * os_strdup(const char *s) 7763ff40c12SJohn Marino { 7773ff40c12SJohn Marino size_t len; 7783ff40c12SJohn Marino char *d; 7793ff40c12SJohn Marino len = os_strlen(s); 7803ff40c12SJohn Marino d = os_malloc(len + 1); 7813ff40c12SJohn Marino if (d == NULL) 7823ff40c12SJohn Marino return NULL; 7833ff40c12SJohn Marino os_memcpy(d, s, len); 7843ff40c12SJohn Marino d[len] = '\0'; 7853ff40c12SJohn Marino return d; 7863ff40c12SJohn Marino } 7873ff40c12SJohn Marino 7883ff40c12SJohn Marino #endif /* WPA_TRACE */ 789*a1157835SDaniel Fojt 790*a1157835SDaniel Fojt 791*a1157835SDaniel Fojt int os_exec(const char *program, const char *arg, int wait_completion) 792*a1157835SDaniel Fojt { 793*a1157835SDaniel Fojt pid_t pid; 794*a1157835SDaniel Fojt int pid_status; 795*a1157835SDaniel Fojt 796*a1157835SDaniel Fojt pid = fork(); 797*a1157835SDaniel Fojt if (pid < 0) { 798*a1157835SDaniel Fojt perror("fork"); 799*a1157835SDaniel Fojt return -1; 800*a1157835SDaniel Fojt } 801*a1157835SDaniel Fojt 802*a1157835SDaniel Fojt if (pid == 0) { 803*a1157835SDaniel Fojt /* run the external command in the child process */ 804*a1157835SDaniel Fojt const int MAX_ARG = 30; 805*a1157835SDaniel Fojt char *_program, *_arg, *pos; 806*a1157835SDaniel Fojt char *argv[MAX_ARG + 1]; 807*a1157835SDaniel Fojt int i; 808*a1157835SDaniel Fojt 809*a1157835SDaniel Fojt _program = os_strdup(program); 810*a1157835SDaniel Fojt _arg = os_strdup(arg); 811*a1157835SDaniel Fojt 812*a1157835SDaniel Fojt argv[0] = _program; 813*a1157835SDaniel Fojt 814*a1157835SDaniel Fojt i = 1; 815*a1157835SDaniel Fojt pos = _arg; 816*a1157835SDaniel Fojt while (i < MAX_ARG && pos && *pos) { 817*a1157835SDaniel Fojt while (*pos == ' ') 818*a1157835SDaniel Fojt pos++; 819*a1157835SDaniel Fojt if (*pos == '\0') 820*a1157835SDaniel Fojt break; 821*a1157835SDaniel Fojt argv[i++] = pos; 822*a1157835SDaniel Fojt pos = os_strchr(pos, ' '); 823*a1157835SDaniel Fojt if (pos) 824*a1157835SDaniel Fojt *pos++ = '\0'; 825*a1157835SDaniel Fojt } 826*a1157835SDaniel Fojt argv[i] = NULL; 827*a1157835SDaniel Fojt 828*a1157835SDaniel Fojt execv(program, argv); 829*a1157835SDaniel Fojt perror("execv"); 830*a1157835SDaniel Fojt os_free(_program); 831*a1157835SDaniel Fojt os_free(_arg); 832*a1157835SDaniel Fojt exit(0); 833*a1157835SDaniel Fojt return -1; 834*a1157835SDaniel Fojt } 835*a1157835SDaniel Fojt 836*a1157835SDaniel Fojt if (wait_completion) { 837*a1157835SDaniel Fojt /* wait for the child process to complete in the parent */ 838*a1157835SDaniel Fojt waitpid(pid, &pid_status, 0); 839*a1157835SDaniel Fojt } 840*a1157835SDaniel Fojt 841*a1157835SDaniel Fojt return 0; 842*a1157835SDaniel Fojt } 843