Hallo,
ich wollte ein bisschen mit statx spielen und habe dieses Python-Skript erstellt, das auf die Funktion über ctypes zugreift:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #!/usr/bin/env python3 import sys from ctypes import * if len(sys.argv) == 1: print(f"Usage: {sys.argv[0]} FILE [FILE ..]") AT_FDCWD = -100 class statx_timestamp(Structure): _fields_ = [ ("tv_sec", c_longlong), ("tv_nsec", c_uint), ] class statx_result(Structure): _fields_ = [ ('stx_mask', c_uint), ('stx_blksize', c_uint), ('stx_attributes', c_ulonglong), ('stx_nlink', c_uint), ('stx_uid', c_uint), ('stx_gid', c_uint), ('stx_mode', c_ushort), ('stx_ino', c_ulonglong), ('stx_size', c_ulonglong), ('stx_blocks', c_ulonglong), ('stx_attributes_mask', c_longlong), ('stx_atime', statx_timestamp), ('stx_btime', statx_timestamp), ('stx_ctime', statx_timestamp), ('stx_mtime', statx_timestamp), ('stx_rdev_major', c_uint), ('stx_rdev_minor', c_uint), ('stx_dev_major', c_uint), ('stx_dev_minor', c_uint), ] # see include/uapi/linux/stat.h #/* # * Flags to be stx_mask # * # * Query request/result mask for statx() and struct statx::stx_mask. # * # * These bits should be set in the mask argument of statx() to request # * particular items when calling statx(). # */ STATX_TYPE = 0x00000001 # /* Want/got stx_mode & S_IFMT */ STATX_MODE = 0x00000002 # /* Want/got stx_mode & ~S_IFMT */ STATX_NLINK = 0x00000004 # /* Want/got stx_nlink */ STATX_UID = 0x00000008 # /* Want/got stx_uid */ STATX_GID = 0x00000010 # /* Want/got stx_gid */ STATX_ATIME = 0x00000020 # /* Want/got stx_atime */ STATX_MTIME = 0x00000040 # /* Want/got stx_mtime */ STATX_CTIME = 0x00000080 # /* Want/got stx_ctime */ STATX_INO = 0x00000100 # /* Want/got stx_ino */ STATX_SIZE = 0x00000200 # /* Want/got stx_size */ STATX_BLOCKS = 0x00000400 # /* Want/got stx_blocks */ STATX_BASIC_STAT = 0x000007ff # /* The stuff in the normal stat struct */ STATX_BTIME = 0x00000800 # /* Want/got stx_btime */ STATX_ALL = 0x00000fff # /* All currently supported flags */ STATX__RESERVED = 0x80000000 # /* Reserved for future struct statx expansion */ #/* # * Attributes to be found in stx_attributes and masked in stx_attributes_mask. # * # * These give information about the features or the state of a file that might # * be of use to ordinary userspace programs such as GUIs or ls rather than # * specialised tools. # * # * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS # * semantically. Where possible, the numerical value is picked to correspond # * also. # */ STATX_ATTR_COMPRESSED = 0x00000004 # /* [I] File is compressed by the fs */ STATX_ATTR_IMMUTABLE = 0x00000010 # /* [I] File is marked immutable */ STATX_ATTR_APPEND = 0x00000020 # /* [I] File is append-only */ STATX_ATTR_NODUMP = 0x00000040 # /* [I] File is not to be dumped */ STATX_ATTR_ENCRYPTED = 0x00000800 # /* [I] File requires key to decrypt in fs */ STATX_ATTR_AUTOMOUNT = 0x00001000 # /* Dir: Automount trigger */ STATX_ATTR_VERITY = 0x00100000 # /* [I] Verity protected file */ AT_STATX_SYNC_TYPE = 0x6000 # /* Type of synchronisation required from statx() */ AT_STATX_SYNC_AS_STAT = 0x0000 # /* - Do whatever stat() does */ AT_STATX_FORCE_SYNC = 0x2000 # /* - Force the attributes to be sync'd with the server */ AT_STATX_DONT_SYNC = 0x4000 # /* - Don't sync attributes with the server */ flags = AT_STATX_SYNC_AS_STAT mask = STATX_ALL libc = CDLL('libc.so.6') statx_fp = libc.statx statx_fp.argtypes = [c_int, c_char_p, c_int, c_uint, POINTER(statx_result)] statx_fp.restype = c_int result = statx_result() for arg in sys.argv[1:]: pathname = c_char_p(arg.encode()) if libc.statx(AT_FDCWD, pathname, flags, mask, byref(result)) == 0: print(f"{arg} btime: {result.stx_btime.tv_sec}.{result.stx_btime.tv_nsec}") print("done.") |
Wenn ich es unter Arch Linux ARM auf einem Cubietruck mit Python 3.8.1 und glibc 2.30 laufen lasse, funktioniert es einwandfrei. Das selbe ist auf einer Arch Linux Installation mit Python 3.8.1 und glibc 2.31 der Fall.
Aber unter Ubuntu 20.04 mit den aktuellsten Updates (glibc 2.30, Python 3.8.2rc1) bekomme ich einen Speicherzugriffsfehler, nachdem das Skript durchgelaufen ist (also die letzte Zeile mit dem "done." ausgegeben wurde):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | $ gdb --args python3 test_statx.py test* GNU gdb (Ubuntu 9.1-0ubuntu1) 9.1 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from python3... Reading symbols from /usr/lib/debug/.build-id/4d/55f777d694d06f1b6850d7dd667bc23093673e.debug... (gdb) r Starting program: /usr/bin/python3 test_statx.py test-fsmount.c test-statx test-statx.c test_statx.py test-fsmount.c btime: 1582613663.451475714 test-statx btime: 1582613736.439231928 test-statx.c btime: 1582613677.807441996 test_statx.py btime: 1582643363.637416148 done. Program received signal SIGSEGV, Segmentation fault. update_refs (containers=0x932800 <_PyRuntime+416>) at ../Modules/gcmodule.c:351 351 ../Modules/gcmodule.c: Datei oder Verzeichnis nicht gefunden. (gdb) bt #0 update_refs (containers=0x932800 <_PyRuntime+416>) at ../Modules/gcmodule.c:351 #1 collect.constprop.0 (generation=2, n_collected=0x7fffffffdce0, n_uncollectable=0x7fffffffdce8, nofail=0, state=0x9327b8 <_PyRuntime+344>) at ../Modules/gcmodule.c:1053 #2 0x00000000005f5033 in collect_with_callback.constprop.0 (generation=generation@entry=2, state=0x9327b8 <_PyRuntime+344>) at ../Modules/gcmodule.c:1240 #3 0x000000000066aa48 in PyGC_Collect () at ../Modules/gcmodule.c:1833 #4 0x0000000000676806 in Py_FinalizeEx () at ../Python/pylifecycle.c:1223 #5 0x00000000006ad3d9 in Py_RunMain () at ../Modules/main.c:646 #6 0x00000000006ad649 in Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:698 #7 0x00007ffff7deb1e3 in __libc_start_main (main=0x4ebfc0 <main>, argc=6, argv=0x7fffffffdf38, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf28) at ../csu/libc-start.c:308 #8 0x00000000005f2dfe in _start () at ../Objects/obmalloc.c:1233 (gdb) bt full #0 update_refs (containers=0x932800 <_PyRuntime+416>) at ../Modules/gcmodule.c:351 gc = 0x0 #1 collect.constprop.0 (generation=2, n_collected=0x7fffffffdce0, n_uncollectable=0x7fffffffdce8, nofail=0, state=0x9327b8 <_PyRuntime+344>) at ../Modules/gcmodule.c:1053 i = <optimized out> m = 0 n = 0 young = 0x932800 <_PyRuntime+416> old = 0x932800 <_PyRuntime+416> unreachable = {_gc_next = 140737342234432, _gc_prev = 6015152} finalizers = {_gc_next = 5998512, _gc_prev = 9464672} gc = <optimized out> t1 = 0 stats = <optimized out> #2 0x00000000005f5033 in collect_with_callback.constprop.0 (generation=generation@entry=2, state=0x9327b8 <_PyRuntime+344>) at ../Modules/gcmodule.c:1240 result = <optimized out> collected = 0 uncollectable = 0 #3 0x000000000066aa48 in PyGC_Collect () at ../Modules/gcmodule.c:1833 exc = 0x0 value = 0x0 tb = 0x0 state = <optimized out> n = <optimized out> #4 0x0000000000676806 in Py_FinalizeEx () at ../Python/pylifecycle.c:1223 status = <optimized out> runtime = <optimized out> tstate = <optimized out> interp = 0x957890 malloc_stats = 0 #5 0x00000000006ad3d9 in Py_RunMain () at ../Modules/main.c:646 exitcode = 0 #6 0x00000000006ad649 in Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:698 args = {argc = 6, use_bytes_argv = 1, bytes_argv = 0x7fffffffdf38, wchar_argv = 0x0} #7 0x00007ffff7deb1e3 in __libc_start_main (main=0x4ebfc0 <main>, argc=6, argv=0x7fffffffdf38, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf28) at ../csu/libc-start.c:308 self = <optimized out> result = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {0, 7281275953589829323, 6237648, 140737488346928, 0, 0, -7281275181122666805, -7281293042995249461}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x7fffffffdf70, 0x7ffff7ffe190}, data = {prev = 0x0, cleanup = 0x0, canceltype = -8336}} } not_first_call = <optimized out> #8 0x00000000005f2dfe in _start () at ../Objects/obmalloc.c:1233 No symbol table info available. |
Hat jemand eine Idee, was ich falsch mache bzw. warum es da zu dem Segfault (scheint bei der Garbage-Collection zu passieren) kommt?